STM32向GSM模块发送AT+CSTT命令时TX缓冲区丢字符问题
AT命令发送丢失字符问题(STM32 + GSM模块)
开发STM32搭载GSM模块的系统时,发送AT+CSTT命令返回ERROR,排查发现模块实际收到的是A+CSTT(丢失了AT中的'T')。进一步测试发现:密码长度≤2位时命令发送正常,超过2位就出现丢字符问题;DEBUG打印显示发送前命令格式完全正确,推测问题出在串口收发的数据处理环节。
发送AT命令的代码
void sendAT(char command[], char answer[], int waitForAnswer) { char ATcommand[500]; uint8_t buffer[500] = { 0 }; uint8_t ATisOK = 0; sprintf(ATcommand, "%s\n", command); DEBUG_PRINT("Sending AT Command: "); DEBUG_PRINT(ATcommand); while (!ATisOK) { HAL_UART_Transmit(&huart2, (uint8_t*) ATcommand, strlen(ATcommand), 2000); HAL_UART_Receive(&huart2, buffer, sizeof(buffer) - 1, 300); buffer[sizeof(buffer) - 1] = '\0'; HAL_Delay(500); ATisOK = !waitForAnswer; if (strstr((char*) buffer, "OK")) { ATisOK = 1; } DEBUG_PRINT("GSM: "); DEBUG_PRINT((char* ) buffer); HAL_Delay(1000); memset(buffer, 0, sizeof(buffer)); } } char* sendATWithReturn(char command[]) { char ATcommand[500]; uint8_t buffer[300] = { 0 }; char *returnBuffer = malloc(300 * sizeof(char)); if (returnBuffer == NULL) { return NULL; } sprintf(ATcommand, "%s\n", command); HAL_UART_Transmit(&huart2, (uint8_t*) ATcommand, strlen(ATcommand), 1000); HAL_UART_Receive(&huart2, buffer, 300, 100); HAL_Delay(500); DEBUG_PRINT("GSM: "); DEBUG_PRINT((char* ) buffer); strncpy(returnBuffer, (char*) buffer, 300); return returnBuffer; }
模块初始化代码
void modemStart(char *apn, char *user, char *pwd) { sendATWithReturn("AT"); HAL_Delay(1000); sendATWithReturn("AT+CPIN?"); HAL_Delay(1000); sendATWithReturn("AT+CREG?"); HAL_Delay(1000); sendATWithReturn("AT+CGATT?"); HAL_Delay(1000); sendATWithReturn("AT+CSQ"); HAL_Delay(1000); char command[500]; snprintf(command, sizeof(command), "AT+CGDCONT=1,\"IP\",\"%s\"", apn); sendAT(command, "OK", 1); memset(command, 0, sizeof(command)); HAL_Delay(1000); sendAT("AT+CGATT=1", "OK", 0); HAL_Delay(1000); sendATWithReturn("AT+CSTT?"); HAL_Delay(1000); snprintf(command, sizeof(command), "AT+CSTT=\"%s\",\"%s\",\"%s\"", apn, user, pwd); sendAT(command, "OK", 1); memset(command, 0, sizeof(command)); HAL_Delay(1000); sendATWithReturn("AT+CIICR"); HAL_Delay(1000); sendATWithReturn("AT+CIFSR"); HAL_Delay(1000); sendATWithReturn("AT+CIPMUX=1"); /* AT+CPIN?: Verifica o status do PIN do SIM. AT+CREG?: Verifica o status de registro na rede. Sequência de Inicialização: AT+NETCLOSE: Fecha qualquer conexão de rede existente. AT+CGATT=0: Desativa o GPRS. AT+CGATT=1: Ativa o GPRS. AT+CGDCONT: Define o contexto PDP. AT+CSTT: Define o APN, usuário e senha. AT+CIICR: Inicia a conexão sem fio. AT+CIFSR: Obtém o endereço IP. AT+CIPMUX=1: Habilita o modo de múltiplas conexões. */ }
日志信息
19:37:54.671 -> Serial2: Send AT: 19:37:54.671 -> Sending AT Command: AT 19:37:54.671 -> GSM: AT 19:37:54.671 -> OK 19:37:54.671 -> 19:37:56.282 -> Serial2: GSM: AT 19:37:56.282 -> OK 19:37:56.282 -> 19:37:57.878 -> Serial2: GSM: AT+CPIN? 19:37:57.878 -> +CPIN: READY 19:37:57.878 -> 19:37:57.878 -> OK 19:37:57.878 -> 19:37:59.455 -> Serial2: GSM: AT+CREG? 19:37:59.455 -> +CREG: 0,1 19:37:59.455 -> 19:37:59.455 -> OK 19:37:59.455 -> 19:38:01.060 -> Serial2: GSM: AT+CGATT? 19:38:01.060 -> +CGATT: 1 19:38:01.060 -> 19:38:01.060 -> OK 19:38:01.060 -> 19:38:04.242 -> Serial2: GSM: AT+CSQ 19:38:04.242 -> +CSQ: 18,0 19:38:04.242 -> 19:38:04.242 -> OK 19:38:04.242 -> Sending AT Command: AT+CGDCONT=1,"IP","zap.vivo.com.br" 19:38:04.287 -> GSM: AT+CGDCONT=1,"IP","zap.vivo.com.br" 19:38:04.287 -> OK 19:38:04.287 -> 19:38:06.839 -> Serial2: Sending AT Command: AT+CGATT=1 19:38:06.839 -> GSM: AT+CGATT=1 19:38:06.885 -> OK 19:38:06.885 -> 19:38:11.069 -> Serial2: GSM: AT+CSTT? 19:38:11.069 -> ERROR 19:38:11.069 -> Sending AT Command: AT+CSTT="zap.vivo.com.br","vivo","vivo" 19:38:11.069 -> GSM: A+CSTT="zap.vivo.com.br","vivo","vivo" 19:38:11.069 -> ERROR 19:38:11.069 -> 19:38:12.670 -> Serial2: GSM: A+CSTT="zap.vivo.com.br","vivo","vivo" 19:38:12.670 -> ERROR
排查与修复建议
1. 调整串口发送超时参数
当前HAL_UART_Transmit的超时设置(2000ms/1000ms)可能不足以完成长命令的发送,导致数据截断。建议:
- 将超时参数改为
HAL_MAX_DELAY,确保数据完全发送完成后再退出函数; - 确认STM32与GSM模块的波特率配置完全一致,波特率不匹配是丢字符的常见原因。
2. 替换sprintf为snprintf
sprintf存在缓冲区溢出风险,可能破坏内存数据间接影响发送。建议:
// 替换原sprintf语句 snprintf(ATcommand, sizeof(ATcommand), "%s\n", command);
同时检查snprintf的返回值,确保命令没有超出缓冲区长度:
int cmdLen = snprintf(command, sizeof(command), "AT+CSTT=\"%s\",\"%s\",\"%s\"", apn, user, pwd); if (cmdLen >= sizeof(command)) { DEBUG_PRINT("Command buffer overflow!\n"); return; }
3. 优化串口接收逻辑
当前发送后立即调用HAL_UART_Receive且超时仅300ms,可能模块还未返回数据就结束接收,导致后续处理混乱。建议:
- 发送完成后增加适当延时(如100ms),确保模块有足够时间处理命令;
- 改用中断方式接收数据,避免阻塞式接收的时序问题;
- 检查
HAL_UART_Receive的返回值,确认是否成功接收数据,避免处理空缓冲区或不完整数据。
4. 硬件层面排查
- 检查STM32与GSM模块的串口接线,确保TX/RX引脚连接正确,无虚焊、松动;
- 尝试降低串口波特率(如从115200降至9600),排除高速波特率下的信号干扰问题。
内容的提问来源于stack exchange,提问作者Matheus Markies
相关产品推荐
相关产品推荐

