4. 通信原理详解
关于Modbus通信,网上能搜出一堆教程,我也查阅参考了很多,说实话,大多数都只是把自己的成功案例亮了出来,至于为什么能够成功,通信是否稳定,是否具备可改造性,没什么说明。
这个是官方提供的一个例程,包含PDF教程和项目文件,都是英文版,有兴趣的可以下载下来看一看,本次教程就是以它为基础的。
《如何使用 STEP 7 ( TIA Portal ) 为 SIMATIC S7-1200 建立 MODBUS - RTU 通信?》
47756141_Description.pdf (526,2 KB)
Registrierung notwendig 47756141_Sample_project_for_STEP_7_TIA_Portal_V15.zip (2,2 MB)
4.1 Modbus_Comm_Load
Modbus_Comm_Load 的组态更改将保存在 CM 中,而不是 CPU 中。恢复电压和插拔时,将使用保存在设备配置中的数据组态 CM。必须在这些情况下调用 Modbus_Comm_Load 指令。
大家知道,Modbus_Comm_Load只需要在PLC上电时运行一次即可,所以我在Startup OB100里面对"modbusCommLoad_REQ"进行置位,当调用 Modbus_Comm_Load 指令成功后复位。
Startup OB100
"modbusCommLoad_REQ" := TRUE;
Modbus FC7
这里的Done_Stored变量也是用作下面"Modbus_Master_DB"里面REQ启动的必要条件。
4.2 Modbus_Master的运行机制
Modbus_Master 前面已经组态好了。
上一节里面有Modbus_Master每个参数的含义表,编程之前需要很熟悉它。
这里先重点给大家讲一下Modbus_Master这个指令的运行机制:
首先给"MB_ADDR"、“MODE”、DATA_ADDR"赋值,确定从站号、读/写、要访问数据的地址,然后REQ接通,开始发送命令,执行过程中"BUSY"会变为TRUE,当数据传输成功完成时"BUSY"变为FALSE、随之"DONE"变为 TRUE 并保持一个周期。如果通信不成功,会再次发送指令,如果在响应超时时间(“Modbus_Comm_Load"的RESP_TO”,默认1000ms)内始终无法成功通信,则 ERROR 位将变为 TRUE ,并保持一个周期。在这期间STATUS会显示错误代码,建议将其保存。
不难看出,一次通信,是以”REQ“置位TRUE为开始,以”BUSY“输出TRUE为运行中,以”DONE“或者”ERROR“输出TRUE为结束。
这里要及其注意的是,在REQ置位TRUE后到DONE或ERROR输出TRUE前这段时间内,MODE、DATA_ADDR 和 DATA_LEN 参数是不允许发生改变的,否则该次通信将以将以 ERROR = 1 和 STATUS = 8200 终止。
5. 单个变频器的数据读写
版本1 单个变频器单个数据的读写
//版本1 单个变频器单个数据的读写
CASE "INV".Master_Step OF
1: //写开始
"modbusMaster_MODE" := 1;
"modbusMaster_DATA_ADDR" := 40101; //主设定值 40101,频率0~50Hz转换为主设定值0~16384
"modbusMaster_DATA_PTR" := INT_TO_WORD(REAL_TO_INT(16384 * "INV".M101_FREQ_Set / 50));
"modbusMaster_REQ" := TRUE;
IF "modbusMaster_BUSY" THEN
"INV".Master_Step := 2;
END_IF;
2: //写结束
IF "modbusMaster_DONE" OR "modbusMaster_ERROR" THEN
"modbusMaster_REQ" := FALSE;
"INV".Master_Step := 3;
END_IF;
3: //读开始
"modbusMaster_MODE" := 0;
"modbusMaster_DATA_ADDR" := 40110; //状态字 40110
"modbusMaster_REQ" := TRUE;
IF "modbusMaster_BUSY" THEN
"INV".Master_Step := 4;
END_IF;
4: //读结束
IF "modbusMaster_DONE" OR "modbusMaster_ERROR" THEN
IF "modbusMaster_ERROR" THEN
"INV".M10[1].状态字 := 0;
ELSE
"INV".M10[1].状态字 := "modbusMaster_DATA_PTR";
END_IF;
"modbusMaster_REQ" := FALSE;
"INV".Master_Step := 1;
END_IF;
ELSE
"modbusMaster_REQ" := FALSE;
"INV".Master_Step := 1;
END_CASE;
在Modbus_Comm_Load已激活组态,Modbus_Master使能的情况下,你发现程序起作用了,给"INV".M101_FREQ_Set设定一个频率25Hz,变频器操作面板上显示了对应的设定转速。同时"INV".M10[1].状态字也收到了数值。然而你通过开关/中间继电器接通DI0,发现变频器完全没有动作……这就对了。回顾一下上一节,是不是少了点什么东西。
再看一看状态字,发现位0的值为0,未接通就绪。
于是我将Step1修改了一下,成了这样:
版本2 增加变频器就绪使能
1: //写开始
"modbusMaster_MODE" := 1;
IF %DB9.DBX77.0 THEN //状态字第0位,变频器接通就绪
"modbusMaster_DATA_ADDR" := 40101; //主设定值 40101,频率0~50Hz转换为主设定值0~16384
"modbusMaster_DATA_PTR" := INT_TO_WORD(REAL_TO_INT(16384 * "INV".M101_FREQ_Set / 50));
ELSE
"modbusMaster_DATA_ADDR" := 40100; //控制字40100
"modbusMaster_DATA_PTR" := 16#047E;
END_IF;
"modbusMaster_REQ" := TRUE;
IF "modbusMaster_BUSY" THEN
"INV".Master_Step := 2;
END_IF;
这会儿我们发现,一启动通信,状态字变了。
然后接通DI0,变频器顺利启动。
这时候,控制字、主设定值、状态字我们都读写了,那就顺便把主实际值40111也读了吧。
版本3 增加读主实际值
这里我们增加了一个Bool变量”Read_DATA_ADDR_Change“,每次读数据结束取反一次,实现40110和40111的轮流读数据。
3: //读开始
"modbusMaster_MODE" := 0;
IF "Read_DATA_ADDR_Change" THEN
"modbusMaster_DATA_ADDR" := 40110; //状态字
ELSE
"modbusMaster_DATA_ADDR" := 40111; //主实际值
END_IF;
"modbusMaster_REQ" := TRUE;
IF "modbusMaster_BUSY" THEN
"INV".Master_Step := 4;
END_IF;
4: //读结束
IF "modbusMaster_DONE" OR "modbusMaster_ERROR" THEN
IF "modbusMaster_DATA_ADDR" = 40110 THEN
IF "modbusMaster_ERROR" THEN
"INV".M10[1].状态字 := 0;
ELSE
"INV".M10[1].状态字 := "modbusMaster_DATA_PTR";
END_IF;
ELSIF "modbusMaster_DATA_ADDR" = 40111 THEN
IF "modbusMaster_ERROR" THEN
"INV".M10[1].主实际值 := 0;
ELSE
"INV".M10[1].主实际值 := "modbusMaster_DATA_PTR";
END_IF;
"INV".M101_FREQ_Back := INT_TO_REAL(WORD_TO_INT("modbusMaster_DATA_PTR")) * 50 / 16384;
"modbusMaster_REQ" := FALSE;
"INV".Master_Step := 1;
"Read_DATA_ADDR_Change" := NOT "Read_DATA_ADDR_Change";
END_IF;
END_IF;
ELSE
至此,单个变频器的Modbus通信就基本上实现了,如果需要读写其他数据,记得再读写的最开始更改DATA_ADDR即可。
下一节,我以手头的五个变频器为例,讲一下多个从站轮询这块。