EPICS modbus 模块数字量读写练习

2023-12-07 11:45

本文主要是介绍EPICS modbus 模块数字量读写练习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文使用modbus slave软件模拟一个受控的modbus设备,此模拟设备提供如下功能:

1、线圈1,起始地址为0,数量为8,软件设置如下(功能码1):

2、线圈2,起始地址为8,数量为8,软件设置如下(功能码1):

3、离散输入,起始地址为0,数量为8,软件设置如下(功能码2):

使用EPICS Modbus模块对以上modbus设备进行读写,过程如下:

使用makeBaseApp.pl构建IOC程序框架,并且在configure/RELEASE中指定base所在路径以及所需要的支持模块modbus路径。在程序的src路径下Makefile中指定要添加的数据块定义文件和库文件。

在程序的Db目录下,编写如下模板文件:

1) bo_bit.template:用于写modbus设备的单线圈

record(bo,"$(P)$(R)") {field(DTYP,"asynUInt32Digital")field(OUT,"@asynMask($(PORT) $(OFFSET) 0x1)")field(ZNAM,"$(ZNAM)")field(ONAM,"$(ONAM)")
}

2)bi_bit.template:用于读modbus设备的线圈状态或者离散输入状态

record(bi,"$(P)$(R)") {field(DTYP,"asynUInt32Digital")field(INP,"@asynMask($(PORT) $(OFFSET) 0x1)")field(SCAN,"$(SCAN)")field(ZNAM,"$(ZNAM)")field(ONAM,"$(ONAM)")field(ZSV,"$(ZSV)")field(OSV,"$(OSV)")
}

3)wfo_bit.template:用于一次写modbus设备的多个线圈

record(waveform,"$(P)$(R)") {field(DTYP,"asynInt32ArrayOut")field(INP,"@asyn($(PORT) $(OFFSET=0))MODBUS_DATA")field(FTVL,"ULONG")field(NELM,"$(NELM)")
}

4) wfi_bit.template:用于读取modbus设备多个线圈状态或这多个离散输入状态。

record(waveform,"$(P)$(R)") {field(DTYP,"asynInt32ArrayIn")field(INP,"@asyn($(PORT) $(OFFSET=0))MODBUS_DATA")field(SCAN,"$(SCAN)")field(FTVL,"ULONG")field(NELM,"$(NELM)")
}

将以上模板文件添加到相同路径下Makefile文件中:

...
DB +=  bo_bit.template
DB +=  bi_bit.template
DB +=  wfo_bit.template
DB +=  wfi_bit.template
...

回到IOC顶层目录,执行make命令,编译这个IOC。

进入到启动目录iocBoot/iocmodbusbit中,编写记录实例化文件:

1)coil_bo_bits.substitutions:用于实例化8个bo记录,每个bo写modbus设备1个线圈。

file "../../db/bo_bit.template" { pattern
{P,        R,             PORT,       OFFSET,   ZNAM,   ONAM}
{COUT:,    CO0B,     C0_Out_Bits,     0,        Low,    High}
{COUT:,    CO1B,     C0_Out_Bits,     1,        Low,    High}
{COUT:,    CO2B,     C0_Out_Bits,     2,        Low,    High}
{COUT:,    CO3B,     C0_Out_Bits,     3,        Low,    High}
{COUT:,    CO4B,     C0_Out_Bits,     4,        Low,    High}
{COUT:,    CO5B,     C0_Out_Bits,     5,        Low,    High}
{COUT:,    CO6B,     C0_Out_Bits,     6,        Low,    High}
{COUT:,    CO7B,     C0_Out_Bits,     7,        Low,    High}
}

2)coil_bi_bits.substitutions:用于实例化16个bi记录,每个bi读取modbus设备1个线圈状态。

file "../../db/bi_bit.template" { pattern
{P,        R,          PORT,         OFFSET,   ZNAM,   ONAM,  ZSV,       OSV,    SCAN}
{CIN:,    CI00B,     C0_In_Bits,     0,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI01B,     C0_In_Bits,     1,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI02B,     C0_In_Bits,     2,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI03B,     C0_In_Bits,     3,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI04B,     C0_In_Bits,     4,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI05B,     C0_In_Bits,     5,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI06B,     C0_In_Bits,     6,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI07B,     C0_In_Bits,     7,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI08B,     C1_In_Bits,     0,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI09B,     C1_In_Bits,     1,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI10B,     C1_In_Bits,     2,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI11B,     C1_In_Bits,     3,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI12B,     C1_In_Bits,     4,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI13B,     C1_In_Bits,     5,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI14B,     C1_In_Bits,     6,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{CIN:,    CI15B,     C1_In_Bits,     7,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
}

3)dis_bi_bits.substitutions:用于实例化8个bi记录,每个bi取modbus设备离散输入状态。

file "../../db/bi_bit.template" { pattern
{P,        R,          PORT,         OFFSET,   ZNAM,   ONAM,  ZSV,       OSV,    SCAN}
{DIN:,    DI00B,     D0_In_Bits,     0,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI01B,     D0_In_Bits,     1,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI02B,     D0_In_Bits,     2,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI03B,     D0_In_Bits,     3,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI04B,     D0_In_Bits,     4,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI05B,     D0_In_Bits,     5,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI06B,     D0_In_Bits,     6,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
{DIN:,    DI07B,     D0_In_Bits,     7,        Low,    High,  NO_ALARM,  MAJOR,  "I/O Intr"}
}

4)coil_wfo_bits.substitutions:实例化一个waveform记录,用于一次最多设置modbus设备8个线圈。

file "../../db/wfo_bit.template" { pattern
{P,        R,             PORT,       OFFSET,   NELM}
{COUT:,    WFO,            C0_Out_WF,         0,        8}
}

5) dis_wfi_bits.substitutions:实例化一个waveform记录,用于读取modbus设备8个离散输入的状态。

file "../../db/wfi_bit.template" { pattern
{P,        R,          PORT,         OFFSET,   , NELM ,    SCAN}
{DIN:,    WFI,         D0_In_Bits,     8,       8,  "I/O Intr"}
}

编写启动脚本st.cmd:

#!../../bin/linux-x86_64/modbuspoll#- You may have to change modbuspoll to something else
#- everywhere it appears in this file< envPathscd "${TOP}"## Register all support components
dbLoadDatabase "dbd/modbuspoll.dbd"
modbuspoll_registerRecordDeviceDriver pdbbase# 连接modbus设备
drvAsynIPPortConfigure("mpoll","192.168.3.15:502",0,0,1)
# 使用modbus tcp类型
modbusInterposeConfig("mpoll", 0 ,2000,0)# 用于写线圈,起始地址0,每次写1个,一共写8次
drvModbusAsynConfigure("C0_Out_Bits", "mpoll", 0, 5,  0, 8, 0,  100, "mpoll")
# 用于写线圈,起始地址8,一次写8个线圈
drvModbusAsynConfigure("C0_Out_WF",   "mpoll", 0, 15, 8, 8, 0,  100, "mpoll")# 用于读线圈,起始地址0,每次读取一个,一共读8次,轮询时间为500ms
drvModbusAsynConfigure("C0_In_Bits",  "mpoll", 0, 1,  0, 8, 0,  500, "mpoll")
# 用于读线圈,起始地址8,每次读取一个,一共读8次,轮询时间为500ms
drvModbusAsynConfigure("C1_In_Bits",  "mpoll", 0, 1,  8, 8, 0,  500, "mpoll")# 用于读取离散输入,起始地址0,每次读取一个,读取8次,轮询时间100ms
drvModbusAsynConfigure("D0_In_Bits", "mpoll",  0,  2, 0, 8, 0,  100, "mpoll")cd "${TOP}/iocBoot/${IOC}"
# 加载实例化记录
# 写线圈
dbLoadTemplate("coil_bo_bits.substitutions")
# 写线圈
dbLoadTemplate("coil_wfo_bits.substitutions")
# 读线圈
dbLoadTemplate("coil_bi_bits.substitutions")
# 读离散输入
dbLoadTemplate("dis_bi_bits.substitutions")
# 读离散输入
dbLoadTemplate("dis_wfi_bits.substitutions")iocInit

启动这个IOC:

[root@localhost iocmodbusbit]# ../../bin/linux-x86_64/modbuspoll st.cmd
#!../../bin/linux-x86_64/modbuspoll
...
# bit write
drvModbusAsynConfigure("C0_Out_Bits", "mpoll", 0, 5,  0, 8, 0,  100, "mpoll")
# bit array write
drvModbusAsynConfigure("C0_Out_WF",   "mpoll", 0, 15, 8, 8, 0,  100, "mpoll")
# Coil bit Read
drvModbusAsynConfigure("C0_In_Bits",  "mpoll", 0, 1,  0, 8, 0,  500, "mpoll")
drvModbusAsynConfigure("C1_In_Bits",  "mpoll", 0, 1,  8, 8, 0,  500, "mpoll")
# Discrete bit Read
drvModbusAsynConfigure("D0_In_Bits", "mpoll",  0,  2, 0, 8, 0,  100, "mpoll")
cd "/usr/local/EPICS/program/modbuspoll/iocBoot/iocmodbusbit"
dbLoadTemplate("coil_bo_bits.substitutions")
dbLoadTemplate("coil_wfo_bits.substitutions")
dbLoadTemplate("coil_bi_bits.substitutions")
dbLoadTemplate("dis_bi_bits.substitutions")
dbLoadTemplate("dis_wfi_bits.substitutions")
iocInit
Starting iocInit
...
## Start any sequence programs
#seq sncxxx,"user=blctrl"
epics> dbl
COUT:CO0B
COUT:CO1B
COUT:CO2B
COUT:CO3B
COUT:CO4B
COUT:CO5B
COUT:CO6B
COUT:CO7B
COUT:WFO
DIN:WFI
CIN:CI00B
CIN:CI01B
CIN:CI02B
CIN:CI03B
CIN:CI04B
CIN:CI05B
CIN:CI06B
CIN:CI07B
CIN:CI08B
CIN:CI09B
CIN:CI10B
CIN:CI11B
CIN:CI12B
CIN:CI13B
CIN:CI14B
CIN:CI15B
DIN:DI00B
DIN:DI01B
DIN:DI02B
DIN:DI03B
DIN:DI04B
DIN:DI05B
DIN:DI06B
DIN:DI07B

1) COUT:CO0B~COUT:CO7B:bo记录,每个bo记录用于写一个线圈。

2)COUT:WF:waveform记录,用于一次写8个线圈。

3)DIN:WFI:waveform记录,用于读取8个离散输入。

4)CIN:CI00B~CIN:CI15B:bi记录,每个bi记录读取一个线圈状态。

5)DIN:DI00B~DIN:DI00B,bi记录,每个bi记录读取一个离散输入。

用css绘制控制界面,进行记录连接后,如下所示:

1)顶层窗口区域:Coil Out按钮写线圈,Coil In回读线圈状态

2)中间窗口区域:Coil Array Out可以一次最多写8个线圈,Coil In回读线圈状态。

3)底层窗口区域:用于读取离散输入,离散输入状态需要在modbus slave窗口中设置 ,Discrete Bit in 和Discrete Bit Array In都回读modbus slave窗口中设置的离散输入的状态。

这篇关于EPICS modbus 模块数字量读写练习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/465745

相关文章

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

C#读写文本文件的多种方式详解

《C#读写文本文件的多种方式详解》这篇文章主要为大家详细介绍了C#中各种常用的文件读写方式,包括文本文件,二进制文件、CSV文件、JSON文件等,有需要的小伙伴可以参考一下... 目录一、文本文件读写1. 使用 File 类的静态方法2. 使用 StreamReader 和 StreamWriter二、二进

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

MySQL主从复制与读写分离的用法解读

《MySQL主从复制与读写分离的用法解读》:本文主要介绍MySQL主从复制与读写分离的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、主从复制mysql主从复制原理实验案例二、读写分离实验案例安装并配置mycat 软件设置mycat读写分离验证mycat读

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

ShardingSphere之读写分离方式

《ShardingSphere之读写分离方式》:本文主要介绍ShardingSphere之读写分离方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录ShardingSphere-读写分离读写分离mysql主从集群创建 user 表主节点执行见表语句项目代码读写分

Python logging模块使用示例详解

《Pythonlogging模块使用示例详解》Python的logging模块是一个灵活且强大的日志记录工具,广泛应用于应用程序的调试、运行监控和问题排查,下面给大家介绍Pythonlogging模... 目录一、为什么使用 logging 模块?二、核心组件三、日志级别四、基本使用步骤五、快速配置(bas

Python datetime 模块概述及应用场景

《Pythondatetime模块概述及应用场景》Python的datetime模块是标准库中用于处理日期和时间的核心模块,本文给大家介绍Pythondatetime模块概述及应用场景,感兴趣的朋... 目录一、python datetime 模块概述二、datetime 模块核心类解析三、日期时间格式化与

Python如何调用指定路径的模块

《Python如何调用指定路径的模块》要在Python中调用指定路径的模块,可以使用sys.path.append,importlib.util.spec_from_file_location和exe... 目录一、sys.path.append() 方法1. 方法简介2. 使用示例3. 注意事项二、imp