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

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

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

以下是实际连接图:

需要EPICS软件模块如下:
以下步骤描述如何建立这个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
- #include
- #include
- #include
- #include
- #include
-
- 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/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 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
/db - # databases, templates, substitutions like this
- DB += udp6721.proto
- DB += udp6721.db
- DB += udp6721.req
-
- #----------------------------------------------------
- # If
.db template is not named *.template add - #
_template = -
- 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
-
- < 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
_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:SubSleep
9 用CSS查看连接以上记录实例:

可以通过以上图形界面设置直流电源的电压和电流输出。
程序下载:【免费】利德UDP6720系列直流电源IOC程序资源-CSDN文库
- 1.*IDN?
- 查询设备信息。
-
- 2.MEASure:VOLTage?
- MEASure:CURRent?
- MEASure:POWEr?
- 查询回读电压\电流\功率值。
-
- 3.MEASure:ALL?
- 同时查询回读电压、电流、功率值。
-
- 4.[SOURce:]VOLTage <value>
- [SOURce:]CURRent <value>
- 设置输出电压(电流)值,如果已打开保护功能且设置值大于保护值时,设置无效。
-
- 5.[SOURce:]VOLTage:PROTection <value>
- [SOURce:]CURRent:PROTection <value>
- 设置过压(过流)保护功能的保护值。
-
- 6.[SOURce:]VOLTage:PROTection:STATe {ON|OFF}
- [SOURce:]CURRent:PROTection:STATe {ON|OFF}
- 打开或关闭过压(过流)保护功能。
-
- 7.[SOURce:]VOLTage?
- [SOURce:]CURRent?
- 查询输出电压(电流)值。
-
- 8.[SOURce:]VOLTage:PROTection?
- [SOURce:]CURRent:PROTection?
- 查询过压(过流)保护功能的保护值。
-
- 9.[SOURce:]VOLTage:PROTection:STATe?
- [SOURce:]CURRent:PROTection:STATe?
- 查询过压(过流)保护功能的开关状态。返回“ON”或“OFF”。
-
- 10.OUTPut {ON|OFF}
- 打开或关闭输出。
-
- 11.OUTPut?
- 查询输出开关状态。返回“ON”或“OFF”。
-
- 12.OUTPut:CVCC?
- 查询输出恒压恒流状态。返回“CV”或“CC”