首页 / 资讯中心 / 文章详情

STM32+LWIP DHCP获取失败?从CubeMX到CLion的排查指南

STM32+LWIP DHCP获取失败?从CubeMX到CLion的排查指南 ★ FEATURED ARTICLE
简介面向STM32嵌入式开发者与物联网学习者的LWIP联网工程包基于STM32F407ZGTx和STM32CubeMX图形化配置配合Clion/CMake工具链实现DHCP动态获取IP及网线插拔状态检测与重连。该工程已有592人学习浏览可作为STM32网络开发的基础模板。压缩包约2.71MB共603个文件其中212个h头文件与108个c源文件构成HAL库及LWIP协议栈主体ioc与mxproject配置记录外设和网络参数elf、hex固件与cmake构建脚本则支撑在Clion中直接编译验证。从CubeMX配置生成到Clion导入构建均有对应文件能帮助快速定位以太网初始化、DHCP调用与连接状态监测等关键流程适合在Cortex-M4平台直接移植或二次改造满足智能设备联网、数据上报等场景的快速搭建需求。1. 为什么 STM32CubeMX CLion LWIP 的组合普遍卡在 DHCP 这一步不少工程师对这套开发链路的预期是STM32CubeMX 生成 LWIP 中间件代码CLion 打开工程编译烧录网口插上网线 DHCP 自动拿到 IP一切顺理成章。但实际把板子握在手里最常见的结局是这一串动作都做完了串口却反复打印 DHCP timeoutping 不通甚至 PHY 的 link 灯压根不亮。这件事的麻烦之处在于STM32CubeMX CLion LWIP 获取 DHCP 是一条很长的配置链路DHCP 只是最下游的一层。前面任何一环出错——ETH 外设没开、RMII 时钟不对、LWIP 内存参数不合理、MAC 地址不合法——最后都表现为DHCP 获取不到 IP。定位时要一头扎进协议栈翻代码而不是只看协议本身。这篇文章把这套链路从 CubeMX 配置、CLion 工程编译、LWIP 初始化顺序到 DHCP 状态机和典型故障逐个拆开。已经能独立编译 STM32 工程、但第一次在 CLion 里碰 LWIP 的人能照着把网口跑通静态 IP 能通但 DHCP 一直失败的人也能在这里找到排查方向。2. CubeMX 里把 LWIP 与 DHCP 正确配对ETH 外设与中间件生成的先后逻辑2.1 先开 ETH 外设再开 LWIP两个必须同时满足的前置条件在 CubeMX 里启用 LWIP 之前第一步永远是先让 ETH 外设存在。很多人直接去 Connectivity → LWIP 里勾选 Enabled发现整排选项是灰色的原因就是左边 Pinout 视图里还没启用以太网相关引脚。以最常见的 STM32F407 LAN8720A RMII 方案为例在 Pinout 视图里打开 ETH 外设后CubeMX 会自动把 RMII 需要的 7 根引脚分配出来ETH_RMII_REF_CLK、ETH_RMII_MDIO、ETH_RMII_MDC、ETH_RMII_CRS_DV、ETH_RMII_RXD0、ETH_RMII_RXD1、ETH_RMII_TX_EN、ETH_RMII_TXD0、ETH_RMII_TXD1。如果此时引脚冲突CubeMX 会标红需要手动调整。ETH 外设启用后再去 Connectivity → LWIP 启用中间件。这里有个容易忽略的细节CubeMX 的 LWIP 页面里有多个协议层的开关很多人直接看 Network Interface 相关配置却漏了最上层的 Ethernet 使能导致生成的工程里只有 LWIP 核心代码而没有 HAL 的 ETH 驱动。时钟配置也必须在生成前确认。RMII 模式的 REF_CLK 必须是 50MHz通常由 STM32 的 MCO2 输出提供。在 Clock Configuration 页面里MCO2 的时钟源要选 PLLCLK分频系数要算准否则后面 PHY 的 RX 采样会出问题。这个问题在 CubeMX 阶段不报错要到运行时才暴露属于典型的配置看着没问题硬件上死活不通。2.2 在 CubeMX 勾选 DHCP 的入口与生成的 netif 初始化代码LWIP 中间件启用后在 LWIP 的配置页面里找到 DHCP 相关选项通常叫 Enable DHCP 或在 ipv4 配置里有个 DHCP 复选框。注意这一步很多人理解成在 LWIP 页面勾了 DHCP代码就会自动调用 dhcp_start。实际上勾选的作用是让生成代码时预置 LWIP_DHCP 宏和自动初始化逻辑真正的启动调用在 MX_LWIP_Init() 尾部。生成工程后打开 lwip.c 或 lwip_init.c 里的 MX_LWIP_Init()能看到 CubeMX 自动写的初始化序列核心逻辑是这样一段void MX_LWIP_Init(void) { /* 先做协议栈全局初始化 */ lwip_init(); /* 注册网卡接口 */ netif_add(g_netif, g_ipaddr, g_netmask, g_gateway, NULL, ethernetif_init, tcpip_input); /* 设为默认网卡并启动 */ netif_set_default(g_netif); netif_set_up(g_netif); netif_set_link_up(g_netif); /* 如果 CubeMX 配置里勾了 DHCP这里会自动调用 */ #if LWIP_DHCP dhcp_start(g_netif); #endif }这段代码里的 g_ipaddr、g_netmask、g_gateway 就是 CubeMX 根据配置生成的 IP 参数默认全 0。如果启用了 DHCP这三个地址在拿到租约前都会被协议栈覆盖为 0所以不要在代码里试图把这些变量改成静态值硬编码——那只会让 DHCP 和静态配置互相打架。2.3 选择能为 CLion 直接消费的工程形式Makefile 转 CMake 的取舍在 CubeMX 的 Project Manager → Project 页面里Toolchain 下拉框里有多个选项常见的是 Makefile 和 CMake。CLion 原生只吃 CMake所以这里直接选 CMake 是最省事的路径。选好后 CubeMX 会生成 CMakeLists.txt 和配套的 cmake 工具链文件CLion 打开根目录即可识别。如果用的是旧版本 CubeMX没有 CMake 选项只能生成 Makefile 工程。CLion 虽然也支持 Makefile 工程通过 Makefile Support 插件但维护起来有点别扭每次从 CubeMX 重新生成代码后Makefile 里的源文件列表、头文件路径有变化的话需要在插件配置里手动同步。作为长期方案我更建议在 CubeMX 里选 CMake 工程让工具链保持干净。生成完成后检查一下目录里是否真的出现了 CMakeLists.txt以及 lwip 相关的源文件路径是否写进了 CMakeLists 的 target_sources。这一个动作能帮你在编译阶段省掉大量莫名其妙的 undefined reference 报错。3. CLion 里跑通编译链与 LWIP 内存参数从报错到可控的第一版固件3.1 配置 ARM GCC 工具链的步骤与常见编译报错CLion 本身不带交叉编译链需要先装好 arm-none-eabi-gcc 工具链。打开 Settings → Build, Execution, Deployment → Toolchains点加号新建一个选择 ARM Embedded然后分别指定 arm-none-eabi-gcc、arm-none-eabi-g、arm-none-eabi-gdb 和 arm-none-eabi-objcopy 的路径。编译器路径写错的话CLion 会在 CMake configure 阶段直接报错根本走不到编译那一步。工具链配好后首次打开 CubeMX 生成的 CMake 工程大概率会碰上几种报错。最常见的是找不到 HAL 配置头文件比如 fatal error: stm32f4xx_hal_conf.h: No such file or directory。原因是 CMakeLists.txt 里的 include 路径没有覆盖 CubeMX 生成的 Inc 目录。解决方法是打开 CMakeLists.txt在 target_include_directories 里把工程根目录下所有需要的路径补全至少包括 Inc、Drivers/STM32F4xx_HAL_Driver/Inc、Drivers/STM32F4xx_HAL_Driver/Inc/Legacy、Middlewares/Third_Party/LwIP/src/include 这几个关键路径。还有一种情况是编译能过但链接阶段报 undefined reference比如 HAL_ETH_Init 或 tcpip_input 找不到定义。这通常不是链接器的问题而是 CubeMX 生成的 CMakeLists.txt 里 target_sources 少了某些 .c 文件比如 stm32f4xx_hal_eth.c 和 lwip 的源文件没被收录。打开 target_sources 对照一下源文件清单手动补进去重新加载 CMake 工程即可。3.2 LWIP 内存四参数MEM_SIZE、PBUF_POOL_SIZE、PBUF_POOL_BUFSIZE、TCPIP_MBOX_SIZELWIP 移植到 STM32 上内存参数直接影响 DHCP 能不能稳定跑。CubeMX 生成代码时会在 lwipopts.h 里给一套默认值但那套默认值是针对通用平台的放在资源有限的 MCU 上常常偏紧。我一般会打开 lwipopts.h 逐个核对这几个参数参数默认值建议值说明MEM_SIZE默认较大根据 RAM 余量调通常 16~32 KB协议栈内部堆用于 netconn 等动态分配PBUF_POOL_SIZE8~168~16pbuf 池数量太小会丢包PBUF_POOL_BUFSIZE1280~15001500每个 pbuf 大小必须能容纳一个完整 MTU 帧TCPIP_MBOX_SIZE88~16TCP/IP 线程消息邮箱容量高频收发时需调大这个表格是通用的起点。DHCP 获取本身占用的 pbuf 不多但如果 PBUF_POOL_SIZE 太小DHCP 的 discover 报文发出后offer 报文回来时 pbuf 池被其他通信占满DHCP 就会超时重传表现成静态 IP 能用DHCP 偶尔能获取成功但极不稳定。所以不要为了省 RAM 把这几个参数压得太狠。PBUF_POOL_BUFSIZE 和 MEM_SIZE 是两套独立的内存体系前者是固定池后者是可变堆。DHCP 获取过程中 DHCP 报文相对较小一般不挑剔这两个参数但 TCP 收发大包时 PBUF_POOL_BUFSIZE 小于 1500 会造成分包失败。把这两个参数和后面 TCP_MSS 参数一起看不要只调一个。3.3 强制开启 LWIP_DHCP 宏与 AUTOIP 的取舍CubeMX 勾选 DHCP 后生成的 lwipopts.h 里 LWIP_DHCP 宏应该是 1。但如果你的工程是自己改过 lwipopts.h或者从别的工程拷贝过来这个宏可能被别处的定义覆盖。这里有两种处理方式我倾向于在 CMakeLists.txt 里用 add_compile_definitions 强制指定这样不管 lwipopts.h 怎么改编译宏始终生效add_compile_definitions(LWIP_DHCP1)比如在 CMakeLists.txt 里的 add_executable 前面加上这行然后重新加载工程。用编译宏而不是去改头文件的好处是CubeMX 重新生成代码后 lwipopts.h 会被覆盖但 CMakeLists.txt 里的宏不会丢少一次重复劳动。同时建议把 LWIP_AUTOIP 关掉。AUTOIP 会在 DHCP 失败后自动给自己分配一个 169.254.x.x 的链路本地地址这个地址在某些网络环境下会导致设备看起来通了但实际访问不了外网排查时很容易混淆问题。DHCP 和 AUTOIP 同时开启时协议栈的地址分配逻辑会进入一种先到先得的竞争状态在调试初期非常难判断到底谁生效了。等 DHCP 稳定了再考虑要不要开 AUTOIP 做兜底。3.4 netif 的 MAC 地址最容易忽略的合法性约束在 ethernetif.c 里CubeMX 生成的代码会定义一个 MAC 地址数组类似uint8_t mac_addr[6] {0x02, 0x00, 0x00, 0x12, 0x34, 0x56};这个数组的生成逻辑是 CubeMX 在配置时根据目标芯片和随机数生成的看起来没什么问题。但这里藏着一个非常隐蔽的坑MAC 地址第一个字节的最低位必须是 0。这个位是 IEEE 802.3 规定的单播/多播标志位如果它为 1这个 MAC 地址就是组播地址有些 PHY 芯片对这个地址的处理行为非常奇怪会导致设备不主动发报文DHCP 的 discover 根本发不出去。所以拿到新板子第一步先看 ethernetif.c 里这个数组第一字节。如果 bit0 是 1手动改掉比如把 0x03 改成 0x02把 0x01 改成 0x00。这个问题在 CubeMX 生成的工程里出现概率不高但从别的工程复制 LWIP 配置时很容易带上属于典型的从哪来不知道但 DHCP 就是不行的玄学问题。4. 从 netif 注册到 dhcp_start()获取 DHCP 的关键控制流4.1 lwip_init() 之后的初始化次序netif_add、netif_set_default、netif_set_upLWIP 的初始化顺序一旦颠倒DHCP 就必然失败。要理解为什么先看协议栈的依赖关系netif 必须完成注册才能接收报文默认网卡必须设置好后 tcpip_input 才知道把收到的帧交给哪个接口接口必须处于 up 状态协议栈才会把它当成可用接口去处理 DHCP 状态机。CubeMX 生成的 MX_LWIP_Init() 里顺序是对的先 lwip_init()再 netif_add()然后 netif_set_default()接着 netif_set_up()。这里值得多说一句的是 netif_set_link_up() 和 netif_set_up() 的区别。前者表示物理链路已连接网线插上了后者表示网络接口逻辑上已被使用。在 PHY 自动协商完成之前不应该手动调用 netif_set_link_up()因为此时链路实际是断的链路层状态和物理状态不一致DHCP 报文即使发出去了也到不了交换机。在实际调试中我常看到有人把 netif_set_link_up() 放在初始化函数里而 PHY 的协商还没结束结果就是 DHCP 请求发出去后完全没有回应。正确的做法是等 PHY 中断或轮询到 link 状态位后再调用 netif_set_link_up()。如果用的是 CubeMX 的默认移植这一步通常已经由 ethernetif.c 里的 link 检测逻辑处理好了不需要额外关心。4.2 DHCP 状态机DISCOVER → OFFER → REQUEST → BOUND 在 LWIP 里的对应实现LWIP 的 DHCP 客户端实现在 dhcp.c 里核心状态机挂在 netif 的 dhcp 结构体上。dhcp_start() 被调用后协议栈并不会立即开始广播 DHCPDISCOVER而是先经过一段很短的状态准备期然后置为 DHCP_STATE_DISCOVER发出第一个 discover 报文。之后协议栈进入等待状态由 DHCP 精细定时器DHCP_FINE_TIMER_MSECS默认 500ms不断推进。收到 OFFER 报文后客户端校验报文里的 xid 事务编号是否和本机发出的 discover 一致以及 server_id 选项是否有效确认后进入 DHCP_STATE_REQUEST发出 REQUEST 报文。服务器返回 ACK 后状态机跳到 DHCP_STATE_BOUND此时 netif-dhcp-offered_ip_addr 才会被写入 netif 的 IP 地址字段。这个状态迁移过程在 lwip 的 dhcp.c 里是自动的工程代码里通常不需要直接操作状态字段。但调试时可以通过打印 netif-dhcp-state 的数值来观察客户端处在哪个阶段这个技巧留在最后一章展开。如果你看到状态一直停在一个值上不变说明对应的报文没等到需要回头查链路层。4.3 周期维护 tcpip_thread 与 eth_rx 轮询主循环里应该做什么LWIP 在 STM32 上有两种运行模式裸机NO_SYS1和 RTOS 模式。CubeMX 默认会在中间件配置里提示你选一种这个选择直接决定了主循环里要不要手动驱动协议栈。裸机模式下接收报文和定时器都需要手动喂。CubeMX 生成的 ethernetif.c 里会有一个 ethernetif_input() 函数用来把收到的网络帧送进 LWIP 协议栈sys_check_timeouts() 则用来驱动 DHCP 的定时器状态机。这两个函数在主循环里必须周期调用否则 DHCP 流程永远走不到下一步。int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_LWIP_Init(); while (1) { /* 裸机模式下必须手动喂包 */ ethernetif_input(g_netif); /* 驱动 LWIP 内部超时与 DHCP 状态机 */ sys_check_timeouts(); /* 业务代码放这里 */ HAL_Delay(1); } }逻辑说明ethernetif_input() 从以太网 DMA 描述符里取出接收到的帧交给 LWIP 的 tcpip_input 入口sys_check_timeouts() 触发 DHCP 精细定时器和粗定时器的回调。如果这两个调用间隔太久DHCP 报文会被延迟处理而 DHCP 服务器端的超时时间通常是固定的客户端迟迟不回应就会导致获取失败。建议把这两个调用的间隔控制在 10ms 以内HAL_Delay(1) 是实际项目中常用的节奏。RTOS 模式下情况完全不同。CubeMX 生成的代码在初始化时会创建 tcpip_thread 线程ethernetif_input() 和 sys_check_timeouts() 都由这个线程调度主循环里不需要也不应该手动调用。如果你在裸机工程里用 RTOS 代码库或者在 RTOS 工程里又手动调了这两个函数结果要么是重复调用、要么是定时器任务冲突DHCP 行为会变得很不稳定。4.4 获取 DHCP 后的验证入口检查 IP 地址是否真正生效DHCP 拿到 IP 后netif 结构体里的 ip_addr 字段会被更新。最简单的验证方式是在代码里轮询这个字段但要注意一点在拿到 IP 之前这个字段是 0.0.0.0拿到后变成实际地址。判断的触发条件是两个状态同时成立netif 的 flag 里设置了 NETIF_FLAG_UP并且 ip_addr 不再全 0。if ((netif_is_up(g_netif)) (!ip4_addr_isany_val(netif_ip4_addr(g_netif)))) { /* DHCP 已经获取到合法 IP */ uint32_t ip ip4_addr_get_uint32(netif_ip4_addr(g_netif)); printf(DHCP OK: %lu.%lu.%lu.%lu\r\n, (ip 24) 0xFF, (ip 16) 0xFF, (ip 8) 0xFF, ip 0xFF); }这段代码里的 netif_ip4_addr() 宏在较新的 LWIP 版本里是标准接口旧版本访问 netif-ip_addr.u_addr.ip4.addr 也能拿到同样的数值。注意打印格式里的移位顺序IP 地址在 lwip 里是以网络字节序保存的这里用大端方式拆出来才是 192.168.1.100 这种正常格式。如果拆出来的数字前后颠倒多半是字节序处理反了。5. DHCP 获取不了的避坑排查5 个压箱底的故障场景5.1 链路层故障MAC 地址不合法与 RMII 时钟频率错误先说文首那个最常见的坑。现象是DHCP 一直超时串口反复打印 timeout静态 IP 也同样 ping 不通甚至 PHY 的 link 灯不亮。这时候首先查 MAC 地址数组看第一字节的最低位是否为 0。有一次我在一块代工板子上折腾了半个下午最后发现是设计文件里把 MAC 地址写成了 0x03位 0 为 1PHY 把本地地址当成了组播地址拒绝收发单播帧。解决方式很简单把 MAC 数组的第一个字节改成 0x02 或 0x00 之类的偶数地址即可。改完重新编译烧录link 灯和设备协商恢复正常。这里建议在 ethernetif.c 的同一处加个注释标清楚第一字节 bit0 必须为 0防止后面接手的人又改回去。第二个链路层重灾区是 RMII 的 REF_CLK 频率。现象是偶尔能获取到 IP但链路极不稳定十几秒就断一次重连后又能用。用逻辑分析仪或示波器测量 PHY 的 REF_CLK 引脚如果发现频率不是 50MHz问题就出在 MCO2 的时钟配置上。查 STM32 的 RCC 寄存器确认 MCO2 的预分频系数。如果 PLLCLK 是 100MHz分频系数应该是 2输出才是 50MHz。这里的坑在于 CubeMX 的时钟树页面改起来很顺手但改完后有没有真正生效需要重新生成代码并检查 HAL_RCC_MCOConfig 的调用参数。5.2 生成与编译层面LWIP 源码没生成、CMake 源文件缺失第三个坑发生在 CubeMX 阶段。现象生成的工程目录里根本找不到 LWIP 中间件源码lwip.c、ethernetif.c 都不存在。原因通常是启用 LWIP 后没有保存配置就直接生成代码CubeMX 的中间件页面存在一个图纸未保存的状态生成时只输出了 HAL 库代码把 LWIP 模块整个跳过了。这个问题的特征很隐蔽因为 CubeMX 不会报错只会在输出栏里提示某模块被跳过。解决方法是回到 CubeMX 的 LWIP 配置页按 CtrlS 保存所有修改确认左侧页面显示没有未保存的星号标记再重新生成。如果你已经在这个工程上做过大量 CLion 配置可以只重新生成代码而不用重建工程目录CubeMX 会覆盖已有源文件CMakeLists.txt 也会同步更新CLion 重新加载一下就能看到新增的 LWIP 文件。第四个坑与 CMake 相关。现象是编译时大量 undefined reference 报错指向 HAL_ETH_Init、lwip_init、tcpip_input 等符号。原因是生成的 CMakeLists.txt 没把 LWIP 源文件目录完整收到 target_sources 里常见于 CubeMX 版本升级后模板路径变化或工程目录有中文路径导致的相对路径解析异常。解决方式是打开 CMakeLists.txt 检查 LWIP 相关路径比较典型的是 Middlewares/Third_Party/LwIP 下的 src/core、src/netif、src/api 目录是否都包含缺哪个补哪个。5.3 DHCP 参数层宏被覆盖与超时重试节奏不合理第五个坑出在配置宏打架上。现象是 CubeMX 页面里 DHCP 明明勾选了生成的 lwipopts.h 里却找不到 LWIP_DHCP 的定义或者定义被注释掉了。这是因为 CubeMX 的 LWIP 页面生成代码时会根据上层配置修改 lwip/opt.h 或生成 lwipopts.h但如果你从旧工程拷贝过 lwipopts.hCubeMX 有概率不覆盖这个文件导致新配置没写进去。排查方式是在 CLion 里直接搜索整个工程目录看有几个 lwipopts.h逐个打开确认 LWIP_DHCP 宏的值。解决方式前面提过直接在 CMakeLists.txt 里加 add_compile_definitions(LWIP_DHCP1) 强制开启一劳永逸。第六个场景是 DHCP 超时重试节奏异常。现象是 DHCP 客户端发完 discover 后没有任何回应过很久才报超时或者几秒内反复重试把网络打满。LWIP 的 DHCP 重传由 DHCP_COARSE_TIMER_SECS 和 DHCP_FINE_TIMER_MSECS 控制默认值分别是 1 秒和 500 毫秒重试次数由 LWIP_DHCP 的相关宏控制。网段里如果有多个设备同时做 DHCP 请求协议栈的重传阈值和超时时间配置太激进会让交换机不堪重负。遇到这类问题把重试超时时间适当拉长给服务器留出响应窗口通常能改善成功率。6. 调试 DHCP 跳变的三个技巧让分配过程从黑匣子变成可观测状态机第一个技巧是打印 DHCP 状态机的状态值。LWIP 的 dhcp.c 里定义了一组 DHCP_STATE_ 开头的枚举从 DHCP_STATE_OFF 到 DHCP_STATE_BOUND 依次编号。在 netif 初始化后周期读取 netif-dhcp-state 并打印能看到客户端在 DISCOVER、REQUEST、BOUND 之间跳动的完整过程。如果状态长时间停在 DISCOVER问题几乎肯定在物理链路或报文收发如果卡在 REQUEST问题多半在 DHCP 服务器对客户端身份的校验上比如 MAC 地址被服务器拉黑。这个观察方法比看日志猜要快得多。第二个技巧是用 PHY 寄存器确认链路状态再谈 DHCP。很多人一上来就调 LWIP浪费大量时间后发现 PHY 压根没协商成功。不如先把链路层验透。下面这段代码读取 LAN8720A 的基本模式状态寄存器检查 link 位和协商结果uint32_t phyreg 0; HAL_StatusTypeDef st HAL_ETH_ReadPHYRegister(heth, PHY_ADDRESS, PHY_BSR, phyreg); if (st HAL_OK) { if (phyreg PHY_LINKED_STATUS) { /* 链路已建立可以继续查 DHCP */ } else { /* PHY 未协商成功先查网线、复位、REF_CLK */ } }PHY_ADDRESS 对应硬件上 PHY 芯片的地址引脚设置LAN8720A 默认地址是 0。PHY_BSR 是基本状态寄存器PHY_LINKED_STATUS 这个宏在 HAL 库里通常已经定义好。运行这段代码如果链路状态位一直是 0就不用去看 tcpip_thread 和 DHCP 了问题不在协议栈。第三个技巧是静态 IP 对照实验。代码里暂时把 dhcp_start 注释掉手动给 netif 赋一个固定 IP、掩码和网关然后 ping 这个 IP。如果静态 IP 能通问题锁定在 DHCP 流程如果静态 IP 也不通问题在 MAC、PHY、时钟或 DMA 描述符配置。这个三分法能快速砍掉一半排查范围。注意对照实验做完后要把静态 IP 代码删干净避免和 DHCP 代码冲突。我记得有一次调一个远程设备的网络模块DHCP 获取 IP 后经常几小时掉线一次抓包看到重协商过程中客户端和服务器对租约时间理解不一样最后发现是 LWIP 的 DHCP 租约时间处理参数和服务器下发的 option 51 值不匹配。从那以后我在调试 DHCP 时都会主动打印租约时长和续租时间而不是只看 IP 拿到没有。这套从 CubeMX 到 CLion 再到 DHCP 状态机的链路踩过一次坑之后就能变成肌肉记忆希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站