在工业自动化领域,Modbus TCP协议因其简单可靠的特点,已成为设备间通信的事实标准。而STM32F107作为一款带有以太网控制器的Cortex-M3内核微控制器,搭配DM9161物理层芯片,能够以极低成本构建工业级通信节点。
这个项目最吸引我的地方在于:它完美解决了传统工业现场的三个痛点。首先,相比RS485总线,以太网布线更灵活且传输距离不受限;其次,Modbus TCP协议栈的开销比Modbus RTU更小;最重要的是,整套方案BOM成本可以控制在50元以内,这对批量部署的设备厂商极具吸引力。
STM32F107VCT6是这个项目的核心大脑,选择它主要基于三点:
实际选型时要注意:STM32F107有LQFP100和LQFP144两种封装,建议选择后者以便保留更多调试接口。
DM9161AEP作为PHY芯片,其硬件设计有几个关键点:
c复制// 硬件初始化示例(部分代码)
void ETH_GPIO_Config(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 配置RMII接口引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; // TXD0/TXD1
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 时钟使能配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
}
使用LwIP作为TCP/IP协议栈时,需要特别注意以下移植点:
c复制#define MEM_SIZE (16*1024) // 根据实际需求调整
#define PBUF_POOL_SIZE 16 // 建议不小于8
c复制err_t dm9161_output(struct netif *netif, struct pbuf *p) {
// 数据发送函数实现
ETH_DMATxDescList[tx_index].Buffer1Addr = (uint32_t)p->payload;
ETH_DMATxDescList[tx_index].ControlBufferSize = p->len | ETH_DMATxDesc_TIC;
ETH_DMATxDescList[tx_index].Status = ETH_DMATxDesc_OWN;
// 触发DMA传输...
}
Modbus TCP与RTU版本的主要差异在于:
典型数据帧处理流程:
c复制IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_256); // 约1.6s超时
IWDG_SetReload(0xFFF);
IWDG_Enable();
问题1:PHY无法建立链路
问题2:TCP连接频繁断开
问题3:Modbus响应超时
在72MHz主频下实测性能表现:
| 测试项 | 数值 |
|---|---|
| TCP连接建立时间 | <200ms |
| 寄存器读取延迟 | 3-5ms |
| 最大并发连接数 | 8 |
| 数据传输速率 | 800KB/s |
测试环境:
这套方案经过验证可应用于:
一个实用的技巧是将常用功能码做成函数指针数组,大幅提升协议处理效率:
c复制typedef void (*modbus_handler)(uint8_t*, uint16_t);
const modbus_handler handlers[] = {
NULL, // 0x00
read_coils, // 0x01
read_discrete_inputs, // 0x02
read_holding_registers, // 0x03
// ...其他功能码处理函数
};
实际部署时发现,在电磁环境复杂的车间,给RJ45接口加装磁环能有效降低误码率。另外建议将TCP Keepalive间隔设置为30秒,可以更快检测断线情况。