基于EPICS stream模块的直流电源的IOC控制程序实例

2023-11-02 13:04

本文主要是介绍基于EPICS stream模块的直流电源的IOC控制程序实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本实例程序实现了对优利德UDP6720系列直流电源的网络控制和访问,先在此介绍这个项目中使用的硬件:

1、UDP6721直流电源:受控设备

2、moxa串口服务器5150:将UDP6721直流电源设备串口连接转成网络连接

3、香橙派Zero3:运行IOC程序。

 需要EPICS软件模块如下:

  1. base
  2. asyn
  3. stream
  4. autosave

以下步骤描述如何建立这个IOC程序的过程:

1、使用工具命令makeBaseApp.pl构建IOC程序架构,程序架构如下:

root@orangepizero3:/usr/local/EPICS/program/udp6721# ls
bin  configure  db  dbd  document  iocBoot  lib  Makefile  udp6721App

2、修改confiure/RELEASE文件,增加依赖模块所在的路径:

...
SUPPORT=/usr/local/EPICS/synApps/support
ASYN=$(SUPPORT)/asyn
STREAM=$(SUPPORT)/stream/streamDevice
AUTOSAVE=$(SUPPORT)/autosave
...

3、进入udp6721App/src/目录下,编写sub记录中所需要调用函数的源代码以及相应的dbd文件:

// ubRecordSleep.c
#include <stdio.h>
#include <dbDefs.h>
#include <epicsThread.h>
#include <registryFunction.h>
#include <subRecord.h>
#include <epicsExport.h>int mySubDebug = 0;static long mySubInit(struct subRecord *precord)
{if (mySubDebug){printf("Record %s called mySubInit(%p)\n", precord->name, (void *)precord);}printf("subInit was called\n");return 0;
}static long mySubProcess(struct subRecord * precord)
{if(mySubDebug){printf("Record %s called mySubProcess(%p)\n", precord->name,(void *)precord);}epicsThreadSleep(precord->val);return 0;
}
# subRecordSleepSupport.dbd
variable(mySubDebug)
function(mySubInit)
function(mySubProcess)

修改这个目录中的Makefile文件,指明所需要的数据库定义文件以及链接的库文件以及需要编译的源文件:

TOP=../..include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================#=============================
# Build the IOC applicationPROD_IOC = udp6721
# udp6721.dbd will be created and installed
DBD += udp6721.dbd# udp6721.dbd will be made up from these files:
udp6721_DBD += base.dbd
udp6721_DBD += asyn.dbd
udp6721_DBD += stream.dbd
udp6721_DBD += subRecordSleepSupport.dbd
udp6721_DBD += drvAsynIPPort.dbd
udp6721_DBD += asSupport.dbd# Include dbd files from all support applications:
#udp6721_DBD += xxx.dbd# Add all the support libraries needed by this IOC
udp6721_LIBS += asyn
udp6721_LIBS += stream
udp6721_LIBS += autosaveudp6721_SRCS += subRecordSleep.c
# udp6721_registerRecordDeviceDriver.cpp derives from udp6721.dbd
udp6721_SRCS += udp6721_registerRecordDeviceDriver.cpp# Build the main IOC entry point on workstation OSs.
udp6721_SRCS_DEFAULT += udp6721Main.cpp
udp6721_SRCS_vxWorks += -nil-# Add support from base/src/vxWorks if needed
#udp6721_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary# Finally link to the EPICS Base libraries
udp6721_LIBS += $(EPICS_BASE_IOC_LIBS)#===========================include $(TOP)/configure/RULES

4、进入udp6721App/Db/下编写协议文件,数据库实例文件和用于数据保存的req文件:

1)数据库实例文件:

record(stringin, "$(P)DeviceInfo")
{field (DESC, "Read Device Info of PS1")field (DTYP, "stream")field (INP,  "@udp6721.proto getIDNInfo PS1")field (PINI, "YES")field (SCAN, "10 second")
}record(bo, "$(P)OnOff")
{field (DESC, "Turn On/Off the Device")field (DTYP, "stream")field (OUT,  "@udp6721.proto setSwitch PS1")field (ZNAM, "OFF")field (ONAM, "ON")field (PINI, "YES")field (FLNK, "$(P)OnOff_RBV")
}record(bi, "$(P)OnOff_RBV")
{field (DESC, "The Status of  the Device")field (DTYP, "stream")field (INP,  "@udp6721.proto getSwitch PS1")field (ZNAM, "OFF")field (ONAM, "ON")field (PINI, "YES")field (SCAN, "Passive")
}record(ai, "$(P)Voltage_M")
{field (DESC, "Output Voltage")field (DTYP, "stream")field (INP,  "@udp6721.proto measureVoltage PS1")field (PREC, "2")field (PINI, "YES")
}record(ai, "$(P)Current_M")
{field (DESC, "Output Current")field (DTYP, "stream")field (INP,  "@udp6721.proto measureCurrent PS1")field (PREC, "3")field (SCAN, "I/O Intr")
}record(ai, "$(P)Power_M")
{field (DESC, "Output Power")field (DTYP, "stream")field (INP,  "@udp6721.proto measurePower PS1")field (PREC, "4")field (SCAN, "I/O Intr")
}record(bi, "$(P)CVCC_RBV")
{field (DESC, "Device Output Mode CV/CC")field (DTYP, "stream")field (INP,  "@udp6721.proto getCVCC PS1")field (ZNAM, "CV")field (ONAM, "CC")field (SCAN, "1 second")field (PINI, "YES")
}record(ai, "$(P)Voltage_RBV")
{field (DESC, "Output Voltage")field (DTYP, "stream")field (INP,  "@udp6721.proto getVoltage PS1")field (PREC, "2")field (PINI, "YES")
}record(ai, "$(P)Current_RBV")
{field (DESC, "Output Current")field (DTYP, "stream")field (INP,  "@udp6721.proto getCurrent PS1")field (PREC, "3")field (PINI, "YES")
}record(ao, "$(P)SetVoltage")
{field (DESC, "Output Voltage")field (DTYP, "stream")field (OUT,  "@udp6721.proto setVoltage PS1")field (PREC, "2")field (FLNK, "$(P)SubSleep")
}record(ao, "$(P)SetCurrent")
{field (DESC, "Output Current")field (DTYP, "stream")field (OUT,  "@udp6721.proto setCurrent PS1")field (PREC, "3")field (FLNK, "$(P)SubSleep")
}record(fanout, "$(P)Fanout")
{field(SELM,"All")field(SCAN, "Passive")field(LNK0, "$(P)Voltage_M")field(LNK1, "$(P)Voltage_RBV")field(LNK2, "$(P)Current_RBV")
}record(sub,"$(P)SubSleep")
{field(INAM,"mySubInit")field(SNAM,"mySubProcess")field(VAL, "0.8")field(FLNK, "$(P)Fanout.PROC")
}record(ao, "$(P)SetVProtectValue")
{field (DESC, "Set Protect Voltage")field (DTYP, "stream")field (OUT,  "@udp6721.proto setVProtectValue PS1")field (PREC, "2")field (FLNK, "$(P)VProtectValue_RBV")
}record(ai, "$(P)VProtectValue_RBV")
{field (DESC, "Protect Voltage")field (DTYP, "stream")field (INP,  "@udp6721.proto getVProtectValue PS1")field (PREC, "2")field (PINI, "YES")
}record(ao, "$(P)SetCProtectValue")
{field (DESC, "Set Protect Currrent")field (DTYP, "stream")field (OUT,  "@udp6721.proto setCProtectValue PS1")field (PREC, "3")field (FLNK, "$(P)CProtectValue_RBV")
}record(ai, "$(P)CProtectValue_RBV")
{field (DESC, "Protect Current")field (DTYP, "stream")field (INP,  "@udp6721.proto getCProtectValue PS1")field (PREC, "3")field (PINI, "YES")
}record(bo, "$(P)OnOffVProtectState")
{field (DESC, "Set Volt Protect State")field (DTYP, "stream")field (ZNAM, "ON")field (ONAM, "OFF")field (OUT,  "@udp6721.proto switchVProtectState PS1")field (FLNK, "$(P)OnOffVProtectState_RBV")
}record(bi, "$(P)OnOffVProtectState_RBV")
{field (DESC, "Volt Protect State")field (DTYP, "stream")field (ZNAM, "ON")field (ONAM, "OFF")field (INP,  "@udp6721.proto getVProtectState PS1")field (PINI, "YES")
}record(bo, "$(P)OnOffCProtectState")
{field (DESC, "Set Current Protect State")field (DTYP, "stream")field (ZNAM, "ON")field (ONAM, "OFF")field (OUT,  "@udp6721.proto switchCProtectState PS1")field (FLNK, "$(P)OnOffCProtectState_RBV")
}record(bi, "$(P)OnOffCProtectState_RBV")
{field (DESC, "Current Protect State")field (DTYP, "stream")field (ZNAM, "ON")field (ONAM, "OFF")field (INP,  "@udp6721.proto getCProtectState PS1")field (PINI, "YES")
}record(stringout, "$(P)SetRemote")
{field (DESC, "Current Protect State")field (DTYP, "stream")field (OUT,  "@udp6721.proto setRemote PS1")field (FLNK, "$(P)Remote_RBV")
}record(bi, "$(P)Remote_RBV")
{field (DESC, "Remote State")field (DTYP, "stream")field (INP,  "@udp6721.proto getRemote PS1")field (ZNAM, "YES")field (ONAM, "NO")field (PINI, "YES")
}

协议文件:

Terminator = LF;getIDNInfo {out "*IDN?";in "Uni-Trend,%s";
}# Switch is an enum, either OFF or ON
# use bi and bo recordsgetSwitch {out "OUTPUT?"; in "%{OFF|ON}";
}setSwitch {out "OUTPUT %{OFF|ON}";@init { getSwitch; }
}measureVoltage {out "MEASure:ALL?";in  "%f,%*f,%*f";
}measureCurrent {in  "%*f,%f,%*f";
}measurePower {in "%*f,%*f,%f";
}getCVCC {out "OUTPUT:CVCC?"; in "%{CV|CC}";
}setVoltage {out "VOLTage %.2f";
}getVoltage {out "VOLTage?";in "%f";
}setCurrent {out "CURRent %.3f";
}getCurrent {out "CURRent?";in "%f";
}setVProtectValue {out "VOLTage:PROTection %.2f";
}getVProtectValue {out "VOLTage:PROTection?";in "%f";
}setCProtectValue {out "CURRent:PROTection %.3f";
}getCProtectValue {out "CURRent:PROTection?";in "%f";
}switchVProtectState {out "VOLTage:PROTection:STATe %{ON|OFF}";
}getVProtectState {out "VOLTage:PROTection:STATe?";in "%{ON|OFF}";
}switchCProtectState {out "CURRent:PROTection:STATe {ON|OFF}";
}getCProtectState {out "CURRent:PROTection:STATe?";in "%{ON|OFF}";
}setRemote {out "SYSTem:REMote";
}getRemote {out "SYSTem:REMote?";in "%{YES|NO}";
}

存储配置文件:

$(P)SetVoltage
$(P)SetCurrent
$(P)SetVProtectValue
$(P)SetCProtectValue
$(P)SetRemote

编辑相同路径下的Makefile文件,添加以下:

TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE#----------------------------------------------------
# Create and install (or just install) into <top>/db
# databases, templates, substitutions like this
DB += udp6721.proto
DB += udp6721.db
DB += udp6721.req#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_template = <templatename>include $(TOP)/configure/RULES

5 切换到顶层目录,执行make命令,进行编译。

6 进入启动目录 iocBoot/iocudp6721/:

创建两个目录autosave和req,并且在req下添加一个auto_settings.req文件,内容如下:

file udp6721.req  P=$(P)

7 编辑启动文件st.cmd,内容如下:

#!../../bin/linux-aarch64/udp6721#- You may have to change udp6721 to something else
#- everywhere it appears in this file< envPathscd "${TOP}"## Register all support components
dbLoadDatabase "dbd/udp6721.dbd"
udp6721_registerRecordDeviceDriver pdbbasedrvAsynIPPortConfigure("PS1", "192.168.3.101:4001", 0, 0 ,1)## Load record instances
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/db/")
dbLoadRecords("db/udp6721.db","P=UDP6721:")set_requestfile_path("$(TOP)/db")
set_requestfile_path("$(TOP)/iocBoot/$(IOC)/req/")# 通过调用set_savefile_path函数指定你想要.sav文件被写到哪个目录中。
set_savefile_path("$(TOP)/iocBoot/$(IOC)/autosave/")# 使用set_pass<N>_restoreFile()函数
# 指定哪些save文件要在记录初始化前(pass 0)前被恢复,以及哪些save文件在记录初始化后(pass 1)被恢复
set_pass1_restoreFile("auto_settings.sav")save_restoreSet_numSeqFiles(3)
save_restoreSet_SeqPeriodInSeconds(600)
save_restoreSet_RetrySeconds(60)
save_restoreSet_CAReconnect(1)
save_restoreSet_CallbackTimeout(-1)cd "${TOP}/iocBoot/${IOC}"
iocInitcreate_monitor_set("auto_settings.req",5,"P=UDP6721:")

8 启动这个IOC,用dbl查看加载的记录实例:

 ../../bin/linux-aarch64/udp6721 st.cmd
epics> dbl
UDP6721:Voltage_M
UDP6721:Current_M
UDP6721:Power_M
UDP6721:Voltage_RBV
UDP6721:Current_RBV
UDP6721:VProtectValue_RBV
UDP6721:CProtectValue_RBV
UDP6721:SetVoltage
UDP6721:SetCurrent
UDP6721:SetVProtectValue
UDP6721:SetCProtectValue
UDP6721:OnOff_RBV
UDP6721:CVCC_RBV
UDP6721:OnOffVProtectState_RBV
UDP6721:OnOffCProtectState_RBV
UDP6721:Remote_RBV
UDP6721:OnOff
UDP6721:OnOffVProtectState
UDP6721:OnOffCProtectState
UDP6721:Fanout
UDP6721:DeviceInfo
UDP6721:SetRemote
UDP6721:SubSleep

9 用CSS查看连接以上记录实例:

可以通过以上图形界面设置直流电源的电压和电流输出。 

这篇关于基于EPICS stream模块的直流电源的IOC控制程序实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

Jenkins构建Maven聚合工程,指定构建子模块

一、设置单独编译构建子模块 配置: 1、Root POM指向父pom.xml 2、Goals and options指定构建模块的参数: mvn -pl project1/project1-son -am clean package 单独构建project1-son项目以及它所依赖的其它项目。 说明: mvn clean package -pl 父级模块名/子模块名 -am参数

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群 华为云最近正在举办828 B2B企业节,Flexus X实例的促销力度非常大,特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求,一定不要错过这个机会。赶紧去看看吧! 什么是华为云Flexus X实例 华为云Flexus X实例云服务是新一代开箱即用、体

JavaSE(十三)——函数式编程(Lambda表达式、方法引用、Stream流)

函数式编程 函数式编程 是 Java 8 引入的一个重要特性,它允许开发者以函数作为一等公民(first-class citizens)的方式编程,即函数可以作为参数传递给其他函数,也可以作为返回值。 这极大地提高了代码的可读性、可维护性和复用性。函数式编程的核心概念包括高阶函数、Lambda 表达式、函数式接口、流(Streams)和 Optional 类等。 函数式编程的核心是Lambda