3.10 SIM900A GSM 短信模块
3.10.1 模块来源
采购链接: SIM900A 模块\短信\开发板\GSM\GPRS\STM32\无线数据传输超 TC35i
资料下载: https://pan.baidu.com/s/1URIDQv_UNmlGHA5MxJhdHQ 提取码:91yb
3.10.2 规格参数
工作电压:2.0V-5.5V
工作电流:52mA~104mA
默认频率:433Mhz
发射功率:20dBm
参考通信距离:3km
控制方式:串口
3.10.3 移植过程
我们的目标是在梁山派 GD32F470 上能够完成无线传输的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
3.10.3.1 查看资料
模块供电必须使用 5V-1A 以上,如果供电电源是电脑的 USB 口,则无法正常工作,需要外部供电。这里采用手机充电器给开发板供电。
模块上 5VR(RX) 5VT(TX) 是可以兼容单片机各种 TTL 电平接口的。接不同的单片机 TTL 电平接口时,只要保证模块上 VCC_MCU 接入的电压跟单片机的 TTL 电平电压一致就可以了。
SIM 卡的选择:
SIM900A 模块为 2G 模块,支持全部 2G 卡,支持大部分 3G 或 4G 的手机卡, 不支持电信卡。支持全部的移动和联通卡。并接入天线。
模块接入电源后,模块上的两个指示灯开始工作,此时可以通过观察 D5 和 D6 LED 来大致判断模块的工作状态。
| D5 | D6 | 模块工作状态 |
|---|---|---|
| 长亮 | 亮一秒灭一秒(快闪) | 模块正在搜索网络 |
| 长亮 | 亮一秒灭三秒(慢闪) | 模块已经搜索到网络,可以正常工作 |
| 反复长亮几秒灭一秒 | 亮一秒灭一秒(快闪) | 电源电流或者电压不够 |
| 熄灭 | 亮一秒灭三秒(慢闪) | 有电话进来 |
| 灭一下后长亮 | 亮一秒灭三秒(慢闪) | 接收到一条短信 |
3.10.3.2 引脚选择
GSM 模块的电压是 5V,但是电流要大于 1A。可以使用充电器、充电宝、或者降压模块,给立创·梁山派的 USB 口供电即可。使用电脑的 USB 口供电,模块会一直复位。
| GSM 模块 | 立创·梁山派 |
|---|---|
| 3VR | PA2 |
| 3VT | PA3 |
| VCC | 5V |
| GND | GND |
3.10.3.3 移植至工程
移植步骤中的导入.c 和.h 文件与之前相同,只是将.c 和.h 文件更改为 bsp_sim900a.c 与 bsp_sim900a.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 bsp_sim900a.c 中,编写如下代码。
/********************************************************************************
* 文 件 名: bsp_esp01s.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年05月31日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#include "bsp_sim900a.h"
#include "stdio.h"
#include "string.h"
unsigned char GSM_RX_BUFF[GSM_RX_LEN_MAX];
unsigned char GSM_RX_FLAG = 0;
unsigned char GSM_RX_LEN = 0;
/************************************************************
* 函数名称:GSM_USART_Init
* 函数说明:连接GSM的初始化
* 型 参:bund=串口波特率
* 返 回 值:无
* 备 注:模块波特率默认是 9600
*************************************************************/
void GSM_USART_Init(unsigned int bund)
{
/* 使能 GSM_USART 的时钟 */
rcu_periph_clock_enable(RCU_GSM_USART);
/* 使能时钟 */
rcu_periph_clock_enable(RCU_GSM_TX);
rcu_periph_clock_enable(RCU_GSM_RX);
/* 配置引脚为复用功能 */
gpio_af_set(PORT_GSM_TX, BSP_GSM_AF, GPIO_GSM_TX);
/* 配置引脚为复用功能 */
gpio_af_set(PORT_GSM_RX, BSP_GSM_AF, GPIO_GSM_RX);
/* 配置TX引脚为复用上拉模式 */
gpio_mode_set(PORT_GSM_TX, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_GSM_TX);
/* 配置RX引脚为复用上拉模式 */
gpio_mode_set(PORT_GSM_RX, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_GSM_RX);
/* 配置PA2引脚为为输出模式 */
gpio_output_options_set(PORT_GSM_TX, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_GSM_TX);
/* 配置PA3引脚为为输出模式 */
gpio_output_options_set(PORT_GSM_RX, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_GSM_RX);
/* 设置GSM_USART的波特率为115200 */
usart_baudrate_set(GSM_USART, bund);
/* 设置GSM_USART的校验位为无 */
usart_parity_config(GSM_USART, USART_PM_NONE);
/* 设置GSM_USART的数据位为8位 */
usart_word_length_set(GSM_USART, USART_WL_8BIT);
/* 设置GSM_USART的停止位为1位 */
usart_stop_bit_set(GSM_USART, USART_STB_1BIT);
/* 使能串口1 */
usart_enable(GSM_USART);
/* 使能GSM_USART传输 */
usart_transmit_config(GSM_USART, USART_TRANSMIT_ENABLE);
/* 使能GSM_USART接收 */
usart_receive_config(GSM_USART, USART_RECEIVE_ENABLE);
/* 使能GSM_USART接收中断标志位 */
usart_interrupt_enable(GSM_USART, USART_INT_RBNE);
/* 使能GSM_USART空闲中断标志位 */
usart_interrupt_enable(GSM_USART, USART_INT_IDLE); // DLE 线检测中断
/* 配置中断优先级 */
nvic_irq_enable(GSM_USART_IRQ, 2, 2); // 配置中断优先级
}
/******************************************************************
* 函 数 名 称:GSM_USART_Send_Bit
* 函 数 说 明:向GSM模块发送单个字符
* 函 数 形 参:ch=字符
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void GSM_USART_Send_Bit(unsigned char ch)
{
//发送字符
usart_data_transmit(GSM_USART, ch);
// 等待发送数据缓冲区标志自动置位
while(RESET == usart_flag_get(GSM_USART, USART_FLAG_TBE) );
}
/******************************************************************
* 函 数 名 称:GSM_USART_send_String
* 函 数 说 明:向GSM模块发送字符串
* 函 数 形 参:str=发送的字符串
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void GSM_USART_send_String(unsigned char *str)
{
while( str && *str ) // 地址为空或者值为空跳出
{
GSM_USART_Send_Bit(*str++);
}
}
//清除串口接收的数据
/******************************************************************
* 函 数 名 称:Clear_GSM_RX_BUFF
* 函 数 说 明:清除GSM发过来的数据
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Clear_GSM_RX_BUFF(void)
{
unsigned char i = GSM_RX_LEN_MAX-1;
while(i)
{
GSM_RX_BUFF[i--] = 0;
}
GSM_RX_LEN = 0;
GSM_RX_FLAG = 0;
}
/******************************************************************
* 函 数 名 称:GSM_Send_Cmd
* 函 数 说 明:向GSM模块发送指令,并查看GSM模块是否返回想要的数据
* 函 数 形 参:cmd=发送的AT指令 ack=想要的应答 waitms=等待应答的时间 cnt=等待应答多少次
* 函 数 返 回:1=得到了想要的应答 0=没有得到想要的应答
* 作 者:LC
* 备 注:无
******************************************************************/
char GSM_Send_Cmd(char *cmd,char *ack,unsigned int waitms,unsigned char cnt)
{
GSM_USART_send_String((unsigned char*)cmd);//1.发送AT指令
while(cnt--)
{
//串口中断接收蓝牙应答
if( GSM_RX_FLAG == 1 )
{
GSM_RX_FLAG = 0;
GSM_RX_LEN = 0;
//查找是否有想要的数据
if( strstr((char*)GSM_RX_BUFF, ack) != NULL )
{
return 1;
}
//清除接收的数据
memset( GSM_RX_BUFF, 0, sizeof(GSM_RX_BUFF) );
}
//时间间隔
delay_1ms(waitms);
}
GSM_RX_FLAG = 0;
GSM_RX_LEN = 0;
return 0;
}
/**********************************************************
* 函 数 名 称:Get_Signal_Quality
* 函 数 功 能:获取模块信号强度
* 传 入 参 数:无
* 函 数 返 回:信号强度0~99
* 作 者:LC
* 备 注:99=未知 小于10信号差
**********************************************************/
uint8_t Get_Signal_Quality(void)
{
int send_time = 3;
int signal = 0;
char *signal_buff;
//查询信号强度
GSM_USART_send_String((unsigned char*)"AT+CSQ\r\n");
while(send_time--)
{
//假设接收到 "+CSQ:19,0"
if( strstr((char*)GSM_RX_BUFF,"+CSQ:") != NULL )
{
//获取子字符串地址 signal_buff = "+CSQ:19,0"
signal_buff = strstr( (char*)GSM_RX_BUFF, "+CSQ:" );
//字符串以","分割,得到 signal_buff = "+CSQ:19"
signal_buff = strtok( signal_buff, "," );
//字符串地址增加,得到 signal_buff = "19"
signal_buff = signal_buff + strlen("+CSQ:");
//将字符串类型转为整型,得到 signal = 19
signal = atoi( signal_buff );
// //如果信号未知
// if( signal == 99 ) return 2;
}
delay_1ms(200);
}
return signal;
}
/******************************************************************
* 函 数 名 称:Get_GSM_State
* 函 数 说 明:获取GSM模块状态
* 函 数 形 参:无
* 函 数 返 回:1=未检查到设备
2=未检查到天线
3=SIM卡未插入
4=没有注册到网络
* 作 者:LC
* 备 注:如果接收到‘>’,说明当前处于发送短信模式。
******************************************************************/
uint8_t Get_GSM_State(void)
{
char buff[255]={0};
GSM_USART_Send_Bit(0X1A);
//检查设备是否存在
if( GSM_Send_Cmd("AT\r\n","OK", 1000,3) == 0 )
{
return 1;
}
Get_Signal_Quality();
//检查SIM卡是否插入
if( GSM_Send_Cmd("AT+CPIN?\r\n","READY", 1000,3) == 0 )
{
return 3;
}
//检查是否注册网络
if( GSM_Send_Cmd("AT+COPS?\r\n","CHINA", 1000,3) == 0 )
{
return 4;
}
return 0;
}
/**********************************************************
* 函 数 名 称:Send_message_text
* 函 数 功 能:向指定电话号码发送英文短信
* 传 入 参 数:phone_number=接收短信的电话号码 send_text=发送的英文短信
* 函 数 返 回:0=发送成功
1=设置模块使用GSM字符串格式失败
2=设置短信格式失败
3=选择短信接收人失败
4=发送内容失败
* 作 者:LC
* 备 注:无
**********************************************************/
uint8_t Send_Message_Text(char *phone_number, char *send_text)
{
char buff[255]={0};
//确保上一条信息发送完毕
GSM_USART_Send_Bit(0X1A);
if( GSM_Send_Cmd("AT+CSCS=\"GSM\"\r\n","OK", 1000,3) == 0 )
{
return 1;
}
//设置短信的输入和发送格式为文本模式
if( GSM_Send_Cmd("AT+CMGF=1\r\n","OK", 1000,3) == 0 )
{
return 2;
}
//向MESSAGE_TEXT发送短信
sprintf(buff,"AT+CMGS=\"%s\"\r\n", phone_number);
if( GSM_Send_Cmd(buff,">", 1000,3) == 0 )
{
return 3;
}
//发送内容为Hello\r\n
sprintf(buff,"%s\r\n", send_text);
if( GSM_Send_Cmd(buff,">", 1000,3) == 0 )
{
return 4;
}
//发送短信结束符
GSM_USART_Send_Bit(0X1A);
return 0;
}
/******************************************************************
* 函 数 名 称:GSM_USART_IRQHandler
* 函 数 说 明:连接GSM的串口中断服务函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void GSM_USART_IRQHandler(void)
{
if(usart_interrupt_flag_get(GSM_USART,USART_INT_FLAG_RBNE) != RESET) // 接收缓冲区不为空
{
//接收数据
GSM_RX_BUFF[ GSM_RX_LEN ] = usart_data_receive(GSM_USART);
#if DEBUG
//测试,查看接收到了什么数据
printf("%c", GSM_RX_BUFF[ GSM_RX_LEN ]);
#endif
//接收长度限制
GSM_RX_LEN = ( GSM_RX_LEN + 1 ) % GSM_RX_LEN_MAX;
}
if(usart_interrupt_flag_get(GSM_USART,USART_INT_FLAG_IDLE) == SET) // 检测到空闲中断
{
usart_data_receive(GSM_USART); // 必须要读,读出来的值不能要
GSM_RX_BUFF[GSM_RX_LEN] = '\0'; //字符串结尾补 '\0'
GSM_RX_FLAG = SET; // 接收完成
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
在文件 bsp_sim900a.h 中,编写如下代码。
#ifndef _BSP_SIM900A_H_
#define _BSP_SIM900A_H_
#include "gd32f4xx.h"
#include "string.h"
#include "systick.h"
//是否开启串口0调试,查看GSM回显数据
#define DEBUG 1
//发送给这个号码
#define MESSAGE_TEXT "15676033359"
/**************************** 串口配置 ****************************/
#define RCU_GSM_TX RCU_GPIOA // 串口TX的端口时钟
#define RCU_GSM_RX RCU_GPIOA // 串口RX的端口时钟
#define RCU_GSM_USART RCU_USART1 // 串口1的时钟
#define PORT_GSM_TX GPIOA // 串口TX的端口
#define PORT_GSM_RX GPIOA // 串口RX的端口
#define GPIO_GSM_TX GPIO_PIN_2 // 串口TX的引脚
#define GPIO_GSM_RX GPIO_PIN_3 // 串口RX的引脚
#define BSP_GSM_AF GPIO_AF_7 // 串口1的复用功能
#define GSM_USART USART1 // 串口1
#define GSM_USART_IRQ USART1_IRQn // 串口1中断
#define GSM_USART_IRQHandler USART1_IRQHandler // 串口1中断服务函数
#define GSM_RX_LEN_MAX 200 //串口接收最大长度
void GSM_USART_Init(unsigned int bund);
void GSM_USART_send_String(unsigned char *str);
uint8_t Get_GSM_State(void);
uint8_t Send_Message_Text(char *phone_number, char *send_text);
#endif2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
3.10.4 案例一 向指定电话号码发送英文信息
在 main.c 中编写以下代码。(确保.c 和.h 已经按照以上进行移植)
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年06月8日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "BSP_sim900a.h"
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); //优先级分组
systick_config(); //滴答定时器初始化 1ms
usart_gpio_config(9600);
GSM_USART_Init(9600);
printf("start\r\n");
Get_GSM_State();
Send_Message_Text("15676033359","1234567890");
while(1)
{
;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
实验现象:15676033359 会接收到短信内容为 1234567890。
通过网盘分享的文件:立创·梁山派GD32F470ZGT6开发板【模块移植手册代码】
链接: https://pan.baidu.com/s/1pp44yjD1Dhh7U9iZ2a11IA 提取码: LCKF