PLC与FPGA协同工作的Modbus通信实现方案
在产线设备中,PLC常作为主控单元负责工艺流程,FPGA作为高速算法加速/多路采集前端。两者之间通过Modbus RTU(RS485)或 Modbus TCP(以太网)互通,是成本与开发难度最平衡的协同方案。本文以西门子S7‑1200 PLC + Xilinx Artix‑7 FPGA(UART+FreeModbus)为例,讲清完整实现链路。
一、系统架构与协议选型
[S7‑1200 PLC]
│ Modbus RTU @ 115200,8,N,1 (RS485端口 CM1241)
▼
[Artix‑7 FPGA]
├─ UART → FreeModbus Slave (保持寄存器映射)
└─ 用户逻辑:滤波/位置闭环/高速计数
• Modbus RTU:适合中低速、点对点或总线型多从站(≤32节点),接线简单
• Modbus TCP:若FPGA带以太网PHY(如Zynq PS侧),可改用TCP,PLC侧用MB_CLIENT功能块
- 寄存器规划:Holding Registers (0x03/0x10) 用于PLC←→FPGA参数/状态交换
二、FPGA侧:FreeModbusSlave移植与寄存器映射
1. 硬件连接
• FPGA UART通过 MAX3485 转 RS485,A/B 接PLC CM1241 的 A/B
• 120Ω终端电阻在总线两端(PLC侧与最远FPGA侧)
2. FreeModbus移植要点(portserial.c / porttimer.c)
// portserial.c 关键回调
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
if( xRxEnable ) HAL_UART_Receive_IT(&huart1,&rx_byte,1);
if( xTxEnable ) RS485_DE_H(); else RS485_DE_L();
}
3. 保持寄存器回调(用户需实现)
// 假设 usRegHoldingBuf[100] 为FPGA内部映射数组
eMBErrorCode eMBRegHoldingCB( UCHAR *pucRegBuffer,
USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
int idx = usAddress - 1; // Modbus地址从1开始
if( idx<0 || idx+usNRegs>100 ) return MB_ENOREG;
if( eMode == MB_REG_READ )
for(int i=0;i<usNRegs;i++)
xMBSetWord( pucRegBuffer+i*2, usRegHoldingBuf[idx+i] );
else // MB_REG_WRITE
for(int i=0;i<usNRegs;i++)
usRegHoldingBuf[idx+i] = xMBGetWord( pucRegBuffer+i*2 );
return MB_ENOERR;
}
映射示例:
• HR[0] – 控制字(bit0=启动滤波 bit1=清错误)
• HR[1..2] – 目标位置(32位,分高低字)
• HR[10] – 实际位置反馈
• HR[20] – 错误码
三、PLC侧:S7‑1200 Modbus Master配置
1. 硬件与指令
• 插入 CM 1241 RS485 模块,设端口参数 115200, 8, N, 1
- 调用库 Modbus_Master(MB_CLIENT 用于TCP)功能块
2. 功能块示例(写控制字+目标位置)
"MB_Master_DB"(REQ := xStartWrite,
MB_ADDR:= 1, // FPGA从站地址
MODE := 0, // 0=写多个保持寄存器
DATA_ADDR := 40001, // Holding Register 0 (PLC地址表示法)
DATA_LEN := 3, // 控制字 + 位置低 + 位置高
DATA_PTR := P#DB10.DBX0.0 WORD 3,
DONE => xDone,
ERROR => xErr,
STATUS => wStatus);
对应读取反馈:
"MB_Master_DB"(REQ:=xStartRead,
MB_ADDR:=1,
MODE:=1, // 1=读保持寄存器
DATA_ADDR:=40011, // HR[10]
DATA_LEN:=2,
DATA_PTR:=P#DB10.DBX6.0 WORD 2,
...);
3. 轮询与超时
建议主循环中以 200ms周期轮询读反馈,写指令仅在参数变更或启动命令时触发,避免总线冲突。
四、调试与故障排查
现象 排查点
PLC报 80C8 (slave not responding) 检查A/B是否反接、终端电阻、波特率一致
FPGA收到帧但回帧错误 FreeModbus CRC计算错或UART中断丢失 → 打开 MB_FUNC_DEBUG 打印十六进制
写HR值FPGA不响应 确认 eMBRegHoldingCB 中地址偏移 usAddress-1 正确,且HR数组足够大
偶发帧丢失(多从站) 降低波特率(例9600→19200)或加总线空闲延迟(T3.5字符)
TCP模式无法连从站 确认FPGA IP/Port(502)、防火墙关、ARP表有MAC
五、扩展:Modbus TCP + Zynq PS侧
若用Zynq,可在PS端运行 lwIP + FreeModbus TCP,PL逻辑通过BRAM与PS共享保持寄存器:
// PS侧应用层
xMBTCPAccept( sock );
eMBPoll();
// 在 eMBRegHoldingCB 中读写 ps_shared_bram[]
PLC侧改用 MB_CLIENT 指向 FPGA IP:502,其余寄存器规划不变。
六、结语
PLC与FPGA协同的Modbus实现可总结为三点:① 规划好保持寄存器地址与含义(控制/参数/反馈/状态)→ ② FPGA跑FreeModbusSlave并实现eMBRegHoldingCB映射 → ③ PLC用Modbus_Master/MB_CLIENT按周期读写。该方案成本低、兼容性强,且便于后期扩展多FPGA从站或切换为Modbus TCP。





