LV030-ATK-MW8266D联调与排错
驱动写完只是开始。模块不上报、上报了但判不出帧、判出帧了却内容不对——这三类现象看起来都是"没有应答",实际定位手段完全不同。这一篇讲联调环境怎么搭、日志该长什么样,以及怎么用几个状态量把故障范围从"整个链路"缩小到"某一行代码"。
一、测试环境准备
(1)PC 与模块连同一个 2.4 GHz 热点。ESP8266 不支持 5 GHz,这一步没做对,后面所有步骤都会莫名失败。
(2)在 PC 上开网络调试助手,建 TCP Server,端口 8080,记下 PC 的局域网 IP(ipconfig),填进 DEMO_TCP_SERVER_IP。
(3)串口助手连调试口,115200 8N1,用于看日志。
(4)先关掉 PC 防火墙,或为 8080 放行。
(5)把模块 IP、PC IP、服务器端口写在纸面上再开始,这三者任何一个记错都会表现为"连接超时"。
更省事的做法是保留一个 at <指令> 调试命令,不改代码就能逐条试指令,见LV025-ATK-MW8266D驱动实现里 API 一览的自测层部分。
二、预期日志
初始化阶段(atk_mw8266d_init() 内部的 AT 测试成功会打印一行):
ATK-MW8266D_EOK
Joining to AP...
IP: 192.168.1.123进入透传后,按键或周期发送的数据应当原样出现在网络调试助手的接收区;服务器下发的数据则出现在串口助手里:
AT test success!
Enter unvarnished!
This ATK-MW8266D TCP Connect Test.日志的价值在于"基线":先确认正常时打印什么,故障时才知道哪一行消失了。AT test success! 没出现,说明卡在 AT 探测;出现了但 Joining to AP... 之后没有 IP,说明卡在联网——两个阶段要查的原因完全不同。
三、先看状态,再猜原因
原始代码在自测失败时只打印"失败了",这没有信息量。改成把 USART3 的收发状态一并打出来:
// Drivers/BSP/ATK_MW8266D/atk_mw8266d_test.c
static void atk_print_uart_state(void)
{
printf(ATK_TEST_TAG " uart: rx_err=%u rx_st=%u rx_type=%u buf=%u/%u SR=%04X CR1=%04X\r\n",
(unsigned int)atk_mw8266d_uart_rx_error_count(),
(unsigned int)huart3.RxState,
(unsigned int)huart3.ReceptionType,
(unsigned int)(huart3.RxXferSize - huart3.RxXferCount),
(unsigned int)huart3.RxXferSize,
(unsigned int)huart3.Instance->SR,
(unsigned int)huart3.Instance->CR1);
}各字段的判读方式:
| 字段 | 含义 | 判读 |
|---|---|---|
buf=n/size | 已进缓冲但还没等到空闲中断的字节数 | 大于 0 说明数据到了、IDLE 没上报;恒为 0 说明一个字节都没收到(模块没应答,或本地没发出去) |
rx_err | 溢出、上一帧未取走就被覆盖等错误累计 | 非 0 多半是电气/接线问题,或上一帧没被 rx_restart() 取走 |
rx_st | HAL 的 RxState | BUSY 说明还在收;如果一直停不到 READY 而 buf 也在涨,就是 HAL 与自管逻辑打架 |
rx_type | HAL 的 ReceptionType | 决定 buf 是按哪个字段算的,换过接收方式时要对着看 |
SR | 状态寄存器快照 | 看 RXNE(0x0020)、IDLE(0x0010)、ORE(0x0008)、FE/NE(0x0002/0x0004)哪一位亮着 |
CR1 | 控制寄存器快照 | 看 RXNEIE(0x0020)、IDLEIE(0x0010)、TE/RE(0x0008/0x0004)是否真的使能 |
buf 那一栏是最有价值的一个数:它把"模块没回"和"回了但没上报"这两件事直接分开——前者查硬件,后者查中断。后面那个故障复盘就是靠这个数字定位的,见at 命令全部返回 ERROR 的排查记录。
四、常见故障
| 现象 | 最可能的原因 | 处理 |
|---|---|---|
init failed,10 次 AT 全无应答 | P8 跳线帽没短接 / TX-RX 没交叉 / PA4 一直低 / 波特率不符 | 按接线与工程配置里的核对表逐条检查 |
偶发 init failed,重上电就好 | 供电不足(峰值 200 mA)或复位后等待不足 | 换稳的 3.3 V,把 500 ms 加到 800 ms |
AT 有回应但 AT+RESTORE 超时 | 模块重启较慢,3 s 不够 | 把超时加到 5000 ms |
join_ap 失败 | SSID 是 5 GHz / 密码错 / 信号弱 / MAC 过滤 | 用手机热点验证;查 +CWJAP:<error code>(1 超时 2 密码错 3 找不到 AP 4 连接失败) |
get_ip() 拿到乱码或空串 | 没先 ATE0,第一对引号是回显的指令本身 | 在 get_ip() 之前 ate_config(0) |
connect tcp server 返回 ERROR | 服务器没启动 / 端口被占 / 不在同网段 | 先用 PC 的 telnet 或第二个调试助手连一次 |
| 透传发数据,服务器收不到 | CIPSEND 没返回 >(没真正进入透传)/ 连接已断 | 打印 enter_unvarnished() 的返回值;查模块是否打印 CLOSED |
| 退出透传后 AT 无响应 | +++ 前后静默不足 1 s | 退出后 HAL_Delay(1000) 再发 AT |
| 接收数据明显被截断 | 帧缓冲深度上限(原厂 127、本工程 255 字节可用) | 加大 ATK_MW8266D_UART_RX_BUF_SIZE 或改环形缓冲 |
| 程序卡在某处不返回 | send_at_cmd 阻塞(最长 10 s) | 正常现象;需要并发就把 WIFI 流程挪到独立任务 |
| 慢指令一律返回超时 | 等待窗口比指令本身还短(AT+CWJAP 官方建议 15 s) | 把窗口提到 15 s,快指令仍会提前返回 |
| 长 AT 指令被截断或判非法 | 命令行缓冲只有 16 字节,且尾随空格被一起发给模块 | 单行上限提到 64 字节;行尾空白裁掉再解析 |
五、已知限制
(1)帧缓冲只有几百字节(原厂 128、本工程 256)。长应答(AT+CWLAP)与大数据块透传都会被截断,本驱动不适合这两类场景。
(2)全程阻塞式。send_at_cmd() 靠 HAL_Delay(1) 轮询,join_ap() 最坏 10 s,HAL_UART_Transmit 也是阻塞发送。裸机主循环里能接受,放进 RTOS 要注意任务栈与看门狗。
(3)get_ip() 依赖 ATE0。它用"第一个引号对"取 IP,回显开着时取到的是指令本身。这是实现上的取巧,不是协议保证。
(4)没有断线检测与重连。连接断开后模块只打印 CLOSED,驱动不解析、不上报,应用层无法感知。需要的话得自己增加 CLOSED/WIFI DISCONNECT 关键字检测。
(5)只封装了单连接 TCP 客户端 + 透传。多连接(CIPMUX=1)、TCP 服务器(CIPSERVER)、UDP、SSL 都没有封装,需要按同一模式自行扩展——send_at_cmd() 就是扩展的支点。
(6)透传下发无协议分帧。接收边界只靠总线空闲(约 20 ms 间隔)判定,没有长度、没有校验。要保证完整性,必须在应用层自己加帧头与 CRC。
(7)ret += ... 的累加判断只能回答"有没有失败"。建议移植时改为逐条判断并打印步骤名。