Raspberry Pi 4使用C语言与SIM7600X调制解调器通信不稳定问题求助
问题根因
你的代码存在4个核心问题,导致和调制解调器通信异常:
- 未配置串口通信参数:
/dev/ttyUSB这类TTY设备需要手动配置波特率、数据位、校验位、停止位、流控等参数,Minicom/Cutecom启动时会自动设置匹配调制解调器的参数,你的代码直接打开设备未做配置,参数不匹配导致数据收发截断,这就是你输出中反复出现AT+CS错误的原因,完整的AT+CSQ命令被截断成了AT+CS,调制解调器无法识别返回ERROR。 - AT命令结束符不符合规范:3GPP标准定义AT命令必须以
\r(回车符,ASCII 0x0D)作为命令结束标志,你使用的\n不符合要求,会导致调制解调器命令解析异常。 - I/O缓冲未刷新:C标准库的
FILE*流默认开启缓冲,你调用fputs写入命令后,数据可能残留在进程缓冲中没有真正发送到串口,需要调用fflush强制刷新。 - 读取逻辑错误:
fgets的返回值是char*类型,读取成功返回缓冲区指针,出错或读取到EOF时返回NULL,你写的if (line >= 0)属于完全错误的指针判断逻辑,会导致循环逻辑异常,无法正常退出。
修正后的代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> int main() { FILE *modem; struct termios tty; int exitflag=0; char buf[256]; char *line; int res; // 打开串口设备 modem = fopen("/dev/ttyUSB2", "r+b"); if (modem == NULL) { fprintf(stderr, "Unable to open modem\n"); return(-1); } int fd = fileno(modem); // 配置串口参数:115200波特率,8N1,无流控 if(tcgetattr(fd, &tty) != 0) { fprintf(stderr, "Failed to get termios attributes\n"); fclose(modem); return -1; } cfsetispeed(&tty, B115200); cfsetospeed(&tty, B115200); tty.c_cflag &= ~PARENB; // 无校验 tty.c_cflag &= ~CSTOPB; // 1停止位 tty.c_cflag &= ~CSIZE; tty.c_cflag |= CS8; // 8数据位 tty.c_cflag &= ~CRTSCTS; // 关闭硬件流控 tty.c_cflag |= CREAD | CLOCAL; // 开启接收,忽略调制解调器控制线 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控 tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始模式,关闭回显、规范模式 tty.c_oflag &= ~OPOST; // 关闭输出处理 tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 5; // 读取超时500ms if(tcsetattr(fd, TCSANOW, &tty) != 0) { fprintf(stderr, "Failed to set termios attributes\n"); fclose(modem); return -1; } // 发送AT+CSQ命令,以\r结尾 res = fputs("AT+CSQ\r", modem); if (res < 0) { fprintf(stderr, "failed to send to modem (res = %d)\n",res); fclose(modem); return(-1); } fflush(modem); // 刷新输出缓冲,确保命令发送到串口 exitflag=0; while (exitflag==0) { line = fgets(buf, sizeof(buf), modem); if (line != NULL) { fprintf(stderr,"%s",buf); // 读到OK或者ERROR就退出循环 if (strstr(buf, "OK") != NULL || strstr(buf, "ERROR") != NULL) { exitflag = 1; } } else { exitflag=1; fprintf(stderr,"read timeout or error\n"); } } fclose(modem); return(0); }
额外优化建议
- 可以先发送
ATE0\r命令关闭调制解调器的命令回显,这样输出中就不会重复打印你发送的AT命令,只保留调制解调器的返回结果。 - 每次发送命令后建议等待100~200ms再读取返回,避免调制解调器处理未完成。
内容的提问来源于stack exchange,提问作者Rik Hughes
相关产品推荐
相关产品推荐

