1、在库管理器中添加ModbusFB库
主要使用下面的FB功能块实现对从站的通讯参数配置
访问功能码支持通过下表配置 下面结构体也是配置参数表需要使用到的,程序例子中会详细说明使用方法
2、下例配置实现了对从站定义可被访问的数据区域以及大小和可支持的功能码 2.1FB功能块实例化以及相关变量定义 VAR serverTCP:ModbusFB.ServerTCP; xEnable: BOOL:=TRUE; aDiscreteInputsMemory : ARRAY [0..9] OF BOOL; aCoilsMemory1 : ARRAY [0..4] OF BOOL; aCoilsMemory2 : ARRAY [0..4] OF BOOL; aInputRegistersMemory1 : ARRAY [0..6] OF UINT; aInputRegistersMemory2 : ARRAY [0..2] OF UINT; aHoldingRegistersMemory : ARRAY [0..6] OF UINT; END_VAR VAR CONSTANT //配置从站支持的功能码(只有配置为TRUE的功能码主站才可以通过相应功能码访问从站) fcsSupported : ModbusFB.SupportedFcs := ( ReadCoils:=TRUE, ReadDiscreteInputs:=TRUE, ReadHoldingRegisters:=TRUE, ReadInputRegisters:=TRUE, WriteSingleCoil:=TRUE, WriteSingleRegister:=TRUE, WriteMultipleCoils:=TRUE, WriteMultipleRegisters:=TRUE ); // 数据模型配置,通俗讲就是把从站的线圈、离散输入、输入寄存器、保持寄存器,分成多少段,分别映射到 PLC 的哪些变量里 tableDefs : ModbusFB.TableDefinitions := ( //// 离散输入(Discrete Inputs,只读位) tableDiscreteInputs := ( uiNumSections := 1,// 配置1个数据段 pSections := ADR(aDiscreteInputsSections[0])// 段数组的起始地址 ), // 线圈(Coils,可读写位) tableCoils := ( uiNumSections := 2,// 配置2个数据段 pSections := ADR(aCoilsSections[0])// 段数组的起始地址 ), // 输入寄存器(Input Registers,只读16位寄存器) tableInputRegisters := ( uiNumSections := 3,// 配置3个数据段 pSections := ADR(aInputRegistersSections[0]) ), // 保持寄存器(Holding Registers,可读写16位寄存器) tableHoldingRegisters := ( uiNumSections := 2, // 配置2个数据段 pSections := ADR(aHoldingRegistersSections[0]) ) ); //Modbus 数据模型(Data Model) 的数据段(TableSection)初始化代码,是实现 Modbus 自动映射的核心配置 aDiscreteInputsSections : ARRAY [0..0] OF ModbusFB.TableSection := [ // 作用:把 Modbus 从站的离散输入地址 0-9,自动映射到 PLC 变量 aDiscreteInputsMemory 数组里 ( uiStart := 0,// Modbus 起始地址 0 uiNumDataItems := 10,// 映射 10 个离散输 pStartAddr := ADR(aDiscreteInputsMemory[0]),// 映射到PLC的数组 uiDataItemSize := 8// 位宽8位(按字节映射) ) ]; //把 Modbus 线圈分成两段映射:0-4 映射到 aCoilsMemory1,5-9 映射到 aCoilsMemory2,这种分段配置,可以把不连续的 Modbus 地址,分别映射到 PLC 里不同的变量或数组 aCoilsSections : ARRAY [0..1] OF ModbusFB.TableSection := [ // "coils" 0..4 ( uiStart := 0, uiNumDataItems := 5, pStartAddr := ADR(aCoilsMemory1[0]), uiDataItemSize := 8 ), // "coils" 5..9 ( uiStart := 5, uiNumDataItems := 5, pStartAddr := ADR(aCoilsMemory2[0]), uiDataItemSize := 8 ) ]; //把 Modbus 输入寄存器的 0-2、5-8、10-12 三个不连续地址段,分别映射到 PLC 的不同数组位置。 aInputRegistersSections : ARRAY [0..2] OF ModbusFB.TableSection := [ // 段1:地址 0..2 → 映射到 aInputRegistersMemory1[0] ( uiStart := 0, uiNumDataItems := 3, pStartAddr := ADR(aInputRegistersMemory1[0]), uiDataItemSize := 16 ), // 段2:地址 5..8 → 映射到 aInputRegistersMemory1[3](同一数组的不同位置) ( uiStart := 5, uiNumDataItems := 4, pStartAddr := ADR(aInputRegistersMemory1[3]), uiDataItemSize := 16 ), // 段3:地址 10..12 → 映射到 aInputRegistersMemory2[0](另一个数组) ( uiStart := 10, uiNumDataItems := 3, pStartAddr := ADR(aInputRegistersMemory2[0]), uiDataItemSize := 16 ) ]; //0-6 映射到保持寄存器专用数组,7-9 复用输入寄存器数组,适合数据需要跨表同步的场景 //把保持寄存器 7-9 直接映射到了 aInputRegistersMemory2,实现了 “输入寄存器和保持寄存器的数据共享”,一次读取就能同时更新两个变量。 aHoldingRegistersSections : ARRAY [0..1] OF ModbusFB.TableSection := [ // 段1:地址 0..6 → 映射到 aHoldingRegistersMemory[0] ( uiStart := 0, uiNumDataItems := 6, pStartAddr := ADR(aHoldingRegistersMemory[0]), uiDataItemSize := 16 ), // 段2:地址 7..9 → 直接映射到 aInputRegistersMemory2[0] ( uiStart := 7, uiNumDataItems := 3, pStartAddr := ADR(aInputRegistersMemory2[0]), uiDataItemSize := 16 ) ]; END_VAR 2.2程序实现 // 配置tcpServer serverTCP( xEnable:= xEnable, fcsSupported:= fcsSupported, dataModel:=tableDefs , wsInterfaceName:="eth0" , uiPort:=502 , ); //可查看读写交换次数 IF serverTCP.xWriteRequest THEN aInputRegistersMemory2[1] := aInputRegistersMemory2[1] + 1; END_IF
|