
问题描述Air780 模组AT 状态机第一条 AT 正常、第二条 AT read tlen 恒为 0 问题排查.模组初始化流程先发ATCREG?查询蜂窝注册状态第一条 AT 指令收发完全正常可以收到模组返回CREG:0,1与 OK。状态机流转到下一条指令ATCGATT?查询 GPRS 附着状态代码日志打印出Send ATCGATT?代表已经进入发送分支调用air_send_str发送字符串。但是接收函数uart-read读到的tlen一直等于 0模组完全不返回任何应答多次超时后触发deal_cmd_timeout超时计数4 次重试耗尽后触发重大错误系统复位。现象关键点硬件接线、波特率、串口时钟没问题第一条AT通信正常代码执行到发送日志打印发送提示但是模组收不到第二条 AT 指令接收 tlen 持续为 0无任何返回数据。部分代码如下// 查询附着GPRS网络case_e_AT_CGATT_cat_start:NET_LINE();// 打印行// 先清缓冲区netdev_opt-clear_rxbuf(netdev);// 发送ATCGATT?netdev_opt-send_str(netdev,ATCGATT?\r\n);// 记录当前的滴答到oticknetdev-otickget_sys_ticks();tlen0;// 切换下一个状态netdev-msta;break;case_e_AT_CGATT_cat_wait:// 等待100msnetdev-ntickget_sys_ticks();if((netdev-ntick-netdev-otick)50)break;// 记录当前的滴答到oticknetdev-oticknetdev-ntick;// 切换下一个状态netdev-msta;break;case_e_AT_CGATT_cat_work:// 接收数据到rxbuftlenuart-read(netdev-dev,(rx_buf[netdev-rx_len]),64);netdev-rx_lentlen;if(netdev-rx_lenNdev_RX_BUF_LEN){// 检查缓冲区netdev-rx_len0;netdev-mstanetdev-msta-2;// 回退2步NET_LINE();break;}//rx_buf[netdev-rx_len] \0;// 判断是否收到OKif(strstr(rx_buf,OK)!NULL){//netdev-rx_len 0;// 成立说明收到了OK回应netdev-msta;netdev-ssta0;netdev_opt-ptf_rxbuf(netdev,__func__,__LINE__);NET_LINE();break;}// 处理超时2s超时//4次尝试如果失败则退2个状态,// 如果重大错误自动进入_e_dev_err_mstanetdev_opt-deal_cmd_timeout(netdev,2000,4,netdev-msta-2,__func__,__LINE__);break;原因分析核心错误UART底层write函数FIFO判忙时句柄写死为UART0,和实际操作接口不匹配修改前底层write代码// 发送单字节数据staticvoidwrite(intindex,uint8_tdat){// 判断是否合法interr0;void*uartget_uart_by_index(index,err);if(1err){return;}// 判忙while(UART_IsTXFIFOFull(UART0));// 发送UART_WriteByte(uart,dat);}问题拆解get_uart_by_index(index)会根据传入的序号拿到目标串口句柄我们模组接的是 UART1但是判忙代码写UART_IsTXFIFOFull(UART0)永远只查询 UART0 的发送 FIFO 是否满。当 UART1 的 TX FIFO 已满UART0 的 FIFO 恰好为空while 循环直接退出不会阻塞等待。继续执行UART_WriteByte(uart, dat)向 UART1 写入字节此时 UART1 发送 FIFO 已满字节直接丢失。注意为什么在发送ATCGATT?之前的的ATCREG能跑成功属于偶然现象。发送第一条AT时UATRT1的TX FIFO刚好有空字节成功写入。连续发送第二条AT指令时UART1的FIFO还未排空但UART0是空判忙失效字节丢失Air780E 收不到完整 AT 指令直接不回复任何数据read tlen 恒等于 0。修改前底层write代码// 发送单字节数据staticvoidwrite(intindex,uint8_tdat){// 判断是否合法interr0;void*uartget_uart_by_index(index,err);if(1err){return;}// 判忙while(UART_IsTXFIFOFull(uart));// 发送UART_WriteByte(uart,dat);}排查思路1. 分层定位先排除硬件第一条AT指令ATCREG?正常收发证明供电、串口接线、波特率、接受中断、Air780E 模组本身硬件正常。问题限定在连续发送第二条 AT 的软件逻辑不是硬件故障。2. 区分代码执行日志 ≠ 硬件真正发出数据日志打印Send AT CGATT? 只代表代码走到发送函数不代表字节真正从 TX 引脚发送出去。tlen0代表模组没有返回任何应答大概率模组没有收到完整指令。3. 分层排查顺序上层状态机 → 发送函数 air_send_str → 底层uart-write排除上层字符串发送循环问题怀疑时序增加发送前延时、修改 wait 滴答增加 AT 指令间隔无效怀疑 AT 指令本身更换ATCGATT1依旧 tlen0排除模组 AT 指令不支持的猜想下沉到底层 uart 驱动检查write的 FIFO 判忙逻辑发现句柄写死 BUG。4. 验证猜想修改 FIFO 判忙的句柄测试第二条 AT 可以正常收到应答tlen0问题解决。核心经验串口驱动中判忙查询的串口句柄必须和写入字节的串口句柄保持一致不能硬编码写死某一路串口。总结对硬件外设进行状态查询、读写操作时必须使用同一个外设实例句柄。千万不要混用动态获取的句柄变量和硬编码的外设宏定义二者一旦不匹配极易产生这种偶现、迷惑性极强的隐藏问题。新手不要一上来就修改上层业务状态机分层排查从业务层下沉到底层驱动先确认数据有没有真正发送出去。