☰
在 Arduino_Core_STM32 中使用 STM32Ethernet 库让开发板上网:安装、依赖与 LwIP 调度机制解析
2026/10/15 20:52:13 网站建设 项目流程
  • 嵌入式
  • 固件
  • 驱动开发
  • 硬件开发

【免费下载链接】Arduino_Core_STM32

STM32 core support for Arduino

项目地址:https://gitcode.com/gh_mirrors/ar/Arduino_Core_STM32
点击查看免费下载

本文围绕 STM32 内核(Arduino_Core_STM32)配套的STM32Ethernet专用库展开,介绍如何让板载 Ethernet 控制器的 STM32 开发板接入互联网,包括硬件要求、通过 Arduino Library Manager 安装 LwIP 与 STM32Ethernet 的完整步骤,并结合仓库源码讲解它基于 LwIP 协议栈实现的 DHCP 自动续期、1ms 定时器调度(stm32_eth_scheduler())与Ethernet::schedule()的底层运行机制。读完本文,你可以在一台带以太网口的 STM32 开发板上用与 Arduino Ethernet 完全兼容的 API 快速跑通网络应用,并理解其调度原理以避免在中断与实时性要求高的场景踩坑。

STM32Ethernet 是什么

STM32Ethernet 是 stm32duino 生态中为 STM32 提供的以太网库,它允许带有板载 Ethernet 控制器的 STM32 开发板连接到互联网。它基于 Arduino 官方 Ethernet 库开发,且与 Arduino Ethernet 库完全兼容,因此从 Arduino 迁移到 STM32 时,Ethernet.begin()、EthernetClient、EthernetServer等 API 可以基本原样复用,文档中提供的示例可以直接用于快速上手。

在 docs/libraries/index.md 的 "Dedicated" 一节中,STM32Ethernet 被归类为针对特定硬件(板载 Ethernet 端口,例如 Nucleo-F429ZI)开发的专用库,其依赖项为:

  • LwIP:轻量级 TCP/IP 协议栈(Lightweight TCP/IP stack),是 TCP/IP 协议族的一个小型独立实现,作为 STM32Ethernet 的网络内核。

也就是说,STM32Ethernet 是"Arduino 风格的 API 外壳 + LwIP 协议栈内核"的组合:对外提供与 Arduino Ethernet 一致的用户接口,对内依赖 LwIP 完成 TCP/UDP/IP/DHCP 等协议处理。

硬件要求:需要带板载 Ethernet 的 STM32 板

STM32Ethernet只能用于带 Ethernet 兼容能力的 STM32 开发板,因为它是直接驱动芯片内置的 Ethernet MAC 外设(ETH),而不是通过 SPI 外接 ENC28J60 之类的控制器。官方文档给出的示例板有:

  • NUCLEO-F429ZI(基于 STM32F429ZI)
  • STM32F746G-DISCOVERY(基于 STM32F746NG)

在 boards.txt 中可以看到 NUCLEO_F429ZI 的配置条目,它属于Nucleo_144系列,构建参数为build.product_line=STM32F429xx、build.series=STM32F4xx,并通过-DCUSTOM_PERIPHERAL_PINS引入定制的引脚映射文件。

从仓库的 variant 源码可以确认这类板子的 ETH 外设支持是"开箱即用"的:

  • 在 variants/STM32F4xx/F427Z(G-I)T_F429ZET_F429Z(G-I)(T-Y)_F437Z(G-I)T_F439Z(G-I)(T-Y)/variant_generic.hT_F429ZET_F429Z(G-I)(T-Y)_F437Z(G-I)T_F439Z(G-I)(T-Y)/variant_generic.h) 与 variant_DISCO_F429ZI.hT_F429ZET_F429Z(G-I)(T-Y)_F437Z(G-I)T_F439Z(G-I)(T-Y)/variant_DISCO_F429ZI.h) 中,存在#if !defined(HAL_ETH_MODULE_DISABLED) #define HAL_ETH_MODULE_ENABLED的条件编译块,即只要未显式禁用,ETH HAL 模块默认启用;
  • 在 PeripheralPins_NUCLEO_F4x9ZI.cT_F429ZET_F429Z(G-I)(T-Y)_F437Z(G-I)T_F439Z(G-I)(T-Y)/PeripheralPins_NUCLEO_F4x9ZI.c#L370-L396) 的*** ETHERNET ***段落中,定义了 RMII 模式所需的引脚映射:PA1(ETH_REF_CLK)、PA2(ETH_MDIO)、PA7(ETH_CRS_DV)、PB13(ETH_TXD1)、PC1(ETH_MDC)、PC4(ETH_RXD0)、PC5(ETH_RXD1)、PG11(ETH_TX_EN)、PG13(ETH_TXD0)等,均以GPIO_AF11_ETH复用为以太网功能;
  • STM32F7 系列类似,例如 PeripheralPins_DISCO_F746NG.cT_F746N(E-G)H_F750N8H_F756BGT_F756NGH/PeripheralPins_DISCO_F746NG.c#L413-L415) 同样通过HAL_ETH_MODULE_ENABLED/HAL_ETH_LEGACY_MODULE_ENABLED条件编译启用 ETH 引脚表。

在 cores/arduino/stm32/stm32yyxx_hal_conf.h 中可以看到核心对 ETH 模块的统一开关逻辑:默认不启用(HALv1 下HAL_ETH_MODULE_ENABLED处于注释状态),只有当 variant 或用户配置定义了启用宏时才打开;同时支持HAL_ETH_MODULE_DISABLED宏进行显式关闭。这解释了为什么只有"被 variant 显式启用 ETH 的板子"才能使用本库——如果你的板子没有板载 PHY/网口,或 variant 未启用 ETH 模块,STM32Ethernet 便不适用。

如何判断自己的板子是否支持

  • 查看板卡对应的 variant 头文件(variant_*.h)或variant_generic.h中是否存在HAL_ETH_MODULE_ENABLED;
  • 查看对应PeripheralPins*.c中是否存在*** ETHERNET ***引脚段;
  • 确认板卡在 boards.txt 中登记了上述 product_line 与 variant。

满足以上条件,即可继续安装库并开始开发。

安装:通过 Arduino Library Manager 安装 LwIP 与 STM32Ethernet

两个库都可以通过 Arduino 的库管理器安装,步骤非常简单:

  1. 打开 Arduino IDE,点击Sketch(项目)菜单;
  2. 选择Include Library > Manage Libraries...(包含库 > 库管理器…);
  3. 在搜索框中输入LwIP;
  4. 依次安装LwIP和STM32Ethernet两个库。

[!NOTE] STM32Ethernet 依赖 LwIP,两者缺一不可。只安装 STM32Ethernet 而缺少 LwIP 会导致编译失败;同样,LwIP 由 stm32duino 维护的移植版本(而非其他平台的 LwIP 封装)才是与 STM32Ethernet 配套的正确依赖。

安装完成后,在 Sketch 中使用:

#include <Ethernet.h>

即可开始编写网络程序。由于 API 与 Arduino Ethernet 完全兼容,官方 Ethernet 库的经典示例(如 WebClient、ChatServer、DhcpAddressPrinter 等)都可以作为快速上手起点,这正是文档中所说"Examples allow a quickstart"的含义。

运行机制一:DHCP 自动续期,不再需要调用 maintain()

在使用 Arduino 官方 Ethernet 库时,开发者通常需要在loop()中周期调用EthernetClass::maintain()来检查并续期 DHCP 租约,否则 IP 地址可能在租约到期后失效。

而 STM32Ethernet 中不再需要调用EthernetClass::maintain(),IP 地址的 DHCP 续期由 LwIP 协议栈在后台任务中自动完成。这意味着你的loop()可以专注于业务逻辑,网络层对应用透明。

这一行为来自 LwIP 协议栈本身的架构:LwIP 是一个事件驱动、与操作系统分离的轻量级协议栈,其 DHCP 客户端、TCP 定时器(重传、保活、TIME-WAIT 等)都由协议栈内部的时间机制驱动,而不是依赖应用层轮询。

运行机制二:Idle 任务与 1ms 定时器调度(stm32_eth_scheduler)

LwIP 协议栈需要周期性的"心跳"来驱动定时器和数据接收处理。在 STM32Ethernet 中,这个Idle 任务被放在一个定时器回调里执行,回调频率为每 1ms 一次,由库函数stm32_eth_scheduler()实现。

其工作方式如下:

  • 库默认定义一个DEFAULT_ETHERNET_TIMER宏,默认值为TIM14(STM32 的 14 位通用定时器,在多数带 ETH 的变体中 TIM14_CH1 常被映射到 PA7_ALT3 或 PF9,参见 PeripheralPins.cT_F746Z(E-G)(T-Y)_F750Z8T_F756ZG(T-Y)/PeripheralPins.c#L152-L206) 中的TIM14引脚条目);
  • 该宏可以在 core variant 中重新定义(#define DEFAULT_ETHERNET_TIMER 某个TIMx),以便把定时器让给其他功能(例如与 PWM、Servo、SoftwareSerial 冲突时换用空闲的 TIM 实例);
  • 定时器中断每 1ms 触发一次,中断回调中调用stm32_eth_scheduler()来推进 LwIP 协议栈(驱动 TCP 定时器、DHCP 超时、轮询 MAC 数据接收等);
  • 此外,Ethernet::schedule()可以手动触发一次 LwIP 栈的更新,适合在需要及时推进协议栈的场景显式调用。

使用注意事项

[!IMPORTANT]

  • 由于调度在定时器中断上下文中执行,要小心不要在关闭中断(IRQ)的函数中长时间锁住系统,否则会阻塞stm32_eth_scheduler()的执行,导致协议栈超时处理不及时、DHCP 续期失败甚至网络断连;
  • 如果默认的 TIM14 被你的应用占用,务必在 variant 或编译选项里重新定义DEFAULT_ETHERNET_TIMER,而不是在多个库之间争抢同一个定时器;
  • 需要实时推进 LwIP 栈时,可调用Ethernet::schedule()执行一次更新(从文档描述看,它"performs an update of the LwIP stack")。

这一设计也回应了上文"不再需要 maintain()"的原因:既然 LwIP 的 DHCP 续期逻辑已经由 1ms 定时器定期驱动,应用层自然无需(也不应该)再手动轮询维护。

与核心 HAL 配置的关系

从前文可以看到,STM32Ethernet 能工作的前提之一是核心的 ETH HAL 模块被启用。这一点由两层配置共同决定:

  1. variant 层:带网口的板子在 variant 头文件中通过#define HAL_ETH_MODULE_ENABLED(或HAL_ETH_LEGACY_MODULE_ENABLED)启用 ETH 模块,例如 variants/STM32F4xx/F407V(E-G)T_F417V(E-G)T/variant_generic.hT_F417V(E-G)T/variant_generic.h#L218-L219)、variants/STM32F7xx/F745V(E-G)(H-T)_F746V(E-G)(H-T)_F750V8T_F756VG(H-T)/variant_generic.h(H-T)_F746V(E-G)(H-T)_F750V8T_F756VG(H-T)/variant_generic.h#L224-L225) 等;
  2. hal_conf 层:cores/arduino/stm32/stm32yyxx_hal_conf.h 统一将HAL_ETH_MODULE_DISABLED之外的场景处理为允许 ETH 模块,即"默认未禁用即可启用"。

因此,如果你想在自己的定制板卡上使用 STM32Ethernet,需要同步做三件事:在 variant 中启用HAL_ETH_MODULE_ENABLED、提供正确的 ETH 引脚映射(PeripheralPins.c的*** ETHERNET ***段)、并确认板载 PHY 的 RMII 连接与时钟(REF_CLK/MDC/MDIO)配置正确。

快速验证流程

拿到一块支持板(如 NUCLEO-F429ZI)后,可按以下顺序验证整个链路:

  1. 在 Arduino IDE 中安装 STM32 内核与本库 + LwIP;
  2. 选择对应板卡(Tools > Board 中选择 NUCLEO-F429ZI);
  3. 打开一个基于EthernetClient的官方示例(如 WebClient),将网线接入板载 RJ45 口;
  4. 编译上传后,观察串口输出是否成功通过 DHCP 获取 IP 并完成 HTTP 请求;
  5. 若网络长时间无响应,优先检查:
    • DEFAULT_ETHERNET_TIMER是否被其他库占用;
    • 应用代码中是否存在过长的临界区/关中断段阻塞了 1ms 调度;
    • PHY 与 RMII 引脚连接是否正确。

总结

STM32Ethernet 让带板载以太网的 STM32 开发板能够以 Arduino Ethernet 的成熟 API 接入网络,底层由 LwIP 协议栈驱动。它的核心设计要点可以归纳为:

要点说明
兼容性与 Arduino Ethernet 库 API 完全兼容
前置依赖必须同时安装 LwIP 与 STM32Ethernet
硬件前提板载 Ethernet 控制器(如 NUCLEO-F429ZI、STM32F746G-DISCOVERY),variant 中启用 ETH 模块
DHCP 续期由 LwIP 后台自动完成,无需调用EthernetClass::maintain()
协议栈调度Idle 任务在定时器回调中每 1ms 执行一次stm32_eth_scheduler()
定时器选择默认DEFAULT_ETHERNET_TIMER为TIM14,可在 core variant 中重新定义
手动推进需要时调用Ethernet::schedule()更新 LwIP 栈
关键约束避免在关中断的函数中长时间停留,防止协议栈得不到调度

对于刚接触 STM32 联网开发的读者,建议以 docs/libraries/index.md 中关于 STM32Ethernet 与 LwIP 的说明为入口,结合本文的调度机制理解,再对照 boards.txt 中的板卡配置与对应 variant 的 PeripheralPins.cT_F429ZET_F429Z(G-I)(T-Y)_F437Z(G-I)T_F439Z(G-I)(T-Y)/PeripheralPins_NUCLEO_F4x9ZI.c#L370-L396) 源码,即可快速定位问题并完成联网开发。

  • 嵌入式
  • 固件
  • 驱动开发
  • 硬件开发

【免费下载链接】Arduino_Core_STM32

STM32 core support for Arduino

项目地址:https://gitcode.com/gh_mirrors/ar/Arduino_Core_STM32
点击查看免费下载

相关推荐

上一篇:揭秘全球首个网络安全大模型:SecGPT如何重塑AI驱动的安全防护体系
下一篇:从零开始掌握gsplat:CUDA加速的高斯溅射渲染实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询