博图S 7-1200PLC USS 通讯西门子V20变频器案例,读电流电压轮训,写入变频器加速时间,有课件分析
博图 S7-1200 PLC 与西门子 V20 变频器的 USS 通讯案例:读电流电压轮训与写入加速时间
最近在项目中用到了博图 S7-1200 PLC 与西门子 V20 变频器通过 USS 通讯来实现一些功能,感觉挺有意思的,在这里给大家分享一下具体的实现过程和相关代码分析。
一、硬件连接
首先得把硬件连接好,PLC 的 CPU 与 V20 变频器通过 USS 协议进行通讯。一般就是将 PLC 的通信端口(比如 PORT1)与变频器的 USS 接口连接起来,注意要确保连接正确,不然通讯就会出问题。
二、配置
-
PLC 配置
在博图中,打开项目后,在设备组态里找到 CPU,然后在属性中找到“PROFINET 接口”,在其“属性”的“常规”选项卡中确保以太网接口的设置正确。接着在“属性”的“保护”选项卡中设置好访问权限等。对于 USS 通讯,还需要在设备组态中添加“通信处理器”,选择合适的通讯模块(比如 CM1241 RS485)。添加完成后,双击该模块进行属性设置,在“常规”选项卡中设置通讯的波特率、奇偶校验等参数,要与变频器的 USS 通讯参数一致。这里假设波特率设置为 9600,无奇偶校验。
-
变频器设置
西门子 V20 变频器要设置成 USS 通讯模式。通过变频器的操作面板,进入参数设置界面,找到通讯相关参数。设置变频器的站地址,比如设为 1,波特率设为 9600,数据位 8 位,停止位 1 位,无奇偶校验等,要和 PLC 的设置匹配。
三、编程实现
读电流电压轮训
- 代码部分
// 定义 USS 通讯背景数据块
OB1_DB1:DB1
// 定义变量
VAR
USS_CTRL_DB1.DRV_NAME : ARRAY[0..7] OF CHAR := 'V20 ';
USS_CTRL_DB1.CTRL_MODE := 16#0000;
USS_CTRL_DB1.OP_MODE := 16#0000;
USS_CTRL_DB1.COM_RATE := 9600;
USS_CTRL_DB1.PARITY := 0;
USS_CTRL_DB1.STOP_BITS := 1;
USS_CTRL_DB1.ADDR_MODE := 1;
USS_CTRL_DB1.STATION := 1;
USS_CTRL_DB1.MODE_SEL := 16#0000;
USS_CTRL_DB1.CMD_ID := 16#0000;
USS_CTRL_DB1.PARAMETER := 16#0000;
USS_CTRL_DB1.REQ_SEND := 0;
USS_CTRL_DB1.DONE := 0;
USS_CTRL_DB1.ERROR := 0;
USS_CTRL_DB1.STATUS := 0;
USS_CTRL_DB1.DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_LEN := 256;
USS_CTRL_DB1.RESPONSE := 0;
USS_CTRL_DB1.COMM_ERR := 0;
USS_CTRL_DB1.ACK_ERR := 0;
USS_CTRL_DB1.DATA_VAL := 0;
USS_CTRL_DB1.DATA_SCALE := 0;
USS_CTRL_DB1.DATA_OFFSET := 0;
USS_CTRL_DB1.DATA_STATUS := 0;
USS_CTRL_DB1.DATA_UNIT := 0;
USS_CTRL_DB1.DATA_OVERFLOW := 0;
USS_CTRL_DB1.DATA_UNDERFLOW := 0;
USS_CTRL_DB1.DATA_ERROR := 0;
USS_CTRL_DB1.DATA_TYPE := 0;
USS_CTRL_DB1.DATA_COUNT := 0;
USS_CTRL_DB1.DATA_READY := 0;
USS_CTRL_DB1.DATA_TRANSFER := 0;
USS_CTRL_DB1.DATA_ACK := 0;
USS_CTRL_DB1.DATA_NACK := 0;
USS_CTRL_DB1.DATA_TIMEOUT := 0;
USS_CTRL_DB1.DATA_PENDING := 0;
USS_CTRL_DB1.DATA_ABORT := 0;
USS_CTRL_DB1.DATA_RESET := 0;
USS_CTRL_DB1.DATA_RETRY := 0;
USS_CTRL_DB1.DATA_WAIT := 0;
USS_CTRL_DB1.DATA_RUNNING := 0;
USS_CTRL_DB1.DATA_DONE := 0;
USS_CTRL_DB1.DATA_ERROR_CODE := 0;
USS_CTRL_DB1.DATA_ERROR_MSG := '';
USS_CTRL_DB1.DATA_ERROR_INFO := 0;
USS_CTRL_DB1.DATA_ERROR_ADDR := 0;
USS_CTRL_DB1.DATA_ERROR_LEN := 0;
USS_CTRL_DB1.DATA_ERROR_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_ADDR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_SUM := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_STDDEV := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_VARIANCE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_RANGE := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_THRESHOLD := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_TRIGGER := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_CLEAR := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA_PTR := P#DB1.DBX0.0 BYTE 256;
USS_CTRL_DB1.DATA_ERROR_LOG_LEN := 256;
USS_CTRL_DB1.DATA_ERROR_LOG_DATA := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_COUNT := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MAX := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_MIN := 0;
USS_CTRL_DB1.DATA_ERROR_LOG_AVG := 0;
**手把手玩转S7-1200与V20变频器的USS通讯实战**
最近在调试产线时碰上个需求:用S7-1200 PLC通过USS协议读取V20变频器的实时电流电压,还要能动态修改加速时间。这活看起来基础,实操时从报文结构到轮训逻辑都有坑。今天咱们直接上干货,边写代码边聊避坑指南。
**硬件准备先走一波**
- S7-1214C DC/DC/DC(6ES7 214-1AG40-0XB0)
- V20变频器(功率根据实际电机选)
- 24V开关电源给PLC和变频器供电
- 两芯屏蔽线接PLC的CM1241(RS485模块)与V20的USS端子
*注意:V20的P+接CM1241的B线,N-接A线,反了直接通讯扑街*
**TIA Portal配置三板斧**
1. 设备视图里插入CM1241模块,协议选USS,波特率默认19.2k够用
2. 变频器参数P0003设3(专家模式),P0010设1(快速调试)
3. 设置站地址P2011,比如设3号站,这个值后面编程要用到
**轮训读取电流电压的核心逻辑**
```sql
VAR
USS_PORT : PORT_0; // 硬件标识符
USS_DB : ARRAY[0..1] OF USS_DRV; // 创建两个驱动对象
ReadIndex : INT := 0; // 轮训指针
CurrentValue : REAL; // 实际电流
VoltageValue : REAL; // 直流母线电压
END_VAR
// 主OB块里定时触发
IF "1s脉冲" THEN
CASE ReadIndex OF
0: // 读取输出电流
USS_DB[0].REQ := TRUE;
USS_DB[0].PARAM := 27; // 27对应r0027
USS_DB[0].DRIVE := 3; // 站地址
CurrentValue := USS_DB[0].VALUE;
1: // 读取直流电压
USS_DB[1].REQ := TRUE;
USS_DB[1].PARAM := 25; // r0025
USS_DB[1].DRIVE := 3;
VoltageValue := USS_DB[1].VALUE;
END_CASE
ReadIndex := (ReadIndex + 1) MOD 2; // 循环切换
END_IF
这里用了双通道轮训,每个周期只读一个参数。实测过单通道连续读两个参数容易丢包,特别是当变频器处于运行状态时。USS_DRV块要设置背景数据块,注意每个驱动对象独立实例化。
加速时间写入骚操作
VAR
WriteJob : USS_DRV; // 单独实例
AccelerationTime : REAL := 10.0; // 默认10秒
END_VAR
// 写入P1120加速时间
IF "写入触发信号" THEN
WriteJob.PARAM := 1120; // 参数号
WriteJob.VALUE := AccelerationTime;
WriteJob.REQ := TRUE;
WriteJob.DRIVE := 3;
// 错误处理不能少
IF WriteJob.DONE THEN
IF WriteJob.ERROR THEN
// 记录错误代码WriteJob.STATUS
ELSE
// 写入成功提示
END_IF
END_IF
END_IF
重点注意P1120的数据类型是32位浮点,USS协议自动转换。写入后务必检查STATUS值,常见错误码:16#0008-无效参数,16#8001-通讯超时。
实战踩坑记录
- 遇到过读值突然变0的情况,最后发现是屏蔽层没接参考电位。RS485通讯必须保证等电位,否则共模电压搞事情。
- 轮训间隔别小于200ms,V20的响应速度没那么快。曾经试过100ms间隔导致丢包率30%以上。
- 同时读写多个参数时,USS_DRV对象必须分开实例化,混用会导致数据覆盖。
性能优化Tips
- 关键参数读取用异步处理:先发请求,下一个周期再取结果
- 建立双缓冲区机制,防止数据更新时的数值跳变
- 重要参数做滑动平均滤波,处理偶尔的通讯干扰值
这个方案在包装线速度控制项目上稳定运行了半年多,实测单台PLC带5个V20变频器也没压力。下次准备试试Profinet通讯方案,听说实时性更好,不过硬件成本得翻倍…
博图S 7-1200PLC USS 通讯西门子V20变频器案例,读电流电压轮训,写入变频器加速时间,有课件分析