1. 硬件选型与连接指南做毕业设计或者小型物联网项目时选择适合的硬件组合是关键。我推荐使用STM32F103C8T6俗称蓝莓派搭配SIM800L GSM模块这套组合性价比高且资料丰富。STM32F103C8T6自带多个USART接口64KB Flash完全够用而SIM800L支持四频850/900/1800/1900MHz全球通用性很强。硬件连接要注意几个细节首先用万用表确认模块电压SIM800L是3.3V供电但TX/RX引脚可以兼容5V电平。实际接线时建议按这个顺序GSM模块的VCC接3.3V电流要保证≥2AGND对GND共地SIM_TXD接STM32的USART2_RX(PA3)SIM_RXD接STM32的USART2_TX(PA2)有个坑我踩过一定要在GSM模块电源端并联1000μF电容否则发送短信时电流突增会导致模块重启。天线最好用弹簧天线如果信号弱ATCSQ返回值小于10可以外接胶棒天线。2. 串口通信基础配置串口配置是通信的基础这里给出经过实测稳定的初始化代码。与普通串口不同GSM通信需要特别注意两点波特率误差要小于2%建议用9600bps接收缓冲区要足够大我设为256字节#define GSM_BUF_LEN 256 uint8_t gsmRxBuf[GSM_BUF_LEN]; uint16_t gsmRxIndex 0; void USART2_Init(u32 bound) { // 时钟使能部分与常规配置相同 // ... USART_InitStruct.USART_BaudRate bound; USART_InitStruct.USART_WordLength USART_WordLength_8b; USART_InitStruct.USART_StopBits USART_StopBits_1; USART_InitStruct.USART_Parity USART_Parity_No; USART_InitStruct.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, USART_InitStruct); // 关键配置开启空闲中断 USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); USART_Cmd(USART2, ENABLE); } // 改进的中断处理函数 void USART2_IRQHandler(void) { if(USART_GetITStatus(USART2, USART_IT_RXNE) ! RESET) { gsmRxBuf[gsmRxIndex] USART_ReceiveData(USART2); if(gsmRxIndex GSM_BUF_LEN) gsmRxIndex 0; } if(USART_GetITStatus(USART2, USART_IT_IDLE) ! RESET) { USART_ReceiveData(USART2); // 清除IDLE标志 parseGSMResponse(); // 自定义响应解析函数 gsmRxIndex 0; } }实测发现用空闲中断替代传统的延时等待更可靠。每次收到完整响应后以\r\n结尾立即解析可以避免数据堆积。3. 英文短信发送实战发送英文短信确实简单但有些细节手册不会告诉你。先看基本流程void sendEnglishSMS(char* phone, char* msg) { sendATCommand(ATCMGF1, 500); // 文本模式 sendATCommand(ATCMGS\), 200); // 注意转义引号 sendATCommand(phone, 200); sendATCommand(\\r, 200); sendATCommand(msg, 1000); // 内容 sendATCommand(\x1A, 3000); // CtrlZ结束 }关键点在于每条AT指令后必须跟\r\n回车换行手机号格式要带国际区号如86138001380000x1A发送后要留足3秒等待响应我总结的避坑经验如果返回CMGS错误先检查SIM卡余额和信号强度ATCSQ内容不能包含等特殊字符否则要用URL编码建议添加响应检测例如while(strstr(gsmRxBuf, OK) NULL) { if(strstr(gsmRxBuf, ERROR)) { // 重发逻辑 break; } }4. 中文短信PDU模式详解中文短信必须使用PDU模式核心是要理解UCS2编码。整个过程分为六个步骤4.1 编码转换原理中文字符在PDU模式下采用UTF-16BE编码即每个汉字占2字节。例如报警二字报 → 0x62A5警 → 0x8B66推荐使用在线工具生成PDU码但要注意短信中心号选择自动获取编码类型选UCS2有效期限设为最大4.2 完整发送流程void sendChineseSMS(char* phone, char* pduMsg) { sendATCommand(ATCMGF0, 500); // PDU模式 sendATCommand(ATCSCS\UCS2\, 500); sendATCommand(ATCSMP17,167,0,25,500); // 中文参数 char cmd[100]; sprintf(cmd, ATCMGS%d\r, strlen(pduMsg)/2 15); // 计算PDU长度 sendATCommand(cmd, 500); sendATCommand(pduMsg, 1000); // 发送十六进制PDU sendATCommand(\x1A, 5000); // 延长等待时间 }4.3 手机号特殊处理中文短信的接收号码需要转换为UCS2格式每个数字前加0013800138000 → 0031003800300030003100330038003000300030有个技巧可以先用英文短信获取对方号码的UCS2格式ATCNUM避免手动转换出错。5. 报警系统集成方案将短信功能与传感器结合时建议采用状态机设计typedef enum { GSM_IDLE, GSM_INIT, GSM_READY, GSM_SENDING, GSM_CONFIRM } GSM_State; void GSM_Handler(void) { static GSM_State state GSM_INIT; switch(state) { case GSM_INIT: if(checkATResponse(OK)) { state GSM_READY; } break; case GSM_READY: if(sensorTriggered()) { preparePDUMessage(); state GSM_SENDING; } break; // ...其他状态处理 } }实际项目中我建议添加重试机制最多3次记录发送日志到Flash设计心跳包定期发送状态短信重要报警追加电话拨叫功能调试时可以用串口助手模拟模块响应特别要测试边界情况信号突然中断SIM卡被拔出短信中心号码变更多语言混合内容如温度过高Temperature too high