STM32F103驱动SIM808做GPS追踪器 发送一次短信后死机问题咨询
故障原因及修复方案
核心问题点
- 串口接收中断逻辑错误
USART1中断处理函数中,接收缓存下标i、接收完成标志get_Enter完全没有复位逻辑,每次接收到换行后i会持续累加,很快就会超出str1数组的300字节长度,引发内存越界,导致程序跑飞或者变量值异常。同时get_Enter置1后没有清零,后续的串口接收逻辑完全无法正常触发。
另外接收用到的全局变量i、ch、get_Enter都没有加volatile修饰,编译器优化后会导致主循环读取到的变量值和实际值不一致。 - 存在死等逻辑
主循环中do { p=strstr(str1,"+CMTI:"); } while(p==NULL);是无超时的死等逻辑,一旦模块报文丢失、或者报文被之前的残留数据覆盖,程序会直接卡在此处,不再响应任何操作。 strtok修改原缓存
解析CGNSINF数据时使用的strtok函数会直接修改传入的原字符串内容,会破坏str1中存储的原始返回数据,影响后续逻辑判断。- 没有做命令响应判断
所有AT指令发送后都只靠固定延时等待响应,没有校验模块是否返回OK,一旦模块响应慢、或者返回ERROR,后续逻辑全部错乱。
修复代码示例
1. 调整全局变量定义和中断逻辑
// 全局变量增加volatile修饰,避免编译器优化引发的取值异常 volatile char get_Enter = 0; volatile uint8_t ch; volatile int i=0; char str1[300] = {0}; // 初始化时清空缓存 // 修改串口中断服务函数 void USART1_IRQHandler(void) { // 先判断是否为接收中断,避免误触发 if(USART1->SR & (1<<5)) { ch = USART1->DR & 0xFF; if (ch == '\n'){ get_Enter = 1; str1[i] = '\0'; // 给字符串补结束符 } else{ // 增加边界判断,防止数组越界 if(i < 299) { str1[i] = ch; i++; } } } }
2. 调整主循环逻辑
while (1) { if (get_Enter == 1) { if (flag == 0){ // 去掉无超时死等逻辑,没有找到报文就等待下一次接收触发 p = strstr(str1,"+CMTI:"); if(p != NULL) { Delay(1000); CMGR(); Delay(350); flag = 1; } // 每次处理完当前报文后复位接收标志和缓存 get_Enter = 0; i = 0; memset(str1, 0, 300); } if (flag == 1) { p = strstr(str1,"+CMGR"); if (p){ p = strstr(str1,"loc"); if (p != NULL) { CGNSINF(); Delay(300); p = strstr(str1,"+CGNSINF:"); if (p) { float a[5]; char str2[80]; // 用临时缓存拷贝数据,避免strtok修改原缓存 char tmp_buf[300]; strcpy(tmp_buf, p); const char s[2] = ","; char *token; token = strtok(tmp_buf, s); // 循环变量不要和全局变量i重名 for (int j=0;j<5;j++){ if(token == NULL) break; a[j] = atof(token); token = strtok(NULL, s); } sprintf(str2,"https://maps.google.com/?q=%.6f,%.6f",a[3],a[4]); Send_SMS(str2); } } del_All_SMS(); flag = 0; // 复位接收标志和缓存 get_Enter = 0; i = 0; memset(str1, 0, 300); } } } }
额外优化建议
- 所有AT指令发送后建议增加10秒超时的OK校验逻辑,一旦校验失败可以自动重发指令,避免逻辑卡死后只能手动复位
- SIM808发送短信后需要等待
+CMGS:OK返回后再执行删除短信操作,不要只靠固定延时 - 如果GPS首次定位还没完成,
CGNSINF返回的经纬度是空值,建议增加定位有效性判断,避免返回无效的地图链接
内容的提问来源于stack exchange,提问作者salar1991
相关产品推荐
相关产品推荐

