【STM32外设系列】SIM900A(短信)模块

🎀 文章作者:二土电子

🌸 关注公众号获取更多资料!

🐸 期待大家一起学习交流!


一、SIM900A简介

  在一些项目设计中,我们可能会用到发送短信的功能,我们可以借助SIM900A模块来实现,该模块使用方便,只需要用简单的AT指令即可实现发送短信的功能,当然SIM900A的功能并不仅仅是发送短信,它还有其他可扩展的功能,但是本文只讨论它的短信发送功能最终给出其程序实现。下面我们来看一下SIM900A长什么样子
SIM900A

二、Unicode简介

2.1 什么是Unicode

  Unicode被称为统一码或者万国码,我们这里仅仅介绍Unicode是什么,至于它是如何进行编码的这种更加深入的问题这里不去探讨,大家可以自行搜索了解一下。个人认为,Unicode可以理解成一个字符集,它的出现是为了能够将全世界的字符用一个统一的表来覆盖,每一个字符都有其唯一对应的二进制数,这样就可以避免发生一个在甲编码方案下编辑保存的文件转到乙编码方案下打开出现乱码的情况。

2.2 Unicode转换工具

  我们在使用SIM900A是需要将收件人手机号和短信内容转换成Unicode,我们可以利用Unicode转换工具来实现

Unicode转换工具

  在“双字节汉字”中输入收信人手机号或者短信内容,点击“汉字转Unicode”即可得到对应的Unicode码,使用时注意删掉中间的空格。

三、部分AT指令简介

  使用简单的AT指令即可控制SIM900A发送短信,下面简单介绍一下常用的几条AT指令(以发送中文消息为例配置参数),至于其他的AT指令,可至文末链接下载查看。

  • AT+CPIN?
    查询SIM卡是都可以正常使用,如果返回+CPIN:READY(换行回车)OK,说明SIM卡可以正常使用。
  • AT+CMGF=1
    设置短信模式为文本模式。
  • AT+CSCS=“UCS32”
    编码模式设置为UCS32。
  • AT+CSMP=17,167,0,8
    设置短信文本模式参数,关键点子啊与最后一个参数,最后一个参数为0时,表示为英文模式,第四位参数为8时表示为中文普通文本模式。
  • AT+CMGS=“收信人手机号的Unicode码”
    设置收信人手机号,准备发送短信,发送完该条指令后,可以直接发送转换好的短信内容。

  最后在发送0x1A,等待一小段时间收信人就会收到我们编辑的短信。

四、发送短信调试

  在准备开始程序设计前我们可以先利用USB-TTL来尝试发送一下短信,首先我们来看一下接线

USB-TTLSIM900A
5VVCC
GNDGND
TXD5VR
RXD5VT

  连接好线后我们再将收信人手机号转换成Unicode码,注意删掉中间的空格。

收信人手机号转换

  然后把需要发送的文本内容编辑好,最后我们打开串口助手,依次发送上面AT指令小节中介绍的内容即可,需要注意的是,在发送0x1A时需要将串口助手的发送模式调整为HEX模式。

五、程序设计

  上面利用串口助手调试发送短信成功后,下面的程序设计就不复杂了,只需要用程序代码实现发送上面那些AT指令即可。

5.1 串口初始化程序

  串口初始化程序可以利用一个函数初始化两个串口,下面的指令发送函数中会有利用串口2反馈指令发送成功失败的提示,如果需要的话可以取消注释同时利用此函数初始化一下串口2。

/*
 *==============================================================================
 *函数名称:uart_init
 *函数功能:初始化USART
 *输入参数:UARTx:串口几;bound:波特率
 *返回值:无
 *备  注:可以修改成输入初始化哪个USART
 *==============================================================================
 */
void uart_init(UART_TypeDef UARTx,u32 bound)
{
	// 相关结构体定义
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	switch (UARTx)
	{
		case 0:
			// 使能USART1,GPIOA时钟
			RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);	

			// USART1_TX   GPIOA.9
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   // PA.9
			GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   // 复用推挽输出
			GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.9

			// USART1_RX	  GPIOA.10初始化
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;   // PA10
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入
			GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.10  

			// Usart1 NVIC 配置
			NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;   // 抢占优先级3
			NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;   // 子优先级3
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   // IRQ通道使能
			NVIC_Init(&NVIC_InitStructure);   // 根据指定的参数初始化VIC寄存器

			// USART 初始化设置
			USART_InitStructure.USART_BaudRate = bound;   // 串口波特率
			USART_InitStructure.USART_WordLength = USART_WordLength_8b;   // 字长为8位数据格式
			USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 一个停止位
			USART_InitStructure.USART_Parity = USART_Parity_No;   // 无奇偶校验位
			// 无硬件数据流控制
			USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
			USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 收发模式
			USART_Init(USART1, &USART_InitStructure);   // 初始化串口1
			
			USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);   // 开启串口接收中断
			USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);   // 使能空闲中断
			
			USART_Cmd(USART1, ENABLE);   // 使能串口1
			
			break;
			
		case 1:
			// 使能USART2,GPIOA时钟
			RCC_APB1PeriphClockCmd (RCC_APB1Periph_USART2 | RCC_APB2Periph_GPIOA, ENABLE);	

			// USART2_TX   GPIOA.2
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;   // PA.2
			GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   // 复用推挽输出
			GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.2

			// USART2_RX	  GPIOA.3初始化
			GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;   // PA3
			GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入
			GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.3 

			// Usart2 NVIC 配置
			NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;   // 抢占优先级3
			NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;   // 子优先级3
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   // IRQ通道使能
			NVIC_Init(&NVIC_InitStructure);   // 根据指定的参数初始化VIC寄存器

			// USART2 初始化设置
			USART_InitStructure.USART_BaudRate = bound;   // 串口波特率
			USART_InitStructure.USART_WordLength = USART_WordLength_8b;   // 字长为8位数据格式
			USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 一个停止位
			USART_InitStructure.USART_Parity = USART_Parity_No;   // 无奇偶校验位
			// 无硬件数据流控制
			USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
			USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 收发模式
			USART_Init(USART2, &USART_InitStructure);   // 初始化串口2
			
			USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);   // 开启串口接收中断
			USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);   // 使能空闲中断
			
			USART_Cmd(USART2, ENABLE);   // 使能串口2
			
			break;
			
			default:
				break;
	}
}

5.2 串口中断服务函数

/*
 *==============================================================================
 *函数名称:USART1_IRQHandler
 *函数功能:USART1中断服务函数
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
u32 gReceCount = 0;   // 接收计数变量
u32 gClearCount = 0;   // 清空接收数组计数变量
u8 gReceFifo[1500];   // 接收数组
u8 gReceEndFlag = 0;   // 接收完成标志位 

void USART1_IRQHandler(void)  
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   //接收到一个字节  
	{
		gReceFifo[gReceCount++] = USART_ReceiveData(USART1);
	}
	else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)   //接收到一帧数据
	{
		USART1->SR;   // 先读SR
		USART1->DR;   // 再读DR
		
		gReceEndFlag = 1;   // 接收完成标志置1 
	} 
}

5.3 串口接收内容解析函数

  需要注意的是该函数只能检测到返回信息中包含“OK”的指令,至于其他不包含“OK”的返回信息无法检测。

/*
 *==============================================================================
 *函数名称:Uart_Rece_Pares
 *函数功能:解析串口接收内容
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
extern u8 gOkFlag;   // 配置成功标志位

void Uart_Rece_Pares(void)   // 串口接收内容解析函数
{
	u16 tempVar = 0;   // 临时循环变量
	
	if (gReceEndFlag  == 1)   // 如果接收完成
	{
		// 解析接收内容
		for (tempVar = 0;tempVar < gReceCount;tempVar ++)
		{
			if (gReceFifo[tempVar] == 'O' && gReceFifo[tempVar + 1] == 'K')
			{
				gOkFlag = 1;   // 成功标志位置1
				break;
			}
		}
		
		// 清空接收数组
		for (gClearCount = 0;gClearCount < gReceCount;gClearCount ++)
		{
			gReceFifo[gClearCount] = ' ';
		}
			
		gReceEndFlag = 0;   // 清除接收完成标志位
		gReceCount = 0;   // 清零接收计数变量
	}
}

5.4 串口发送函数

/*
 *==============================================================================
 *函数名称:USART_Send
 *函数功能:串口发送函数
 *输入参数:str:要发送的数据的数组首地址;UARTx:串口几
 *返回值:无
 *备  注:调用前先将需要发送的内容利用sprintf()函数转换成字符串,再进行发送
 *==============================================================================
 */
void USART_Send (UART_TypeDef UARTx,u8 *str)
{
	u8 index = 0;
	
	do
	{
		switch (UARTx)
		{
			case 0:
				USART_SendData(USART1,str[index ++]);
				while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
				break;
			
			case 1:
				USART_SendData(USART2,str[index ++]);
				while (USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET);
			break;
		}
	}
	while(str[index] != 0);
}

5.5 指令发送函数

/*
 *==============================================================================
 *函数名称:Med_Sim900a_SendCmd
 *函数功能:SIM900A发送指令
 *输入参数:str:要发送的指令
 *返回值:无
 *备  注:调用前先将需要发送的内容利用sprintf()函数转换成字符串
					串口1发送指令,串口2返回信息
 *==============================================================================
 */
u8 gSendCunt = 0;   // 记录发送次数

void Med_Sim900a_SendCmd (u8 *str)
{
	u8 string[100];
	
	while (!gOkFlag)
	{
		// 发送AT指令
		USART_Send(UART1,str);
		delay_ms(1000);
		
		gSendCunt = gSendCunt + 1;   // 发送次数加1
		
		// 检测接收内容
		Uart_Rece_Pares();
		
		if (gSendCunt > 10)
		{
			sprintf((char*)string,"%s指令发送失败!\r\n",str);
//			USART_Send(UART2,string);
		}
	}
	
	sprintf((char*)string,"%s指令发送成功!\r\n",str);
//	USART_Send(UART2,string);
	gSendCunt = 0;   // 清零发送次数
	gOkFlag = 0;   // 清零配置成功变量
}

5.6 SIM900A发送短信业务函数

/*
 *==============================================================================
 *函数名称:App_Sim900a_SendMsg
 *函数功能:SIM900A发送短信
 *输入参数:无
 *返回值:无
 *备  注:有待添加返回值,可更改接收手机号,默认发送“酒驾危险”
 *==============================================================================
*/
 
void App_Sim900a_SendMsg (void)
{
	sprintf((char*)gString,"AT+CMGF=1\r\n");
	Med_Sim900a_SendCmd(gString);
	
	delay_ms(200);
	
	sprintf((char*)gString,"AT+CSCS=\"UCS2\"\r\n");
	Med_Sim900a_SendCmd(gString);
	
	delay_ms(200);
	
	sprintf((char*)gString,"AT+CSMP=17,167,0,8\r\n");
	Med_Sim900a_SendCmd(gString);
	
	delay_ms(200);
	
	sprintf((char*)gString,"AT+CMGS=\"%s\"\r\n",NEMBER);
	USART_Send(UART1,gString);
	delay_ms(500);
	
	sprintf((char*)gString,"%s\r\n",CONTENT);
	USART_Send(UART1,gString);
	delay_ms(500);
	
	sprintf((char*)gString,"%c\r\n",0x1a);
	USART_Send(UART1,gString);
	delay_ms(1000);
	delay_ms(1000);
}

六、注意事项

  • 有些文章推荐使用外部电源供电,但是博主测试时分别使用了USB-TTL供电和单片机5V供电,模块均能正常完成发送短信的业务;
  • 在执行短信发送业务时,尽量管不其他中断,否则可能会导致发送失败;
  • 使用时注意尽量使用移动的SIM卡,别的SIM卡可能无法使用;

七、资料链接

  • SIM900A模块AT指令合集
    链接:https://pan.baidu.com/s/1igSMUnegOEBBY0dUcoJDyg
    提取码:5qiy
    –来自百度网盘超级会员V4的分享
  • Chiness_Unicode-中文转UNICON编码工具
    链接:https://pan.baidu.com/s/1fS3HglVCI0yRIw0YclbtHw
    提取码:nvk6
    –来自百度网盘超级会员V4的分享
  • 13
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
ATK-SIM900A模块介绍: ATK-SIM900A模块是 ALIENTEK推出的一款高性能工业级 GSM/GPRS模块 (开发板),接口丰富,功能完善,尤其适用于需要语言、短信、GPRS数据服务的各种领域。 ATK-SIM900A模块支持RS232串口和 LVTTL串口,并带硬件流控制。支持 5V~24V的超宽工作范围,使得本模块可以非常方便与您产品进行连接,从而给产品提供包括语音、短信和GPRS数据传输等功能。 SIM900A模块资料如截图: SIM900A模块原理图截图: SIM900A模块资料汇总截图: SIM900A模块资料具体说明: 模块原理图:模块原理图和封装库 程序源码:此目录包含所有正点原子STM32源码,分库函数和寄存器两个版本,请使用与开发板对应的源码即可。 配套软件:包括CH340 USB串口驱动,串口调试助手,汉字Unicode互换工具等开发过程中常用软件 SIM900A模块资料:SIM900A模块自身的一些官方资料 芯片数据手册:模块使用到的芯片的数据手册 SD卡根目录文件:使用正点原子STM32开发板发送中文短信需要把这个文件夹下面内容复制到SD卡根目录 其他参考资料:一些网络资料 DF文件: TK-SIM900A GSM(GPRS)模块用户手册_V1.1.pdf 这个文档非常重要,是模块介绍 ATK-SIM900A模块使用说明_ANxx.pdf 这个文档有几个版本,对应不同开发板。 ATK-SIM900(A)模块DTMF解码功能_AN1415.pdf:DTMF解码功能说明文档 ATK-SIM900(A)模块彩信功能_AN1414.pdf:彩信功能说明文档 ATK-SIM900(A)模块升级说明_AN1413.pdf :模块升级说明文档 ATK-SIM900A GSM模块常见问题汇总_20140805.pdf:这个文档是模块使用过程中常见问题解答。
STM32驱动SIM900A模块发送短信的过程中,可以采用透传方式进行操作。首先,通过UART给SIM900A模块发送AT指令,将模块配置为短信TEXT模式。然后,使用相应的方式发送短信内容。最后,记得发送0x1A作为结束标志。以下是相关的宏定义和两个关键函数的示例代码: ```c // 相关宏定义 static unsigned char *PhoneNumber="xxxxxxxxxxx"; // 这里填接收短信的电话号码 static unsigned char *SendContent="Hello"; // 短信内容 // 发送短信的函数 void SendSMS(void) { // 配置模块短信TEXT模式 UART_SendString("AT+CMGF=1\r\n"); Delay_ms(100); // 设置接收短信的电话号码 UART_SendString("AT+CMGS=\""); UART_SendString(PhoneNumber); UART_SendString("\"\r\n"); Delay_ms(100); // 发送短信内容 UART_SendString(SendContent); Delay_ms(100); // 发送结束标志 UART_SendChar(0x1A); Delay_ms(100); } // UART发送字符串的函数 void UART_SendString(char *str) { while(*str) { UART_SendChar(*str++); } } // UART发送单个字符的函数 void UART_SendChar(char ch) { // 等待发送缓冲区为空 while(!(USART1->SR & USART_SR_TXE)); // 发送字符 USART1->DR = ch; } ``` 请注意,以上代码仅为示例,具体的实现可能需要根据你的具体硬件和软件环境进行适配和调整。同时,还需要确保STM32SIM900A模块之间的串口通信正常连接,并正确配置UART的波特率、数据位、停止位等参数。 #### 引用[.reference_title] - *1* *3* [【STM32训练—SIM900A模块】第一篇、电脑的串口助手驱动SIM900A发送中文和英文短信](https://blog.csdn.net/Learning1232/article/details/122721950)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [如何利用SIM900A模块发送短信?](https://blog.csdn.net/weixin_42462651/article/details/106037290)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二土电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值