当前位置: 首页 > news >正文

基于modbus rtu协议操作PLC的EPICS示例

硬件设备

本实验中使用到的设备如下:

1、S7-200 Smart SR20 PLC

作为受控设备,执行机构。

S7-200 Smart是西门子的一款小型PLC产品(以下简称Smart系列)。

Smart系列PLC是西门子公司经过大量调研,为中国小型自动化市场量身打造的一款PLC产品。与西门子S7-1200系列相比,Smart系列不支持博途开发环境(使用STEP 7-MicroWIN SMART编程)、不支持Profinet通信(但支持Profibus);最多能扩展6个信号模块(EM)和1个信号板(SB)。

S7-200 SMART PLC 主要性能参数 V2.3,如下图

2、串口服务器 :USR-TCP232-410s

将PLC的485 串口信号转成网络信号接入局域网

产品参数如下:

3、单板机Orange Pi 3 LTS

运行EPICS IOC,运行上位控制程序。

4、串口线 

软件部分

1、PLC上编程

初始化PLC为从设备,设置其工作模式为modbus rtu, 地址为3,波特率为115200,使用PLC自带串口,无延时,最大IO个数为256,最大模拟量为56个字,V存储器是从VB2000开始的100个字

一直使能这个从设备 

2、串口服务器部分

通过浏览器设置串口服务器的IP地址为自己所需的地址:

设置RS485端口的串口参数,需要和PLC设置的参数保持一致,以及访问此RS485所需的端口号:

3、单板机部分:

安装操作系统和所需的EPICS模块

1) 操作系统

Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy

2)所需安装的EPICS 模板

由于EPICS模块之间的依赖关系,需要以下4个模块:

base, seq , ipac ,asyn, modbus

4、IOC建立过程

先创建一个项目目录,在其下用makeBaseApp工具创建一个IOC应用程序的框架,编辑configure/RELEASE文件,添加本IOC依赖的模块,在程序src下Makefile中添加所依赖的库文件和源文件; 在Db文件下添加模板文件:

configure/RELEASE:
...
SUPPORT=/usr/local/EPICS/synApps/support# If using the sequencer, point SNCSEQ at its top directory:
#SNCSEQ = $(MODULES)/seq-ver
ASYN=$(SUPPORT)/asyn
MODBUS=$(SUPPORT)/modbus
AUTOSAVE=$(SUPPORT)/autosave...
xxxApp/src:
....sr20smart_DBD += asyn.dbd
sr20smart_DBD += drvAsynIPPort.dbdsr20smart_DBD += modbus.dbd
sr20smart_DBD += asSupport.dbd# Include dbd files from all support applications:
# #sr20smart_DBD += xxx.dbd
#
# # Add all the support libraries needed by this IOC
#sr20smart_LIBS += xxx
sr20smart_LIBS += asyn
sr20smart_LIBS += modbus
sr20smart_LIBS += autosave...
xxxApp/Db:
bi_bit.template:用于按位读取PLC的输入输出点。
record(bi,"$(P)$(R)$(D)$(M)_$(N)") {field(DTYP,"asynUInt32Digital")field(INP,"@asynMask($(PORT) $(OFFSET) 0x1)")field(SCAN,"$(SCAN)")field(ZNAM,"$(ZNAM)")field(ONAM,"$(ONAM)")field(ZSV,"$(ZSV)")field(OSV,"$(OSV)")
}
bo_bit.template:用于按位写PLC的输出点。
record(bo,"$(P)$(R)Q$(M)_$(N)") {field(DTYP,"asynUInt32Digital")field(OUT,"@asynMask($(PORT) $(OFFSET) 0x1)")field(ZNAM,"$(ZNAM)")field(ONAM,"$(ONAM)")
}

  longin_int16.template:用于按字读取PLC的V存储器以及模拟输入映像区,并且转成16位整数。

record(longin,"$(P)$(R)$(T)_$(M)") {field(DTYP,"asynInt32")field(INP,"@asyn($(PORT) $(OFFSET))$(DATA_TYPE)")field(SCAN, "$(SCAN)")
}

longoutInt16.template: 用于把16位整数按字写入PLC的V存储器。

record(longout,"$(P)$(R)$(T)_$(M)") {field(DTYP,"asynInt32")field(OUT,"@asyn($(PORT) $(OFFSET))$(DATA_TYPE)")
}

 float32_in.template:用于按双字读取PLC的V存储区,并且转成32位浮点数。

record(ai, "$(P)$(R)$(T)_$(M)") {field(DTYP,"asynFloat64")field(INP,"@asyn($(PORT) $(OFFSET))$(DATA_TYPE)")field(HOPR,"$(HOPR)")field(LOPR,"$(LOPR)")field(PREC,"$(PREC)")field(SCAN,"$(SCAN)")
}

float32_out.template:用于将32位浮点数按双字写入到PLC的V存储器。

record(ao, "$(P)$(R)$(T)_$(M)O") {field(DTYP,"asynFloat64")field(OUT,"@asyn($(PORT) $(OFFSET))$(DATA_TYPE)")field(HOPR,"$(HOPR)")field(LOPR,"$(LOPR)")field(PREC,"$(PREC)")
}

回到此IOC的顶层目录,编译以上代码,生产IOC程序。

5、编辑启动目录,添加模板替换文件,编辑启动脚本st.cmd:

1)添加的实例化文件如下:

1)qb.substitutions:实例化8个bo记录,用于写,分别写一个位到PLC的输出点Q0.0~Q0.7

file "../../db/bo_bit.template" { pattern
{P,             R,      M,      N,          PORT,           OFFSET,             ZNAM,           ONAM}
{SR20SMART:,   BIT:,     0      0               QB0,            0,              Low,            High}
{SR20SMART:,   BIT:,     0      1               QB0,            1,              Low,            High}
{SR20SMART:,   BIT:,     0      2               QB0,            2,              Low,            High}
{SR20SMART:,   BIT:,     0      3               QB0,            3,              Low,            High}
{SR20SMART:,   BIT:,     0      4               QB0,            4,              Low,            High}
{SR20SMART:,   BIT:,     0      5               QB0,            5,              Low,            High}
{SR20SMART:,   BIT:,     0      6               QB0,            6,              Low,            High}
{SR20SMART:,   BIT:,     0      7               QB0,            7,              Low,            High}
}

2) qb_rbv.substitutions:实例化8个bi记录,用于读取,分别读取一个位到PLC的输出点Q0.0~Q0.7

file "../../db/bi_bit.template" { pattern
{P,             R,      D,      M,      N,         PORT,         OFFSET,   ZNAM,                                                                 ONAM,  ZSV,       OSV,    SCAN}
{SR20SMART:,    BIT:,   Q,      0,      0_RBV,  QB0_RBV,        0,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      1_RBV,  QB0_RBV,        1,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      2_RBV,  QB0_RBV,        2,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      3_RBV,  QB0_RBV,        3,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      4_RBV,  QB0_RBV,        4,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      5_RBV,  QB0_RBV,        5,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      6_RBV,  QB0_RBV,        6,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   Q,      0,      7_RBV,  QB0_RBV,        7,        Low,                                                                  High,  NO_ALARM,  MAJOR,  "I/O Intr"}
}

3)ib.substitutions:实例化8个bi记录,用于读取,分别读取一个位到PLC的输出点I0.0~I0.7

file "../../db/bi_bit.template" { pattern
{P,        R,           D,      M,      N,         PORT,         OFFSET,   ZNAM,   ONAM,  ZSV,       OSV,    SCAN}
{SR20SMART:,    BIT:,   I       0       0       IB0_1,     0,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       1       IB0_1,     1,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       2       IB0_1,     2,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       3       IB0_1,     3,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       4       IB0_1,     4,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       5       IB0_1,     5,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       6       IB0_1,     6,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{SR20SMART:,    BIT:,   I       0       7       IB0_1,     7,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
}

4) int.substitutions:实例化2个longin记录,第一个实例将从PLC模拟输入区或V存储区读取的一个字转换成16位有符号数,第二个实例将从PLC模拟输入区或V存储区读取的一个字转换成16位无符号数。

file "../../db/longin_int16.template" { pattern
{P,             R,     T,       M       PORT,         OFFSET,  DATA_TYPE  , SCAN}
{SR20SMART:,    INT,   16,      I0,     VW,             0 , INT16 , "I/O Intr"}
{SR20SMART:,    UINT,  16,      UI0,    VW,             1 , UINT16 , "I/O Intr"}
}

5)into.substitutions:实例化2个longout记录,第一个实例将16位有符号数按字写入到PLC的V存储区,第一个实例将16位无符号数按字写入到PLC的V存储区。

file "../../db/longoutInt16.template" { pattern
{P,             R,      T,      M,      PORT,           OFFSET,         DATA_TYPE}
{SR20SMART:,    INT     16,     IO,     VWO,            0,              INT16}
{SR20SMART:,    UINT    16,     UIO,    VWO,            1,              UINT16}
}

6) float.substitutions:实例化2个ai记录,这两个实例将分别从PLC模拟输入区或V存储区读取的二个字转换成32位浮点数。

file "../../db/float32_in.template" { pattern
{P,             R,      T,      M,          PORT,         OFFSET,  DATA_TYPE , HOPR,   LOPR, ,   PREC ,SCAN}
{SR20SMART:,    FLOAT,   32:    F00             VW,             2 ,FLOAT32_BE ,        1000,    -1000,  ,3 , "I/O Intr"}
{SR20SMART:,    FLOAT,   32:    F01             VW,             4 ,FLOAT32_BE ,        1000,    -1000,  ,3 , "I/O Intr"}
}

7)实例化2个ao记录,这两个实例将分别将32位浮点数按双字写入到PLC的V存储区

file "../../db/float32_out.template" { pattern
{P,             R,      T,      M,          PORT,         OFFSET,  DATA_TYPE , HOPR,   LOPR, ,   PREC}
{SR20SMART:,    FLOAT,   32:    F00             VWO,            2 ,FLOAT32_BE ,        1000,    -1000,  ,3 }
{SR20SMART:,    FLOAT,   32:    F01             VWO,            4 ,FLOAT32_BE ,        1000,    -1000,  ,3 }
}
2) 编辑st.cmd文件:
#!../../bin/linux-x86_64/sr20smart#- You may have to change sr20smart to something else
#- everywhere it appears in this file< envPathscd "${TOP}"## Register all support components
dbLoadDatabase "dbd/sr20smart.dbd"
sr20smart_registerRecordDeviceDriver pdbbasedrvAsynIPPortConfigure("sr20smart","192.168.3.209:6666",0,0,1)
modbusInterposeConfig("sr20smart",1 ,2000,0)# func code = 5 按位写线圈
drvModbusAsynConfigure("QB0",   "sr20smart", 3, 5,  0, 8 , 0, 100, "QB0")
# func code = 1 按位读线圈
drvModbusAsynConfigure("QB0_RBV", "sr20smart", 3, 1,  0, 8 , 0, 200, "QB0_RBV")# func code = 2 按位读取离散输入
drvModbusAsynConfigure("IB0_1", "sr20smart", 3, 2,  0, 8 , 0,   200, "IB0_1")# func code = 3 按字读取保持寄存器
drvModbusAsynConfigure("VW",    "sr20smart", 3, 3,  0, 20  , 0, 200, "VW")# func code = 4 按字读取输入寄存器
drvModbusAsynConfigure("AWI",   "sr20smart", 3, 4,  0, 10  , 0,  200, "AWI")# func code = 6 按字写入保持寄存器
drvModbusAsynConfigure("VWO",   "sr20smart", 3, 6,  0, 20  , 0,  200, "VWO")cd "${TOP}/iocBoot/${IOC}"
dbLoadTemplate("qb.substitutions")
dbLoadTemplate("qb_rbv.substitutions")
dbLoadTemplate("ib.substitutions")dbLoadTemplate("int.substitutions")
dbLoadTemplate("float.substitutions")
dbLoadTemplate("floato.substitutions")
dbLoadTemplate("into.substitutions")iocInit

IOC程序启动以及测试

在IOC启动目录下,程序启动命令:../../bin/linux-aarch64/sr20smart st.cmd

dbl查看所有加载的记录。

root@orangepi3-lts:/usr/local/EPICS/program/sr20smart/iocBoot/iocsr20smart# ../../bin/linux-aarch64/sr20smart st.cmd
#!../../bin/linux-x86_64/sr20smart
...
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-06-25T15:50+0000
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
## Start any sequence programs
#seq sncxxx,"user=blctrl"
epics> dbl
SR20SMART:FLOAT32:_F00
SR20SMART:FLOAT32:_F01
SR20SMART:FLOAT32:_F00O
SR20SMART:FLOAT32:_F01O
SR20SMART:BIT:Q0_0_RBV
SR20SMART:BIT:Q0_1_RBV
SR20SMART:BIT:Q0_2_RBV
SR20SMART:BIT:Q0_3_RBV
SR20SMART:BIT:Q0_4_RBV
SR20SMART:BIT:Q0_5_RBV
SR20SMART:BIT:Q0_6_RBV
SR20SMART:BIT:Q0_7_RBV
SR20SMART:BIT:I0_0
SR20SMART:BIT:I0_1
SR20SMART:BIT:I0_2
SR20SMART:BIT:I0_3
SR20SMART:BIT:I0_4
SR20SMART:BIT:I0_5
SR20SMART:BIT:I0_6
SR20SMART:BIT:I0_7
SR20SMART:BIT:Q0_0
SR20SMART:BIT:Q0_1
SR20SMART:BIT:Q0_2
SR20SMART:BIT:Q0_3
SR20SMART:BIT:Q0_4
SR20SMART:BIT:Q0_5
SR20SMART:BIT:Q0_6
SR20SMART:BIT:Q0_7
SR20SMART:INT16_I0
SR20SMART:UINT16_UI0
SR20SMART:AINT16_I0
SR20SMART:AUINT16_UI0
SR20SMART:INT16_IO
SR20SMART:UINT16_UIO

1)bo记录SR20SMART:BIT:Q0_0 ~ SR20SMART:BIT:Q0_7:用于设置PLC Q0.0~Q0.7。

2)bi记录SR20SMART:BIT:Q0_0_RBV ~ SR20SMART:BIT:Q0_7_RBV:用于读取PLC Q0.0~Q0.7的状态。

3)bi记录SR20SMART:BIT:I0_1~SR20SMART:BIT:I0_7:用于读取PLC I0.0~I0.7的状态。

4) longin记录SR20SMART:INT16_I0和SR20SMART:UINT16_UI0:用于读取V存储区VW2000,VW2002。

5)longin记录SR20SMART:AINT16_I0和SR20SMART:AUINT16_UI0:用于读取模拟量输入寄存器AIW0和AIW2。

6)bo记录SR20SMART:INT16_IO和SR20SMART:UINT16_UIO:用于写入V存储区VW2000,VW2002。

7)ai记录SR20SMART:FLOAT32:_F00和SR20SMART:FLOAT32:_F01用于读取V存储区VD2004和VD2008。

8) ao记录SR20SMART:FLOAT32:_F00O和SR20SMART:FLOAT32:_F01O:写入V存储区VD2004和VD2008。

测试

用STEP7 Micro/Win SMART状态表设置V存储区如下:

用通道访问进行读取:

# VW2000
orangepi@orangepi5:~$ caget SR20SMART:INT16_I0
SR20SMART:INT16_I0             -12345
# VW2002
orangepi@orangepi5:~$ caget SR20SMART:UINT16_UI0
# VD2004
SR20SMART:UINT16_UI0           22222
orangepi@orangepi5:~$ caget SR20SMART:FLOAT32:_F00
SR20SMART:FLOAT32:_F00         3.1415
# VD2008
orangepi@orangepi5:~$ caget SR20SMART:FLOAT32:_F01
SR20SMART:FLOAT32:_F01         0.1111
# AIW0
orangepi@orangepi5:~$ caget SR20SMART:AINT16_I0
SR20SMART:AINT16_I0            -2000
# AIW2
orangepi@orangepi5:~$ caget SR20SMART:AUINT16_UI0
SR20SMART:AUINT16_UI0          2000

用通道访问写更改Q和V存储区:

# Q0.0
orangepi@orangepi5:~$ caput SR20SMART:BIT:Q0_1 0
Old : SR20SMART:BIT:Q0_1             High
New : SR20SMART:BIT:Q0_1             Low
# Q0.1
orangepi@orangepi5:~$ caput SR20SMART:BIT:Q0_0 0
Old : SR20SMART:BIT:Q0_0             High
New : SR20SMART:BIT:Q0_0             Low
# VW2000
orangepi@orangepi5:~$ caput SR20SMART:INT16_IO -6666
Old : SR20SMART:INT16_IO             0
New : SR20SMART:INT16_IO             -6666
# VW2002
orangepi@orangepi5:~$ caput SR20SMART:UINT16_UIO 8888
Old : SR20SMART:UINT16_UIO           0
New : SR20SMART:UINT16_UIO           8888
# VD2004
orangepi@orangepi5:~$ caput SR20SMART:FLOAT32:_F00O 1.2345
Old : SR20SMART:FLOAT32:_F00O        0
New : SR20SMART:FLOAT32:_F00O        1.2345
# VW2008
orangepi@orangepi5:~$ caput SR20SMART:FLOAT32:_F01O 5.4321
Old : SR20SMART:FLOAT32:_F01O        0
New : SR20SMART:FLOAT32:_F01O        5.4321

从STEP7 Micro/Win SMART状态表查看相应的存储区:

结论

通过EPICS modbus模块通过modbus rtu协议能够实现对PLC输入映像区和模拟输入区的读取和对输出映像区和V存储器的读写。

http://www.lryc.cn/news/296081.html

相关文章:

  • 网站被攻击有什么办法呢?
  • VoIP之主备注册服务器机制
  • 【数据分享】1929-2023年全球站点的逐年平均降水量(Shp\Excel\免费获取)
  • uniapp /微信小程序 使用map组件实现手绘地图方案
  • react+antd+CheckableTag实现Tag标签单选或多选功能
  • UUID和雪花(Snowflake)算法该如何选择?
  • Jetpack Compose之进度条介绍(ProgressIndicator)
  • 【Qt基本功修炼】Qt线程的两种运行模式
  • 三、设计模式相关理论总结
  • 鸿蒙 WiFi 连接 流程
  • golang 创建unix socket http服务端
  • annaconda如何切换当前python环境
  • gtkmm 与 Cambalache 与 Gtk::Builder (新手向)_
  • uniapp小程序端使用计算属性动态绑定style样式踩坑
  • 计算机网络概念、组成、功能和分类
  • MyBatisPlus基础操作之增删改查
  • 视频处理学习笔记1:YUYV422、NV12和h264
  • CTFshow web(命令执行29-36)
  • PyTorch深度学习实战(23)——从零开始实现SSD目标检测
  • 【附代码】NumPy加速库NumExpr(大数据)
  • 4、安全开发-Python-蓝队项目流量攻击分析文件动态监控图片隐写技术
  • MySQL 日志管理
  • Python CSV文件读取和写入
  • 如何使用C#调用LabVIEW算法
  • 调用百度文心AI作画API实现中文-图像跨模态生成
  • JAVA SpringBoot中使用redis的事务
  • docker部署自己的网站wordpress
  • 基于ISO13400 (DoIP) 实现车辆刷写
  • Chrome 沙箱逃逸 -- Plaid CTF 2020 mojo
  • 汇编笔记 01