Skip to content

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:

text
AT+CWMODE=1

目标模式与当前模式相同时,模块回 no change,同样带 OK,无需特判。模式切换后射频要重新初始化,建议延时 200 ms 再做后续操作。

2. 连接与断开热点(AT+CWJAP / AT+CWQAP) ​

连接热点:

text
AT+CWJAP="MyWiFi","12345678"

连接成功是一个漫长的应答流:WIFI CONNECTED、WIFI GOT IP,最后才给 OK,整个过程通常 1~5 s。失败时模块回 +CWJAP:<错误码> 加 FAIL,没有 OK——这一点对超时策略很关键,详见本文第三节。

开放热点不传密码即可:

text
AT+CWJAP="MyOpenWiFi"

断开热点:

text
AT+CWQAP

断开只脱网,模式不变,IP 随即回落到 0.0.0.0。

3. 查询网络信息 ​

3.1 本机 IP 与 MAC(AT+CIFSR / AT+CIPSTAMAC?) ​

text
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?) ​

text
AT+CWJAP?
+CWJAP:"MyWiFi","f4:2a:7d:f4:2b:8a",11,-56
OK

四个字段依次是热点名、BSSID、信道、信号强度(dBm)。未连接时回 No AP。

3.3 网关与掩码(AT+CIPSTA?) ​

text
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 开着时设置的地址会被重新分配覆盖:

text
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:

text
AT+CIPSTA="192.168.10.200"

AT+CWDHCP 的参数顺序在固件版本间对调过,与 AT+PING 的应答差异属同一类坑:

固件参数顺序关闭 STA DHCP恢复 STA DHCP
AT 1.2.0.0(老)mode 在前AT+CWDHCP=1,0AT+CWDHCP=1,1
新固件enable 在前AT+CWDHCP=0,1AT+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 由模块解析:

text
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 文件中声明:

c
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 文件中声明:

c
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 文件中声明:

c
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:两条指令都失败或应答里找不到 MAC
  • ATK_MW8266D_EINVAL:缓冲区为空或太小

1.4 atk_mw8266d_get_ap_info() ​

查询当前所连热点,该函数在 Drivers/BSP/ATK_MW8266D/atk_mw8266d.h 文件中声明:

c
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 文件中声明:

c
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 文件中声明:

c
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.103
  • time_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:

text
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,然后连接;成功后自动打印网络信息:

text
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 ​

断开热点并打印断开后的网络状态:

text
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:be

2.4 wifi ping ​

经模块探测主机连通性,支持连续探测并统计成功率:

text
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 replies

cnt 取 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 中:

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":

c
// flash-app/Drivers/BSP/ATK_MW8266D/atk_mw8266d.h
#define ATK_MW8266D_ECMD            4U      /* 模块回 ERROR: 指令不存在或不接受 */

(2)用 at 透传命令直接问模块,绕开封装层看原始应答。这是定位的关键一步:

text
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 放行后即可:

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 技能辅助生成