基于EPICSstream模块的直流电源的IOC控制程序实例
- 游戏开发
- 2025-08-14 21:18:01

本实例程序实现了对优利德UDP6720系列直流电源的网络控制和访问,先在此介绍这个项目中使用的硬件:
1、UDP6721直流电源:受控设备
2、moxa串口服务器5150:将UDP6721直流电源设备串口连接转成网络连接
3、香橙派Zero3:运行IOC程序。
以下是实际连接图:
需要EPICS软件模块如下:
baseasynstreamautosave以下步骤描述如何建立这个IOC程序的过程:
1、使用工具命令makeBaseApp.pl构建IOC程序架构,程序架构如下:
root@orangepizero3:/usr/local/EPICS/program/udp6721# ls bin configure db dbd document iocBoot lib Makefile udp6721App2、修改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 application PROD_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 += autosave udp6721_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/RULES4、进入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 records getSwitch { 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/RULES5 切换到顶层目录,执行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 < envPaths cd "${TOP}" ## Register all support components dbLoadDatabase "dbd/udp6721.dbd" udp6721_registerRecordDeviceDriver pdbbase # UDP6721设备的IP地址和连接端口 drvAsynIPPortConfigure("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}" iocInit create_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:SubSleep9 用CSS查看连接以上记录实例:
可以通过以上图形界面设置直流电源的电压和电流输出。
基于EPICSstream模块的直流电源的IOC控制程序实例由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“基于EPICSstream模块的直流电源的IOC控制程序实例”