一、方案整体设计思路
要实现基于 STM32+LAN9252 的 EtherCAT 从机数据采集系统,核心逻辑是:
-
硬件层:STM32 作为主控,负责数据采集(模拟量 / 数字量)、EtherCAT 协议解析;LAN9252 作为 EtherCAT 物理层(PHY)+ 链路层芯片,处理以太网硬件收发;
-
协议层:移植 EtherCAT 从站协议栈(如 SOEM slave/EC-Engineer),实现 EtherCAT 从机状态机、PDO 映射、邮箱通信;
-
应用层:STM32 采集传感器数据(如 ADC、GPIO),通过 EtherCAT PDO 实时上传给主站,响应主站指令。
graph TD
A[EtherCAT主站] -->|以太网| B[LAN9252(EtherCAT PHY)]
B -->|SPI/并行| C[STM32主控]
C --> D[数据采集模块]
D --> D1[ADC模拟量采集]
D --> D2[GPIO数字量采集]
C --> E[EtherCAT从站协议栈]
E --> F[PDO数据映射/传输]
二、硬件选型与连接
1. 核心器件
| 器件 | 选型建议 | 理由 |
|---|---|---|
| STM32 | STM32F407/STM32H743 | 主频高(168MHz+/400MHz),有足够资源跑 EtherCAT 协议栈 |
| LAN9252 | Microchip LAN9252i/9252 | 原生支持 EtherCAT,SPI / 并行接口,集成 PHY,无需额外网络变压器 |
| 采集模块 | 模拟量(ADC)/ 数字量(GPIO) | 根据需求选,如 4-20mA 采集、DI/DO |
2. 硬件连接(STM32F407 + LAN9252)
- 通信接口 :LAN9252 默认用 SPI 与 STM32 通信(推荐,接线少):
- LAN9252_SPI_SCK → STM32_SPIx_SCK(如 SPI2_SCK: PB13)
- LAN9252_SPI_MOSI → STM32_SPIx_MOSI(PB15)
- LAN9252_SPI_MISO → STM32_SPIx_MISO(PB14)
- LAN9252_SPI_CS → STM32_GPIO(PB12,片选)
- LAN9252_INT → STM32_EXTI(PA0,中断引脚,接收 LAN9252 的中断)
- 电源:LAN9252 需 3.3V 供电,STM32 核心 3.3V,模拟采集需 5V/12V(外部供电);
- 以太网口:LAN9252 的 RX+/RX-/TX+/TX - 接 RJ45 网口(带隔离变压器);
- 数据采集:STM32 ADC 通道(如 PA0-PA7)接模拟传感器,GPIO(如 PB0-PB7)接数字量输入。
三、软件实现步骤(基于 STM32CubeIDE)
1. 环境准备
- 开发工具:STM32CubeIDE(最新版)、STM32CubeMX;
- 协议栈:移植SOEM(Simple Open EtherCAT Master/Slave) 从站版本,或 Microchip 官方 LAN9252 EtherCAT 从站驱动;
- 调试工具:EtherCAT 主站软件(如倍福 Twincat 3、SOEM Master)、串口调试器、示波器。
2. 底层驱动开发
(1)LAN9252 驱动(SPI 通信)
#include "lan9252.h"
#include "spi.h"
// LAN9252寄存器读写函数
void LAN9252_WriteReg(uint16_t reg, uint32_t data) {
uint8_t tx_buf[6] = {0};
// 写命令格式:0x00 + 寄存器地址(2字节) + 数据(4字节)
tx_buf[0] = 0x00;
tx_buf[1] = (reg >> 8) & 0xFF;
tx_buf[2] = reg & 0xFF;
tx_buf[3] = (data >> 24) & 0xFF;
tx_buf[4] = (data >> 16) & 0xFF;
tx_buf[5] = (data >> 8) & 0xFF;
tx_buf[6] = data & 0xFF;
HAL_GPIO_WritePin(LAN9252_CS_GPIO_Port, LAN9252_CS_Pin, GPIO_PIN_RESET); // 片选拉低
HAL_SPI_Transmit(&hspi2, tx_buf, 7, 100); // SPI2通信
HAL_GPIO_WritePin(LAN9252_CS_GPIO_Port, LAN9252_CS_Pin, GPIO_PIN_SET); // 片选拉高
}
uint32_t LAN9252_ReadReg(uint16_t reg) {
uint8_t tx_buf[3] = {0};
uint8_t rx_buf[4] = {0};
uint32_t data = 0;
// 读命令格式:0x01 + 寄存器地址(2字节)
tx_buf[0] = 0x01;
tx_buf[1] = (reg >> 8) & 0xFF;
tx_buf[2] = reg & 0xFF;
HAL_GPIO_WritePin(LAN9252_CS_GPIO_Port, LAN9252_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, tx_buf, 3, 100); // 发送读命令
HAL_SPI_Receive(&hspi2, rx_buf, 4, 100); // 接收4字节数据
HAL_GPIO_WritePin(LAN9252_CS_GPIO_Port, LAN9252_CS_Pin, GPIO_PIN_SET);
data = (rx_buf[0] << 24) | (rx_buf[1] << 16) | (rx_buf[2] << 8) | rx_buf[3];
return data;
}
// LAN9252初始化(配置EtherCAT模式、PHY)
void LAN9252_Init(void) {
// 软复位LAN9252
LAN9252_WriteReg(LAN9252_REG_RESET, 0x00000001);
HAL_Delay(100);
// 配置为EtherCAT从站模式,启用SPI接口
LAN9252_WriteReg(LAN9252_REG_MODE, 0x00000002);
// 启用PHY,自动协商速率
LAN9252_WriteReg(LAN9252_REG_PHY_CTRL, 0x00000001);
}
(2)数据采集驱动(ADC+GPIO)
#include "adc.h"
#include "gpio.h"
// 模拟量采集(单次转换)
float ADC_Read_Channel(uint32_t channel) {
ADC_ChannelConfTypeDef sConfig = {0};
// 配置ADC通道
sConfig.Channel = channel;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Error_Handler();
}
// 启动ADC转换并读取值
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) {
uint32_t adc_val = HAL_ADC_GetValue(&hadc1);
// 转换为电压值(3.3V参考,12位ADC)
float voltage = (adc_val * 3.3f) / 4095.0f;
return voltage;
}
return 0.0f;
}
// 数字量采集(GPIO输入)
uint8_t GPIO_Read_DI(uint16_t pin) {
return HAL_GPIO_ReadPin(GPIOA, pin);
}
// 数据采集主函数(采集4路模拟量+4路数字量)
void DataAcquisition(uint32_t *analog_data, uint8_t *digital_data) {
// 采集4路模拟量(ADC1_CH0~CH3)
analog_data[0] = (uint32_t)(ADC_Read_Channel(ADC_CHANNEL_0) * 1000); // 转换为mV,便于传输
analog_data[1] = (uint32_t)(ADC_Read_Channel(ADC_CHANNEL_1) * 1000);
analog_data[2] = (uint32_t)(ADC_Read_Channel(ADC_CHANNEL_2) * 1000);
analog_data[3] = (uint32_t)(ADC_Read_Channel(ADC_CHANNEL_3) * 1000);
// 采集4路数字量(GPIOA_PIN4~PIN7)
digital_data[0] = GPIO_Read_DI(GPIO_PIN_4);
digital_data[1] = GPIO_Read_DI(GPIO_PIN_5);
digital_data[2] = GPIO_Read_DI(GPIO_PIN_6);
digital_data[3] = GPIO_Read_DI(GPIO_PIN_7);
}
3. EtherCAT 从站协议栈移植(SOEM Slave)
SOEM(Simple Open EtherCAT Master)是开源 EtherCAT 协议栈,支持从站模式,核心步骤:
-
移植 SOEM 从站代码:将 SOEM 的 slave 目录下的文件加入工程,适配 STM32 的时钟、中断;
-
配置 PDO 映射:定义过程数据对象(PDO),将采集的模拟量 / 数字量映射到 PDO 通信区:
// PDO映射定义(从站字典)
typedef struct {
// 输出PDO(主站→从站,如控制指令)
uint8_t control_cmd; // 1字节控制命令
// 输入PDO(从站→主站,采集数据)
uint32_t analog_data[4]; // 4路模拟量(mV)
uint8_t digital_data[4]; // 4路数字量
} EtherCAT_Slave_PDO;EtherCAT_Slave_PDO ec_pdo; // PDO通信结构体
// EtherCAT从站初始化
void EtherCAT_Slave_Init(void) {
// 初始化SOEM协议栈
ec_slave_init(&hspi2, LAN9252_INT_Pin);
// 配置PDO映射表
ec_pdo_map_init();
// 启动EtherCAT通信
ec_slave_start();
}// EtherCAT数据更新(主循环调用)
void EtherCAT_UpdateData(void) {
// 1. 读取主站下发的控制指令(输出PDO)
ec_pdo.control_cmd = ec_slave_read_output(0, 0, 1);// 2. 采集数据并写入输入PDO DataAcquisition(ec_pdo.analog_data, ec_pdo.digital_data); // 3. 将输入PDO数据发送给主站 ec_slave_write_input(0, 0, sizeof(ec_pdo.analog_data) + sizeof(ec_pdo.digital_data), &ec_pdo.analog_data);}
-
主程序入口
int main(void) {
// 1. 硬件初始化
HAL_Init();
SystemClock_Config(); // 配置STM32时钟(F407→168MHz)
MX_GPIO_Init();
MX_SPI2_Init();
MX_ADC1_Init();// 2. 外设初始化 LAN9252_Init(); EtherCAT_Slave_Init(); // 3. 主循环 while (1) { // 数据采集 + EtherCAT数据更新 EtherCAT_UpdateData(); // 处理LAN9252中断(如数据收发完成) if (HAL_GPIO_ReadPin(LAN9252_INT_GPIO_Port, LAN9252_INT_Pin) == GPIO_PIN_RESET) { LAN9252_Interrupt_Handler(); } HAL_Delay(10); // 10ms采集一次(可根据需求调整) }}
四、关键调试步骤
- 硬件调试 :
- 用万用表检查 LAN9252 供电、SPI 接线是否正确;
- 用示波器观察 LAN9252_INT 引脚,确认有中断信号(EtherCAT 通信时会周期性触发);
- 协议调试 :
- 用 Twincat 3 作为 EtherCAT 主站,扫描从站(需配置从站 ESC 地址与 LAN9252 匹配);
- 查看主站是否能识别从站,PDO 映射是否正确;
- 数据调试 :
- 给模拟量通道接已知电压(如 1.65V),查看主站接收的数值是否为 1650mV;
- 切换数字量输入引脚电平,验证主站接收的数字量是否同步变化。
五、注意事项
- 时钟精度:EtherCAT 对时钟要求高,STM32 需配置精准的外部晶振(25MHz),避免通信丢包;
- SPI 速率:LAN9252 的 SPI 通信速率建议≤20MHz,过高易导致数据错误;
- PDO 大小:单次 PDO 传输数据不宜过大(建议≤64 字节),保证实时性;
- 容错处理:添加通信超时、数据校验逻辑,避免采集数据异常;
- LAN9252 配置:需确保 LAN9252 工作在 EtherCAT 模式(而非普通以太网模式),否则无法解析 EtherCAT 帧。
六、工具与资源推荐
| 类型 | 资源名称 | 用途 |
|---|---|---|
| 协议栈 | SOEM(GitHub) | 开源 EtherCAT 主 / 从站协议栈 |
| 主站调试 | Twincat 3(倍福) | 专业 EtherCAT 主站软件 |
| 硬件手册 | LAN9252 Datasheet | 寄存器配置、通信时序 |
| STM32 配置 | STM32CubeMX | 快速生成底层驱动 |
| 抓包工具 | Wireshark(EtherCAT 插件) | 分析 EtherCAT 通信帧 |
总结
- 基于 STM32+LAN9252 的 EtherCAT 从机数据采集系统,核心是 "LAN9252 硬件驱动 + EtherCAT 从站协议栈 + 数据采集逻辑";
- 优先选择 STM32F4/H7 系列,移植 SOEM 协议栈实现 PDO 数据传输,保证实时性;
- 调试重点是 LAN9252 的 SPI 通信、EtherCAT 从站识别、采集数据的 PDO 映射,需结合主站工具验证。