用STM32+LAN9252的etherCAT 从站实现传感器数据采集

STM32 + LAN9252 EtherCAT 从站实现传感器数据采集

本文提供完整可落地的工程方案,以 STM32F407(通用款)+ LAN9252 为例,实现传感器数据采集并通过 EtherCAT 上报,包含硬件接线、核心代码、TwinCAT 配置全流程,新手可直接复刻。

一、方案整体设计

1. 核心架构

2. 关键选型(通用适配)

  • STM32:F407VET6(SPI 接口、ADC/DMA、足够 GPIO),其他型号(F1/F7/H7)仅需修改底层驱动
  • LAN9252:核心 ESC,SPI 通信(最高 30MHz),双 PHY 冗余
  • 传感器类型:支持模拟量(4-20mA/0-10V)、数字量(DI/DO)、串口传感器(如 Modbus)
  • EtherCAT 协议:基于 Beckhoff SSC(Standard Slave Controller)标准,兼容所有主站

二、硬件接线(最简必接)

STM32 引脚 LAN9252 引脚 功能说明
PA4 SCS# SPI 片选(低有效)
PA5 SCK SPI 时钟
PA6 SO/SIO1 SPI 主机输入(从机输出)
PA7 SI/SIO0 SPI 主机输出(从机输入)
PB0 IRQ 中断(可选,下降沿触发)
NRST RST# 硬件复位(低有效)
3.3V VDD33 供电(需稳压,纹波 < 100mV)
GND GND 共地
(可选) LED[0/1] 状态指示灯

传感器接线示例

  • 4-20mA 模拟量:传感器→电流转电压模块(如 ACS712)→STM32 ADC 引脚(PA0)
  • 数字量传感器:传感器→光耦隔离→STM32 GPIO(PB1)

三、软件实现(完整代码)

1. 前置准备

  • 安装 STM32CubeMX(生成底层代码)
  • 下载 Beckhoff SSC Tool(生成 EtherCAT 从站代码)
  • 安装 TwinCAT3(主站调试)
  • 依赖库:STM32 HAL 库、LAN9252 SPI 驱动、SSC 从站协议栈

2. 核心代码(分模块)

模块 1:LAN9252 SPI 底层驱动(lan9252_spi.c)

复制代码
#include "lan9252_spi.h"
#include "stm32f4xx_hal.h"

#define LAN9252_SPI hspi1
#define LAN9252_CS_PIN GPIO_PIN_4
#define LAN9252_CS_PORT GPIOA

// SPI片选控制
static void LAN9252_CS_LOW(void) {
    HAL_GPIO_WritePin(LAN9252_CS_PORT, LAN9252_CS_PIN, GPIO_PIN_RESET);
}
static void LAN9252_CS_HIGH(void) {
    HAL_GPIO_WritePin(LAN9252_CS_PORT, LAN9252_CS_PIN, GPIO_PIN_SET);
}

// 读LAN9252 ESC寄存器(32位)
uint32_t LAN9252_ReadReg(uint16_t addr) {
    uint8_t tx_buf[4] = {0x03, (addr >> 8) & 0xFF, addr & 0xFF, 0x00};
    uint8_t rx_buf[4] = {0};
    LAN9252_CS_LOW();
    HAL_SPI_TransmitReceive(&LAN9252_SPI, tx_buf, rx_buf, 4, 100);
    LAN9252_CS_HIGH();
    return (rx_buf[1] << 24) | (rx_buf[2] << 16) | (rx_buf[3] << 8) | rx_buf[0];
}

// 写LAN9252 ESC寄存器(32位)
void LAN9252_WriteReg(uint16_t addr, uint32_t data) {
    uint8_t tx_buf[4] = {0x02, (addr >> 8) & 0xFF, addr & 0xFF, 0x00};
    tx_buf[3] = (data >> 24) & 0xFF;
    tx_buf[2] = (data >> 16) & 0xFF;
    tx_buf[1] = (data >> 8) & 0xFF;
    tx_buf[0] = data & 0xFF;
    LAN9252_CS_LOW();
    HAL_SPI_Transmit(&LAN9252_SPI, tx_buf, 4, 100);
    LAN9252_CS_HIGH();
}

// LAN9252初始化
void LAN9252_Init(void) {
    // 硬件复位(拉低RST# 100us)
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_Delay(10);
    
    // 检查READY位(确认LAN9252启动完成)
    while((LAN9252_ReadReg(0x0084) & 0x01) == 0);
    
    // 初始化SyncManager(SM2=TxPDO,SM3=RxPDO)
    LAN9252_WriteReg(0x0800, 0x00000001); // SM0: 邮箱输出
    LAN9252_WriteReg(0x0810, 0x00000002); // SM1: 邮箱输入
    LAN9252_WriteReg(0x0820, 0x00010003); // SM2: TxPDO(传感器数据上报)
    LAN9252_WriteReg(0x0830, 0x00010004); // SM3: RxPDO(主站控制指令)
}

模块 2:传感器数据采集(sensor.c)

复制代码
#include "sensor.h"
#include "stm32f4xx_hal.h"

ADC_HandleTypeDef hadc1;

// ADC初始化(采集4-20mA传感器,对应0-3.3V)
void Sensor_ADC_Init(void) {
    ADC_ChannelConfTypeDef sConfig = {0};
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = ENABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc1);
    
    sConfig.Channel = ADC_CHANNEL_0; // PA0
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
    
    // 启动ADC连续采集
    HAL_ADC_Start(&hadc1);
}

// 读取模拟量传感器数据(4-20mA转实际值,示例:温度0-100℃)
float Sensor_Read_Analog(void) {
    uint32_t adc_value = HAL_ADC_GetValue(&hadc1);
    // 4-20mA对应ADC值:524(4mA)~2620(20mA),转0-100℃
    float current = (adc_value - 524) / (2620 - 524) * 16 + 4; // 计算电流
    float temp = (current - 4) / 16 * 100; // 电流转温度
    return temp;
}

// 读取数字量传感器(如接近开关)
uint8_t Sensor_Read_Digital(void) {
    return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); // PB1
}

模块 3:EtherCAT PDO 数据交互(ecat_slave.c)

复制代码
#include "ecat_slave.h"
#include "lan9252_spi.h"
#include "sensor.h"

// PDO数据结构体(与TwinCAT配置一致)
typedef struct {
    float temp;       // 温度值(TxPDO,从站→主站)
    uint8_t di_state; // 数字量状态(TxPDO)
    uint8_t do_ctrl;  // 数字量控制(RxPDO,主站→从站)
} PDO_Data_t;

PDO_Data_t pdo_data = {0};

// 更新TxPDO(传感器数据写入LAN9252 PDO缓存)
void ECAT_Update_TxPDO(void) {
    // 读取传感器数据
    pdo_data.temp = Sensor_Read_Analog();
    pdo_data.di_state = Sensor_Read_Digital();
    
    // 将数据写入LAN9252的TxPDO缓存(地址0x1000)
    uint32_t temp_int = *(uint32_t*)&pdo_data.temp; // 浮点转32位整数
    LAN9252_WriteReg(0x1000, temp_int);            // 温度值
    LAN9252_WriteReg(0x1004, pdo_data.di_state);   // 数字量状态
}

// 读取RxPDO(主站控制指令)
void ECAT_Read_RxPDO(void) {
    pdo_data.do_ctrl = LAN9252_ReadReg(0x1008) & 0xFF;
    // 根据主站指令控制DO(示例:PB2)
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, pdo_data.do_ctrl ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

// EtherCAT主循环
void ECAT_Main_Loop(void) {
    // 检查AL状态(0x0130,OP状态=0x08)
    uint32_t al_state = LAN9252_ReadReg(0x0130);
    if(al_state == 0x08) { // OP状态才交互数据
        ECAT_Update_TxPDO();
        ECAT_Read_RxPDO();
    }
}

模块 4:主函数(main.c)

复制代码
#include "main.h"
#include "lan9252_spi.h"
#include "sensor.h"
#include "ecat_slave.h"

SPI_HandleTypeDef hspi1;

int main(void) {
    // 初始化HAL库
    HAL_Init();
    // 系统时钟配置(168MHz)
    SystemClock_Config();
    // 初始化GPIO、SPI、ADC
    MX_GPIO_Init();
    MX_SPI1_Init();
    Sensor_ADC_Init();
    // 初始化LAN9252
    LAN9252_Init();
    
    // 主循环
    while (1) {
        ECAT_Main_Loop(); // EtherCAT数据交互
        HAL_Delay(1);     // 1ms周期(可根据传感器调整)
    }
}

3. SSC Tool 配置(生成 ESI 文件)

  1. 打开 SSC Tool,新建工程,选择 LAN9252 模板;
  2. 配置 PDO 映射:
    • TxPDO(从站→主站):0x1A00,包含温度(32 位浮点)、DI 状态(8 位);
    • RxPDO(主站→从站):0x1600,包含 DO 控制(8 位);
  3. 生成 ESI 文件(LAN9252_Sensor.xml)和从站代码,集成到 STM32 工程。

四、TwinCAT3 主站配置(调试)

1. 导入 ESI 文件

  • 打开 TwinCAT3 → 右键 "EtherCAT" → "Import ESI" → 选择生成的LAN9252_Sensor.xml

2. 扫描从站

  • 连接 EtherCAT 网线(LAN9252 的 ETH0/ETH1)到 PC/TwinCAT 主站;
  • 右键 "EtherCAT Master" → "Scan Devices" → 识别到 LAN9252 从站;

3. 配置 PDO 映射

  • 双击从站 → "Process Data" → 勾选 TxPDO/RxPDO;
  • 映射变量:
    • TxPDO:temp(REAL)、di_state(BOOL);
    • RxPDO:do_ctrl(BOOL);

4. 运行调试

  • 切换到 "Run" 模式,将从站状态从 Init→PreOp→SafeOp→OP;
  • 打开 "Watch" 窗口,实时监控传感器数据(温度、DI 状态),下发 DO 控制指令。

五、关键注意事项

  1. SPI 通信稳定性
    • SPI 时钟频率建议≤10MHz(新手),避免数据丢包;
    • CS 引脚需硬件上拉,减少干扰;
  2. 传感器校准
    • 4-20mA 传感器需校准零点(4mA 对应 ADC 值)和满量程(20mA 对应 ADC 值);
  3. EtherCAT 状态机
    • 确保从站能正常进入 OP 状态,若卡在 PreOp,检查 ESI 文件或 SM 配置;
  4. 电源纹波
    • LAN9252 对电源纹波敏感,需加 100nF+10uF 去耦电容。

六、总结

  1. 核心流程:STM32 采集传感器数据 → 写入 LAN9252 的 TxPDO 缓存 → EtherCAT 主站(TwinCAT)读取数据,同时主站可下发控制指令到 RxPDO;
  2. 关键代码:LAN9252 的 SPI 读写是基础,PDO 数据映射需与 TwinCAT 配置严格一致;
  3. 调试重点:先确保 LAN9252 能被 TwinCAT 识别,再逐步验证传感器采集和 PDO 交互
相关推荐
G***技1 小时前
物流自动化迈入边缘智能,杰和科技AR707成为关键引擎
人工智能·嵌入式硬件·机器人·边缘计算盒
雨洛lhw1 小时前
压控晶振学习笔记
嵌入式硬件·晶振
2501_918126912 小时前
学习所有用c语言定义stm32的语句
c语言·stm32·嵌入式硬件·学习·个人开发
普中科技2 小时前
【普中 51-Ai8051 开发攻略】-- 第 3 章 Ai8051U 介绍
单片机·嵌入式硬件·开发板·普中科技·ai8051u·aicube
隔壁大炮2 小时前
PID控制结构&角度环实现直立
stm32·嵌入式·硬件·pid·平衡车·江协科技
羽获飞2 小时前
从零开始学嵌入式之STM32——29.通用定时器-输入捕获模式测量信号的周期和频率
stm32·单片机·嵌入式硬件
421!2 小时前
ESP32学习笔记之GPIO
开发语言·笔记·单片机·嵌入式硬件·学习·算法·fpga开发
惶了个恐3 小时前
嵌入式硬件第二弹——51单片机(2)
单片机·嵌入式硬件·51单片机
易水寒陈3 小时前
使用vscode开发stm32
ide·vscode·stm32