我有一个在TwinCAT 3中读写Modbus数据的程序。任务周期设置为13 ms。通过观察 Wireshark 日志,我发现读取数据的周期约为 25 ms,而写入数据的周期约为 50 ms。
IF NOT fbmbreadregs.bBusy THEN
fbMBReadRegs(
sIPAddr:= '192.168.2.20',
nTCPPort:= 1504,
nUnitID:= 16#FF,
nQuantity:= 14,
nMBAddr:= 0,
cbLength:= SIZEOF(st_ModbusRead),
pDestAddr:= ADR(st_ModbusRead),
bExecute:= TRUE,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
fbBasicPID(
fSetpointValue:= 50,
fActualValue:= st_ModbusRead.SOC,
bReset:= FALSE,
fCtrlCycleTime:=0.013 ,
fKp:= 0.00005,
fTn:= 1,
fTv:= 0,
fTd:= 0,
fCtrlOutput=> nFout,
nErrorStatus=>);
nPref:=(1/0.001)*(50-nFout);
ELSE
fbMBReadRegs(bExecute:= FALSE);
END_IF
IF NOT fbMBWriteRegs.bBusy THEN
arrPQ[0]:=REAL_TO_WORD(ABS(nPref));
fbMBWriteRegs(
sIPAddr:= '192.168.2.20',
nTCPPort:= 1504,
nUnitID:= 16#FF,
nQuantity:= 5,
nMBAddr:= 16#0014,
cbLength:= SIZEOF(arrPQ),
pSrcAddr:= ADR(arrPQ),
bExecute:= TRUE,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> );
ELSE
fbMBWriteRegs(bExecute:=FALSE);
END_IF
为什么这些时期不同?如何实现读和写操作的周期相同?
您可以通过同步 fbMBWriteRegs 和 fbMBReadRegs 的 bExecute 输入来实现此目的:
fbTON100ms(PT := T#100MS);
IF bRedgeEvery100ms THEN
bRedgeEvery100ms := FALSE;
fbTON100ms.IN := TRUE;
END_IF;
IF fbTON100ms.Q AND (NOT fbmbreadregs.bBusy) AND (NOT fbMBWriteRegs.bBusy)
THEN
fbTON100ms.IN := FALSE;
bRedgeEvery100ms := TRUE;
END_IF
fbMBReadRegs(
sIPAddr:= '192.168.2.20',
nTCPPort:= 1504,
nUnitID:= 16#FF,
nQuantity:= 14,
nMBAddr:= 0,
cbLength:= SIZEOF(st_ModbusRead),
pDestAddr:= ADR(st_ModbusRead),
bExecute:= bRedgeEvery100ms,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
fbMBWriteRegs(
sIPAddr:= '192.168.2.20',
nTCPPort:= 1504,
nUnitID:= 16#FF,
nQuantity:= 5,
nMBAddr:= 16#0014,
cbLength:= SIZEOF(arrPQ),
pSrcAddr:= ADR(arrPQ),
bExecute:= bRedgeEvery100ms,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> );
但据我所知,TwinCat 上的 modbus 通信使用单独的 Windows 进程与 PLC 运行时异步通信 - 您无法 100% 控制 modbus 电报的执行。
可能适用于某些用例的替代选项 - 让 Modbus 通信保持原样,但创建另一对变量,如 st_ModbusReadSync 和 arrPQSync 并同步更新它们,如
IF bRedgeEvery100ms THEN
st_ModbusReadSync := st_ModbusRead;
arrPQ := arrPQSync;
END_IF
另外,将 fbBasicPID 放入 IF NOT fbmbreadregs.bBusy THEN 对我来说似乎是个坏主意。我没有对 PID 调节器的精确解释的经验,但通常它们应该在每个周期中不间断地执行。