Example of IOC control program for DC power supply based on EPICS stream module

This example program implements network control and access to the UDP6720 series DC power supply. First, let’s introduce the hardware used in this project:

1. UDP6721 DC power supply: controlled equipment

2. moxa serial port server 5150: converts the UDP6721 DC power supply device serial port connection into a network connection

3. Orange Pie Zero3: Run the IOC program.

Here is the actual connection diagram:

The required EPICS software modules are as follows:

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

The following steps describe the process of setting up this IOC program:

1. Use the tool command makeBaseApp.pl to build the IOC program architecture. The program architecture is as follows:

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

2. Modify the confiure/RELEASE file and add the path where the dependent modules are located:

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

3. Enter the udp6721App/src/ directory and write the source code of the function that needs to be called in the sub record and the corresponding dbd file:

// 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)\
", precord->name, (void *)precord);
        }
        printf("subInit was called\
");
        return 0;
}

static long mySubProcess(struct subRecord * record)
{
        if(mySubDebug)
        {
                printf("Record %s called mySubProcess(%p)\
", precord->name,(void *)precord);
        }
        epicsThreadSleep(precord->val);
        return 0;
}
# subRecordSleepSupport.dbd
variable(mySubDebug)
function(mySubInit)
function(mySubProcess)

Modify the Makefile in this directory to specify the required database definition files, linked library files, and source files that need to be compiled:

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. Enter udp6721App/Db/ to write the protocol file, database instance file and req file for data saving:

1) Database instance file:

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 Current")
   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")
}

Agreement document:

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}";
}

Store configuration file:

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

Edit the Makefile in the same path and add the following:

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. Switch to the top-level directory and execute the make command to compile.

6 Enter the startup directory iocBoot/iocudp6721/:

Create two directories, autosave and req, and add an auto_settings.req file under req with the following content:

file udp6721.req P=$(P)

7 Edit the startup file st.cmd with the following content:

#!../../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

#IP address and connection port of UDP6721 device
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/")

# Specify the directory where you want the .sav file to be written to by calling the set_savefile_path function.
set_savefile_path("$(TOP)/iocBoot/$(IOC)/autosave/")

# Use set_pass<N>_restoreFile() function
# Specify which save files should be restored before recording initialization (pass 0), and which save files should be restored after recording initialization (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 Start this IOC and use dbl to view the loaded record instance:

 ../../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 Use CSS to view the above record example:

The voltage and current output of the DC power supply can be set through the above graphical interface.

Program download: [Free] Lid UDP6720 series DC power supply IOC program resources-CSDN library

The following is the programming manual for this device:

1.*IDN?
Query device information.

2.MEASure:VOLTage?
MEASure:CURRent?
MEASure:POWEr?
Query the readback voltage\current\power value.

3.MEASure:ALL?
At the same time, query the readback voltage, current, and power values.

4.[SOURce:]VOLTage <value>
[SOURce:]CURRent <value>
Set the output voltage (current) value. If the protection function is turned on and the setting value is greater than the protection value, the setting is invalid.

5.[SOURce:]VOLTage:PROTection <value>
[SOURce:]CURRent:PROTection <value>
Set the protection value of overvoltage (overcurrent) protection function.

6.[SOURce:]VOLTage:PROTection:STATe {ON|OFF}
[SOURce:]CURRent:PROTection:STATe {ON|OFF}
Turn on or off the overvoltage (overcurrent) protection function.

7.[SOURce:]VOLTage?
[SOURce:]CURRent?
Query the output voltage (current) value.

8.[SOURce:]VOLTage:PROTection?
[SOURce:]CURRent:PROTection?
Query the protection value of overvoltage (overcurrent) protection function.

9.[SOURce:]VOLTage:PROTection:STATe?
[SOURce:]CURRent:PROTection:STATe?
Query the switch status of the overvoltage (overcurrent) protection function. Returns "ON" or "OFF".

10.OUTPut {ON|OFF}
Turn the output on or off.

11.OUTPut?
Query the output switch status. Returns "ON" or "OFF".

12.OUTPut:CVCC?
Query the output constant voltage and constant current status. Return "CV" or "CC"

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. C Skill Tree Home Page Overview 193997 people are learning the system