LV040-WiFi连接与ping探测
本文基于 atk-f103 仓库 flash-app 工程的 ATK-MW8266D 驱动,记录 WiFi 联网的完整链路:先用 AT 指令把连接、断开、信息查询、ping 探测逐个跑通,再封装成串口命令,最后复盘一次 ping 不通的排查过程。
涉及源码(均在 flash-app 工程内,下文不再重复标注):
Drivers/BSP/ATK_MW8266D/atk_mw8266d.c/.h:业务层,收发与解析 AT 应答Drivers/BSP/ATK_MW8266D/atk_mw8266d_test.c/.h:串口命令实现Core/Src/main.c:命令注册
一、 AT 指令联网
1. 工作模式切换(AT+CWMODE)
ESP8266 有三种工作模式:1 为 STA(连别人),2 为 AP(被连),3 为 STA + AP 共存。联网上网只用 STA,因此连接前先确保处于模式 1:
AT+CWMODE=1目标模式与当前模式相同时,模块回 no change,同样带 OK,无需特判。模式切换后射频要重新初始化,建议延时 200 ms 再做后续操作。
2. 连接与断开热点(AT+CWJAP / AT+CWQAP)
连接热点:
AT+CWJAP="MyWiFi","12345678"连接成功是一个漫长的应答流:WIFI CONNECTED、WIFI GOT IP,最后才给 OK,整个过程通常 1~5 s。失败时模块回 +CWJAP:<错误码> 加 FAIL,没有 OK——这一点对超时策略很关键,详见本文第三节。
开放热点不传密码即可:
AT+CWJAP="MyOpenWiFi"断开热点:
AT+CWQAP断开只脱网,模式不变,IP 随即回落到 0.0.0.0。
3. 查询网络信息
3.1 本机 IP 与 MAC(AT+CIFSR / AT+CIPSTAMAC?)
AT+CIFSR
+CIFSR:STAIP,"192.168.10.101"
+CIFSR:STAMAC,"dc:4f:22:xx:xx:be"
OK未联网时 STAIP 为 0.0.0.0。较新的固件 AT+CIFSR 只回 IP,MAC 要用 AT+CIPSTAMAC? 单独查;而 AT 1.2.0.0 这类老固件两者都回,用 STAMAC 关键字在两条应答里都能定位到 MAC。
3.2 当前热点信息(AT+CWJAP?)
AT+CWJAP?
+CWJAP:"MyWiFi","f4:2a:7d:f4:2b:8a",11,-56
OK四个字段依次是热点名、BSSID、信道、信号强度(dBm)。未连接时回 No AP。
3.3 网关与掩码(AT+CIPSTA?)
AT+CIPSTA?
+CIPSTA:ip:"192.168.10.101"
+CIPSTA:gateway:"192.168.10.1"
+CIPSTA:netmask:"255.255.255.0"
OK排查"有 IP 但上不了网"时先看这里:gateway 为 0.0.0.0 或不在本网段,出外网必然不通。
3.4 设置静态 IP(AT+CWDHCP / AT+CIPSTA)
静态 IP 分两步:先关掉 STA 的 DHCP,再用 AT+CIPSTA 设地址,顺序不能反——DHCP 开着时设置的地址会被重新分配覆盖:
AT+CWDHCP=1,0
AT+CIPSTA="192.168.10.200","192.168.10.1","255.255.255.0"
AT+CIPSTA?三行依次是:关闭 STA 的 DHCP、设置 IP/网关/掩码、回读确认。AT+CIPSTA 三个参数可以只给第一个,网关与掩码默认取 x.x.x.1 与 255.255.255.0:
AT+CIPSTA="192.168.10.200"AT+CWDHCP 的参数顺序在固件版本间对调过,与 AT+PING 的应答差异属同一类坑:
| 固件 | 参数顺序 | 关闭 STA DHCP | 恢复 STA DHCP |
|---|---|---|---|
| AT 1.2.0.0(老) | mode 在前 | AT+CWDHCP=1,0 | AT+CWDHCP=1,1 |
| 新固件 | enable 在前 | AT+CWDHCP=0,1 | AT+CWDHCP=1,1 |
恢复 DHCP 那一列两条指令写法恰好相同(两个参数都是 1),但语义不同;配置 STA+AP(mode/enable=2)时差异就显形了:老固件 AT+CWDHCP=2,0 与新固件 AT+CWDHCP=0,2 含义完全相反。另外 AT+CWDHCP 修改后需要 AT+RST 重启模块才生效。
三点提醒:
(1)静态 IP 必须与热点同网段,且避开 DHCP 池范围,否则与其它设备冲突。
(2)AT+CIPSTA 的设置保存在模块 flash,断电重启后仍是静态 IP;要恢复 DHCP 需重新执行 AT+CWDHCP 并重启。
(3)静态 IP 只改变本机地址的获取方式,如果设了静态 IP 后 ping 不通,先 AT+CIPSTA? 确认网关与掩码没配错,再回到第三节第 1 节的排查流程。
4. 联通性探测(AT+PING)
模块自带 ICMP 探测指令,域名与点分 IP 都行,DNS 由模块解析:
AT+PING="www.baidu.com"
+11
OK应答是单帧结论,不同固件格式不同(这正是第三节排查的主角):
| 固件 | 成功 | 失败 |
|---|---|---|
| 新固件 | +PING:11 | +PING:TIMEOUT |
| AT 1.2.0.0 实测 | +11 | 回 ERROR(未联网、目标不可达),未见过 +TIMEOUT |
解析层对两种格式的四种帧都做了兼容,其中 +TIMEOUT 属于文档记载、该固件实测未出现,留着兜底。
二、 命令封装
1. 驱动层接口
业务层接口在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 中声明,实现全部基于既有的 atk_exchange() 收发框架:发出指令、在窗口内等应答关键字、期间喂狗。
1.1 atk_mw8266d_set_mode()
切换 WiFi 工作模式,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:
uint8_t atk_mw8266d_set_mode(uint8_t mode);【函数作用】
发送 AT+CWMODE=<mode> 把模块切到 STA / AP / STA+AP,模式没变时模块回 no change,同样按成功处理。
【参数含义】
mode:目标模式,1 为 STA,2 为 AP,3 为 STA+AP
【返回值】
ATK_MW8266D_EOK:已处于目标模式ATK_MW8266D_ERROR:模块回 ERROR 或无应答ATK_MW8266D_EINVAL:mode 不在 1~3
1.2 atk_mw8266d_join_ap()
连接热点,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:
uint8_t atk_mw8266d_join_ap(const char *ssid, const char *pwd, uint32_t timeout_ms);【函数作用】
发送 AT+CWJAP="ssid","pwd" 并等待连接结论,pwd 为 NULL 或空串表示开放热点。
【参数含义】
ssid:热点名称,不能为空pwd:密码,NULL 或空串表示开放热点timeout_ms:最长等待时间,官方建议 15000
【返回值】
ATK_MW8266D_EOK:收到 OK,连接成功ATK_MW8266D_ERROR:模块明确回了 FAIL/ERROR(密码错、找不到热点),立即返回ATK_MW8266D_ETIMEOUT:等满超时没有任何结论ATK_MW8266D_EINVAL:ssid 为空
注意该函数没有走 atk_exchange():它只能等一个关键字,而 AT+CWJAP 失败时回的是 +CWJAP:3\r\nFAIL、没有 OK,用它会白等满超时,把"密码错"误报成"超时"。这里自己收帧,同时认 OK 与 FAIL/ERROR,密码错 1 s 内就出结论。
1.3 atk_mw8266d_get_mac()
查询本机 MAC,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:
uint8_t atk_mw8266d_get_mac(char *buf, uint16_t size);【函数作用】
优先发 AT+CIPSTAMAC? 查 MAC;指令不被认时退回 AT+CIFSR 的 STAMAC 字段(老固件把 IP 与 MAC 一起回),两条应答里 MAC 都在 STAMAC 之后的第一对引号内。
【参数含义】
buf:存放xx:xx:xx:xx:xx:xx的缓冲区size:缓冲区字节数,至少 18
【返回值】
ATK_MW8266D_EOK:成功,buf内为 MAC 字符串ATK_MW8266D_ERROR:两条指令都失败或应答里找不到 MACATK_MW8266D_EINVAL:缓冲区为空或太小
1.4 atk_mw8266d_get_ap_info()
查询当前所连热点,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:
uint8_t atk_mw8266d_get_ap_info(char *ssid, uint16_t ssid_size,
char *bssid, uint16_t bssid_size,
int16_t *channel, int16_t *rssi);【函数作用】
发送 AT+CWJAP? 并解析 +CWJAP:"ssid","bssid",channel,rssi,各输出参数均可为 NULL 按需取用。
【参数含义】
ssid/ssid_size:热点名称落点,建议 33 字节bssid/bssid_size:热点 MAC 落点,建议 18 字节channel:信道落点rssi:信号强度落点(dBm)
【返回值】
ATK_MW8266D_EOK:已连上热点ATK_MW8266D_ERROR:未连接(回答No AP)或应答解析失败
1.5 atk_mw8266d_leave_ap()
断开热点,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:
uint8_t atk_mw8266d_leave_ap(void);【函数作用】
发送 AT+CWQAP 断开当前热点。断开只是脱网,STA 模式不变,之后 IP 回落 0.0.0.0,再查 AT+CWJAP? 会回 No AP。
【参数含义】
无参数。
【返回值】
ATK_MW8266D_EOK:已断开ATK_MW8266D_ERROR:模块回 ERROR 或无应答
1.6 atk_mw8266d_ping_host()
主机探测,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:
uint8_t atk_mw8266d_ping_host(const char *host, uint16_t *time_ms);【函数作用】
发送 AT+PING="host" 做一次 ICMP 探测,域名与点分 IP 都可以,DNS 由模块解析,一次探测最长等 6 s(模块自身约 5 s 超时)。
【参数含义】
host:域名或点分 IP,如www.baidu.com、192.168.10.103time_ms:往返时间落点(ms),可为 NULL
【返回值】
ATK_MW8266D_EOK:收到应答,time_ms带回往返时间ATK_MW8266D_ERROR:模块回+PING:TIMEOUT,探测确实不通ATK_MW8266D_ECMD:模块回 ERROR,指令不存在或不接受ATK_MW8266D_ETIMEOUT:等满超时没有任何结论ATK_MW8266D_EINVAL:host 为空
应答解析同时兼容新老两种格式(+PING:11 与 +11),并要求收齐结论或 OK 就立即返回,不干等满超时,实现见第三节。
2. 控制台命令
命令处理在 Drivers/BSP/ATK_MW8266D/atk_mw8266d_test.c 中实现,入口为 atk_mw8266d_wifi_cmd(),统一注册在 wifi 命令名下,按第一个参数分子命令。
2.1 wifi info
打印当前网络信息:模式、热点名、BSSID、信道、信号强度、IP、MAC:
APP: echo: wifi info
[ESP8266] mode = 1 (STA)
[ESP8266] ssid = MyWiFi
[ESP8266] bssid = f4:2a:7d:f4:2b:8a, ch = 11, rssi = -56 dBm
[ESP8266] ip = 192.168.10.101
[ESP8266] mac = dc:4f:22:xx:xx:be未联网时热点项显示 (not joined)、IP 为 0.0.0.0 并附说明,"查询失败"与"没连上"分开打印。
2.2 wifi join
先 ping 模块确认在线,再按需切 STA,然后连接;成功后自动打印网络信息:
APP: echo: wifi join MyWiFi 12345678
[ESP8266] ---- wifi join ----
[ESP8266] mode = 1 (STA)
[ESP8266] joining "MyWiFi" ...
[ESP8266] joined
[ESP8266] mode = 1 (STA)
[ESP8266] ssid = MyWiFi
[ESP8266] ip = 192.168.10.101
[ESP8266] mac = dc:4f:22:xx:xx:be三种用法:
(1)wifi join <ssid> [pwd]:用给定热点连接,不给密码按开放热点处理。
(2)wifi join:使用 atk_mw8266d.h 中的默认热点宏(ATK_MW8266D_WIFI_SSID / ATK_MW8266D_WIFI_PWD,仓库里是占位符,真实凭据不写入代码)。
(3)wifi join 参数按空格切分,热点名与密码里不能带空格。
2.3 wifi leave
断开热点并打印断开后的网络状态:
APP: echo: wifi leave
[ESP8266] ---- wifi leave ----
[ESP8266] left the AP
[ESP8266] ssid = (not joined)
[ESP8266] ip = 0.0.0.0 (not joined to an AP)
[ESP8266] mac = dc:4f:22:xx:xx:be2.4 wifi ping
经模块探测主机连通性,支持连续探测并统计成功率:
APP: echo: wifi ping www.baidu.com 3
[ESP8266] ping www.baidu.com x3
[ESP8266] reply from www.baidu.com: time=11 ms
[ESP8266] reply from www.baidu.com: time=13 ms
[ESP8266] reply from www.baidu.com: time=12 ms
[ESP8266] 3/3 repliescnt 取 1~10,缺省 1。三种失败分别打印:TIMEOUT(模块说探测不通)、module ERROR(指令不支持)、module silent(6 s 无任何应答,提示检查联网)。
两点实测观察:
(1)ping 局域网 PC 的首个探测往往要 200 ms 上下(ARP 解析,加上防火墙首次处理入站 ICMP),后续稳定在 4~6 ms,属正常现象,不是链路抖动。
(2)断开热点后再探测,模块对 AT+PING 直接回 ERROR,命令层据此打印 module ERROR——"未联网"不需要等超时就能判定。
3. 注册与初始化
wifi 原来注册为无参命令(只跑模块自测),联网功能加入后改为带参注册,main.c 中:
// flash-app/Core/Src/main.c
(void)usart1_cmd_register_arg("wifi", atk_mw8266d_wifi_cmd); /* 'wifi [info|join ...]': 查询/联网 */同一条命令名不能再用 usart1_cmd_register() 注册一次;命令必须在 usart1_rx_start() 之前注册,否则命令表已开始使用。wifi join 过程最长等 15 s,期间驱动层在收帧循环里喂狗,IWDG 使能后也不会复位。
三、 常见问题
1. ping 不通排查实录
1.1 现象
模块联网状态完全正常(wifi info 能看到 IP、RSSI -56 dBm),但 wifi ping 无论是局域网 PC 还是 www.baidu.com,全部打印 TIMEOUT。
1.2 排查步骤
(1)先区分两种失败。初版解析把"模块回 ERROR 帧"与"探测超时"都显示成 TIMEOUT,无法判断是指令不支持还是网络不通。为此错误码里增加 ATK_MW8266D_ECMD,专门表示"模块回 ERROR":
// flash-app/Drivers/BSP/ATK_MW8266D/atk_mw8266d.h
#define ATK_MW8266D_ECMD 4U /* 模块回 ERROR: 指令不存在或不接受 */(2)用 at 透传命令直接问模块,绕开封装层看原始应答。这是定位的关键一步:
APP: echo: at AT+PING="192.168.10.1"
[ESP8266] > AT+PING="192.168.10.1"
[ESP8266] +5
[ESP8266] OK
APP: echo: at AT+PING="www.baidu.com"
[ESP8266] +11
[ESP8266] OK(3)对照透传结果与封装层结果:透传全部成功(网关 5 ms、公网 13 ms、域名 11 ms),封装层却全部超时——问题锁定在应答解析,而不是网络。
1.3 根因:老固件应答格式差异
模块固件是 AT version:1.2.0.0(Ai-Thinker,2016 年),它的 AT+PING 应答是 +<毫秒>(如 +5),超时回 +TIMEOUT;而解析代码按较新固件的文档实现,在等 +PING: 前缀。于是 +5、+13 这些结论帧被当成无关帧丢弃,等满超时报 TIMEOUT。
修复后 wifi ping 与透传结果一致(域名 11~18 ms、局域网 4~6 ms、断开后正确回 module ERROR)。这次排查的两个通用经验:
(1)封装层失败先透传验证。一条 at AT+PING="..." 就把"网络不通"与"解析错误"两个假设分开,比对着代码猜快得多。
(2)老固件的应答格式不能只看新文档。Ai-Thinker 2016 年版固件在网上存量极大,解析层对新老格式做兼容是必要的成本。
2. 其它典型问题
2.1 模块对 AT 指令回 ERROR
如果透传 AT+PING="..." 模块直接回 ERROR,说明这版固件根本没有该指令(老固件指令集不全很常见)。两个选择:升级 ESP8266 AT 固件,或者改用 TCP 连接(AT+CIPSTART)做连通性探测。封装层此时会把这类失败单独报为 module ERROR,与探测超时区分开。
2.2 局域网 PC ping 不通,但外网域名通
这是 Windows 防火墙默认拦截 ICMP 入站,与模块无关。管理员 PowerShell 放行后即可:
New-NetFirewallRule -DisplayName "Allow ICMPv4-In" -Protocol ICMPv4 -IcmpType 8 -Direction Inbound -Action Allow实测同一局域网内,防火墙放行后模块 ping PC 正常(首个探测 200 ms 上下,后续 4~6 ms);反过来 PC ping 模块也能通(实测 3/3 收到),但延迟高达 89~110 ms——ESP8266 处理入站 ICMP 优先级低,这个延迟是模块协议栈的开销,不能拿它衡量无线链路质量。
2.3 外网域名与局域网 IP 都探测不通
wifi info 有 IP 但 wifi ping 全部 +PING:TIMEOUT 时,按三步收敛:
(1)AT+CIPSTA? 看 gateway 是否为 0.0.0.0 或不在本网段——DHCP 没下发网关,出外网必然不通。
(2)AT+PING="<网关>" ——网关是局域网里最应该通的一跳。网关都不通而网关配置正常,基本就是路由器开了 AP 客户端隔离(无线终端之间及与有线不互通),关掉即可,它同时解释 ping PC 不通。
(3)网关通再 AT+PING="223.5.5.5" ——公网 IP 通而域名不通,是 DNS 没下发,TCP 直连 IP 不受影响。
本文档由 markdowncli 技能辅助生成