FUNCTION_BLOCK "ModbusTCP_FB" TITLE = 西门子MBTCP功能FB { S7_Optimized_Access := 'FALSE' } AUTHOR : Mars FAMILY : 功能FB NAME : '005' VERSION : 1.0 //按寄存器轮询 VAR_INPUT FirstScan : Bool; END_VAR VAR_IN_OUT Parameter : "MBTCP_Config"; Data : "MBTCP_Data"; END_VAR VAR MB_CLIENT {InstructionName := 'MB_CLIENT'; LibVersion := '6.0'} : MB_CLIENT; HRReadNumber { S7_SetPoint := 'True'} : Int; // 反馈寄存器数量 HRReadIndex { S7_SetPoint := 'True'} : Int; // 当前反馈寄存器索引 HRParNumber { S7_SetPoint := 'True'} : Int; // 参数寄存器数量 HRParIndex { S7_SetPoint := 'True'} : Int; // 当前参数寄存器索引 HRParIndexLast { S7_SetPoint := 'True'} : Int; // 上一次参数寄存器索引 HRWriteNumber { S7_SetPoint := 'True'} : Int; // 设定值寄存器数量 HRWriteIndex { S7_SetPoint := 'True'} : Int; // 当前设定值寄存器索引 HRWriteIndexLast { S7_SetPoint := 'True'} : Int; // 上一次设定值寄存器索引 HRNumber { S7_SetPoint := 'True'} : Int; // 总的寄存器数量 HRIndex { S7_SetPoint := 'True'} : Int; // 当前读写寄存器索引 HRDataStep { S7_SetPoint := 'True'} : Int; // 读写数据步序 MonitorStep { S7_SetPoint := 'True'} : Int; // 监听步 HRWriteStart { S7_SetPoint := 'True'} : Bool; // 写入改变开始写 HRParStart { S7_SetPoint := 'True'} : Bool; // 参数改变开始写 PollingReq { S7_SetPoint := 'True'} : Bool; // 寄存器轮询触发 ClientDone_P { S7_SetPoint := 'True'} : Bool; // 客户端done上升沿 PollingInitialize { S7_SetPoint := 'True'} : Bool; // 寄存器轮询初始化 PollingFullAddr { S7_SetPoint := 'True'} : Bool; // 完整寄存器读取 PollingStart { S7_SetPoint := 'True'} : Bool; // 寄存器轮询开始 PollingEnd { S7_SetPoint := 'True'} : Bool; // 寄存器轮询结束 DisConnect { S7_SetPoint := 'True'} : Bool; MB_Mode { S7_SetPoint := 'True'} : USInt; MB_Data_Addr { S7_SetPoint := 'True'} : UDInt; MB_Data_Len { S7_SetPoint := 'True'} : UInt; BufferCache { S7_SetPoint := 'True'} : Int; // 缓存区数据 BufferCache_Real { S7_SetPoint := 'True'} : Real; ReadDataScale { S7_SetPoint := 'True'} : Real; // 读取参数换算 WriteDataScale { S7_SetPoint := 'True'} : Real; // 写入参数换算 ParDataScale { S7_SetPoint := 'True'} : Real; // 参数写入换算 ParameterLast { S7_SetPoint := 'True'} : Array[-1..50] of Int; // 参数数据未改变前 WriteLast { S7_SetPoint := 'True'} : Array[-1..40] of Int; // 写入数据未改变前 ClearZero { S7_SetPoint := 'True'} : Array[-1..50] of Int; // 清零数组 TON_Timer {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME; END_VAR VAR_TEMP i : Int; j : Int; k : Int; index : Int; END_VAR VAR CONSTANT HRWriteLen : UInt := 1; // 默认寄存器长度为1 HRParLen : UInt := 1; // 默认寄存器长度为 HRReadLen : UInt := 1; // 默认寄存器长度为1 ModeRead_03 : USInt := 0; // 03功能码 ModeWrite_06 : USInt := 1; // 06功能码 ModeWrite_16 : USInt := 2; // 16功能码 HRFirst : Int := 0; // 寄存器起点 HRReadFirst : Int := 0; // 反馈寄存器起点 HRParFirst : Int := 0; // 参数寄存器起点 HRWriteFirst : Int := 0; // 设定值寄存器起点 END_VAR BEGIN REGION 初始化 IF #FirstScan THEN #PollingFullAddr := TRUE; #HRWriteStart := FALSE; #HRParStart := FALSE; REGION 初始化寄存器 REGION 温控反馈 #HRReadNumber := 0; FOR #i := 0 TO 20 DO IF #Parameter.CofigSlave.CofigRead.Address[#i] <> 0 THEN #HRReadNumber := #HRReadNumber + 1; END_IF; END_FOR; END_REGION REGION 温控参数 #HRParNumber := 0; FOR #j := 0 TO 50 DO IF #Parameter.CofigSlave.CofigParameter.Address[#j] <> 0 THEN #HRParNumber := #HRParNumber + 1; END_IF; END_FOR; END_REGION REGION 温控设定值 #HRWriteNumber := 0; FOR #k := 0 TO 40 DO IF #Parameter.CofigSlave.CofigWrite.Address[#k] <> 0 THEN #HRWriteNumber := #HRWriteNumber + 1; END_IF; END_FOR; END_REGION REGION 初始化last数组 MOVE_BLK(IN:=#ClearZero[-1], COUNT:=37, OUT=>#ParameterLast[-1]); MOVE_BLK(IN:=#ClearZero[-1], COUNT:=42, OUT=>#WriteLast[-1]); END_REGION END_REGION END_IF; IF #FirstScan OR #PollingInitialize THEN REGION 初始化参数 #PollingStart := TRUE; #PollingEnd := FALSE; //初始化索引 #HRIndex := #HRFirst; #HRReadIndex := #HRReadFirst; #HRParIndex := #HRParFirst; #HRWriteIndex := #HRWriteFirst; //初始化-client参数 #DisConnect := #Parameter.#DisConnect; #MB_Mode := #ModeRead_03; #MB_Data_Addr := #Parameter.CofigSlave.CofigRead.Address[#HRReadIndex]; #MB_Data_Len := #HRReadLen; //初始化标志位 #PollingReq := TRUE; #HRDataStep := 0; #MonitorStep := 0; //清空缓存区 #BufferCache := 0; #WriteDataScale := 0.0; #ParDataScale := 0.0; END_REGION END_IF; END_REGION REGION 监听数据变化 // 只要设定值或参数数组有变化,即添加一个标志位 CASE #MonitorStep OF 0: //整体读取数据,赋值到last数组 IF NOT #PollingFullAddr THEN #MonitorStep := 10; END_IF; 10: //判断监听事件是否来到 IF #HRWriteStart OR #HRWriteStart THEN #MonitorStep := 20; ELSIF NOT #HRWriteStart AND NOT #HRParStart THEN #MonitorStep := 11; END_IF; 11: //遍历设定值数组,长到不同的数值 FOR #index := 0 TO 40 DO IF #WriteLast[#index] <> #Data.Write[#index] THEN #HRWriteIndexLast := #index; #HRWriteStart := TRUE; #HRWriteIndex := #HRWriteFirst; EXIT; END_IF; END_FOR; IF #HRWriteStart THEN #MonitorStep := 20; ELSE #MonitorStep := 12; END_IF; 12://遍历参数数组,长到不同的数值 FOR #index := 0 TO 50 DO IF #ParameterLast[#index] <> #Data.Parameter[#index] THEN #HRParIndexLast := #index; #HRParStart := TRUE; #HRParIndex := #HRParFirst; EXIT; END_IF; END_FOR; IF #HRParStart THEN #MonitorStep := 20; ELSE #MonitorStep := 11; END_IF; 20: //判断跳转条件 IF #PollingFullAddr THEN IF NOT #HRParStart AND NOT #HRWriteStart THEN #MonitorStep := 0; END_IF; ELSE #MonitorStep := 10; END_IF; END_CASE; END_REGION REGION 总寄存器 IF #PollingFullAddr THEN #HRNumber := #HRReadNumber + #HRParNumber + #HRWriteNumber; ELSIF #HRWriteStart OR #HRParStart THEN #HRNumber := #HRReadNumber + 1; ELSE #HRNumber := #HRReadNumber; END_IF; END_REGION REGION 轮询启停 IF #PollingStart AND NOT #PollingEnd THEN #PollingInitialize := FALSE; ELSIF NOT #PollingStart AND #PollingEnd THEN #PollingFullAddr := FALSE; #HRWriteStart := FALSE; #HRParStart := FALSE; #PollingInitialize := TRUE; END_IF; END_REGION REGION Modbus TCP Client //堵塞超时(喵~ >▽< ) #MB_CLIENT.Blocked_Proc_Timeout := #Parameter.Blocked_Proc_Timeout; //接收超时(喵~ >▽< ) #MB_CLIENT.Rcv_Timeout := #Parameter.Rcv_Timeout; //Modbus从站地址赋值 #MB_CLIENT.MB_Unit_ID := #Parameter.CofigSlave.MB_Unit_ID; //轮询延迟触发 #TON_Timer(IN := #PollingReq, PT := T#30ms); //客户端 #MB_CLIENT(REQ := #TON_Timer.Q, DISCONNECT := #DisConnect, MB_MODE := #MB_Mode, MB_DATA_ADDR := #MB_Data_Addr, MB_DATA_LEN := #MB_Data_Len, MB_DATA_PTR := #BufferCache, CONNECT := #Parameter.CofigConnect); END_REGION REGION 数据读写 CASE #HRDataStep OF 0: //读取数据 IF NOT #MB_CLIENT.ERROR AND #MB_CLIENT.DONE THEN #PollingReq := FALSE; #HRDataStep := 1; END_IF; 1: //等待Done复位 IF NOT #MB_CLIENT.DONE THEN IF #HRWriteStart OR #HRParStart THEN #HRDataStep := 20; //有设定值/参数值改变 ELSE #HRDataStep := 2;//正常实时读取 END_IF; END_IF; 2: //读取数据 #BufferCache_Real := INT_TO_REAL(#BufferCache); IF #PollingFullAddr THEN #HRDataStep := 3; ELSE #HRDataStep := 4; END_IF; 3: //整体数据读取 IF #HRIndex <= #HRReadNumber - 1 THEN #HRDataStep := 4; ELSIF #HRIndex >= #HRReadNumber AND #HRIndex <= #HRReadNumber + #HRWriteNumber - 1 THEN #HRDataStep := 5; ELSIF #HRIndex >= #HRReadNumber + #HRWriteNumber AND #HRIndex <= #HRNumber - 1 THEN #HRDataStep := 6; END_IF; 4://整体数据读取——实时数据 #ReadDataScale := #BufferCache_Real * #Parameter.CofigSlave.CofigRead.DataScale[#HRReadIndex]; #Data.Read[#HRReadIndex] := REAL_TO_INT(#ReadDataScale); #HRDataStep := 10;//读取完成 5://整体数据读取——设定值数据 #WriteDataScale := #BufferCache_Real * #Parameter.CofigSlave.CofigWrite.DataScale[#HRWriteIndex]; #Data.Write[#HRWriteIndex] := REAL_TO_INT(#WriteDataScale); #WriteLast[#HRWriteIndex] := REAL_TO_INT(#WriteDataScale); #HRDataStep := 10;//读取完成 6://整体数据读取——参数数据 #ParDataScale := #BufferCache_Real * #Parameter.CofigSlave.CofigParameter.DataScale[#HRParIndex]; #Data.Parameter[#HRParIndex] := REAL_TO_INT(#ParDataScale); #ParameterLast[#HRParIndex] := REAL_TO_INT(#ParDataScale); #HRDataStep := 10;//读取完成 10:// 读写切换判断 #BufferCache := 0; IF #PollingFullAddr THEN #HRDataStep := 11; ELSE #HRParIndex := #HRParFirst; #HRWriteIndex := #HRWriteFirst; #HRDataStep := 12; END_IF; 11://整体数据读取——读写切换判断 #HRIndex := #HRIndex + 1; IF #HRIndex <= #HRNumber - 1 THEN #MB_Mode := #ModeRead_03; #PollingStart := TRUE; #PollingEnd := FALSE; #HRDataStep := 13;//索引自加1 ELSE #PollingStart := FALSE; #PollingEnd := TRUE; #HRDataStep := 30;//轮询结束,等待命令 END_IF; 12://实时数据读取 #HRIndex := #HRIndex + 1; IF #HRIndex <= #HRReadNumber - 1 THEN #HRReadIndex := #HRReadIndex + 1; #PollingStart := TRUE; #PollingEnd := FALSE; #HRDataStep := 40;//写入实时读取的参数 ELSE #PollingStart := FALSE; #PollingEnd := TRUE; #HRDataStep := 30;//实时数据读结束,等待命令开启下一个轮询 END_IF; 13://整体数据读取——索引自加1 IF #HRIndex <= #HRReadNumber - 1 THEN #HRDataStep := 14; ELSIF #HRIndex >= #HRReadNumber AND #HRIndex <= #HRReadNumber + #HRWriteNumber - 1 THEN #HRDataStep := 15; ELSIF #HRIndex >= #HRReadNumber + #HRWriteNumber AND #HRIndex <= #HRNumber - 1 THEN #HRDataStep := 16; END_IF; 14://写入实时读取的索引 #HRParIndex := #HRParFirst - 1; #HRWriteIndex := #HRWriteFirst - 1; #HRReadIndex := #HRReadIndex + 1; #HRDataStep := 40;//写入实时读取的参数 15://整体-写入设定值读取的索引 #HRParIndex := #HRParFirst - 1; #HRWriteIndex := #HRWriteIndex + 1; #HRDataStep := 50;//整体-写入设定值读取的参数 16://整体-写入参数读取的索引 #HRParIndex := #HRParIndex + 1; #HRDataStep := 60;//整体-写入参数读取的参数 20: //写入数据 #HRIndex := #HRFirst; #HRReadIndex := #HRReadFirst; IF #HRWriteStart THEN #WriteDataScale := 0.0; IF #HRWriteIndex = 0 THEN #MB_Mode := #ModeWrite_16; #HRDataStep := 21; ELSIF #HRWriteIndex = 1 THEN #BufferCache := 0; #MB_Mode := #ModeRead_03; #HRDataStep := 70;//设定值写入完成,跳转读取设定值数据 ELSIF #HRWriteIndex = 2 THEN #BufferCache_Real := INT_TO_REAL(#BufferCache); #HRDataStep := 23; END_IF; ELSIF #HRParStart THEN #ParDataScale := 0.0; IF #HRParIndex = 0 THEN #MB_Mode := #ModeWrite_16; #HRDataStep := 22; ELSIF #HRParIndex = 1 THEN #BufferCache := 0; #MB_Mode := #ModeRead_03; #HRDataStep := 80;//参数写入完成,跳转读取参数数据 ELSIF #HRParIndex = 2 THEN #BufferCache_Real := INT_TO_REAL(#BufferCache); #HRDataStep := 24; END_IF; ELSE #HRWriteIndexLast := 0; #HRParIndexLast := 0; #PollingStart := FALSE; #PollingEnd := TRUE; #HRDataStep := 30;//出错,临时中断轮询,等待复位命令 END_IF; 21://设定值数据写入 #WriteDataScale := INT_TO_REAL(#Data.Write[#HRWriteIndexLast]) / #Parameter.CofigSlave.CofigWrite.DataScale[#HRWriteIndexLast]; #BufferCache := REAL_TO_INT(#WriteDataScale); #HRDataStep := 70;//监听-写入设定值读取的参数 22://参数数据写入 #ParDataScale := INT_TO_REAL(#Data.Parameter[#HRParIndexLast]) / #Parameter.CofigSlave.CofigParameter.DataScale[#HRParIndexLast]; #BufferCache := REAL_TO_INT(#ParDataScale); #HRDataStep := 80;//监听-写入参数读取的参数 23: //设定值数据读取 #WriteDataScale := #BufferCache_Real * #Parameter.CofigSlave.CofigWrite.DataScale[#HRWriteIndexLast]; #WriteLast[#HRWriteIndexLast] := REAL_TO_INT(#WriteDataScale); #HRDataStep := 25;//读取完成 24: //参数数据读取 #ParDataScale := #BufferCache_Real * #Parameter.CofigSlave.CofigParameter.DataScale[#HRParIndexLast]; #ParameterLast[#HRParIndexLast] := REAL_TO_INT(#ParDataScale); #HRDataStep := 26;//读取完成 25: //设定值数据读取 IF #HRWriteIndex >= 2 THEN #HRWriteIndexLast := 0; #PollingStart := FALSE; #PollingEnd := TRUE; #HRDataStep := 30;//设定值先写后读完毕,等待命令 ELSE #HRWriteIndex := #HRWriteFirst; #HRDataStep := 20;//返回先写后读,等待命令 END_IF; 26://参数数据读取 IF #HRParIndex >= 2 THEN #HRParIndexLast := 0; #PollingStart := FALSE; #PollingEnd := TRUE; #HRDataStep := 30;//设定值先写后读完毕,等待命令 ELSE #HRParIndex := #HRParFirst; #HRDataStep := 20;//返回先写后读,等待命令 END_IF; 30: //空,等待复位 IF #MB_CLIENT.DONE THEN #HRDataStep := 0; ELSE #PollingReq := TRUE; END_IF; 40://写入实时读取的参数 #MB_Data_Addr := #Parameter.CofigSlave.CofigRead.Address[#HRReadIndex]; #MB_Data_Len := #HRReadLen; IF #MB_Data_Addr <> 0 THEN #HRDataStep := 30;//实时数据读完毕,等待命令 END_IF; 50://整体-写入设定值读取的参数 #MB_Data_Addr := #Parameter.CofigSlave.CofigWrite.Address[#HRWriteIndex]; #MB_Data_Len := #HRWriteLen; IF #MB_Data_Addr <> 0 THEN #HRDataStep := 30;//寄存器address+长度赋值完毕,等待复位命令 END_IF; 60://整体-写入参数读取的参数 #MB_Data_Addr := #Parameter.CofigSlave.CofigParameter.Address[#HRParIndex]; #MB_Data_Len := #HRWriteLen; IF #MB_Data_Addr <> 0 THEN #HRDataStep := 30;//寄存器address+长度赋值完毕,等待复位命令 END_IF; 70://监听-写入设定值读取的参数 #MB_Data_Addr := #Parameter.CofigSlave.CofigWrite.Address[#HRWriteIndexLast]; #MB_Data_Len := #HRWriteLen; IF #MB_Data_Addr <> 0 THEN #HRWriteIndex := #HRWriteIndex + 1; #HRDataStep := 30;//设定值写入完成,等待命令 END_IF; 80://监听-写入参数读取的参数 #MB_Data_Addr := #Parameter.CofigSlave.CofigParameter.Address[#HRParIndexLast]; #MB_Data_Len := #HRParLen; IF #MB_Data_Addr <> 0 THEN #HRParIndex := #HRParIndex + 1; #HRDataStep := 30;//参数写入完成,等待命令 END_IF; END_CASE; END_REGION END_FUNCTION_BLOCK