- 嵌入式
- 固件
- 驱动开发
- 硬件开发
【免费下载链接】Arduino_Core_STM32
STM32 core support for Arduino
本文围绕 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 的库管理器安装,步骤非常简单:
- 打开 Arduino IDE,点击Sketch(项目)菜单;
- 选择Include Library > Manage Libraries...(包含库 > 库管理器…);
- 在搜索框中输入
LwIP; - 依次安装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 模块被启用。这一点由两层配置共同决定:
- 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) 等; - 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)后,可按以下顺序验证整个链路:
- 在 Arduino IDE 中安装 STM32 内核与本库 + LwIP;
- 选择对应板卡(Tools > Board 中选择 NUCLEO-F429ZI);
- 打开一个基于
EthernetClient的官方示例(如 WebClient),将网线接入板载 RJ45 口; - 编译上传后,观察串口输出是否成功通过 DHCP 获取 IP 并完成 HTTP 请求;
- 若网络长时间无响应,优先检查:
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
相关推荐
使用 PlatformIO 开发 STM32 Arduino 项目:安装配置、构建上传与调试指南(Arduino_Core_STM32)
使用 PlatformIO 开发 STM32 Arduino 项目:安装配置、构建上传与调试指南(Arduino_Core_STM32) 本篇指南面向使用 Pl
嵌入式固件驱动开发硬件开发Arduino_Core_STM32 快速上手指南:在 Arduino IDE 2 中安装、配置与烧录 STM32 板卡
Arduino_Core_STM32 快速上手指南:在 Arduino IDE 2 中安装、配置与烧录 STM32 板卡 本文以 Arduino_Core_ST
嵌入式固件驱动开发硬件开发Create React App 依赖安装指南:从模板预置依赖到自定义库的完整机制
Create React App 依赖安装指南:从模板预置依赖到自定义库的完整机制 本文围绕 Create React App 官方文档《Installing
前端开发工具CLI构建工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考