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

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

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


需要EPICS软件模块如下:
- base
- asyn
- stream
- 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控制程序实例
本实例程序实现了对优利德UDP6720系列直流电源的网络控制和访问,先在此介绍这个项目中使用的硬件: 1、UDP6721直流电源:受控设备 2、moxa串口服务器5150:将UDP6721直流电源设备串口连接转成网络连接 3、香橙派Zero3:运…...
Unity3D ECS架构适合作为主架构还是局部架构
前言 前言 Unity3D是一款广泛应用于游戏开发的跨平台游戏引擎,提供了丰富的功能和工具来简化游戏开发的过程。而Entity-Component-System(ECS)架构则是一种面向数据的设计模式,它将游戏对象(Entity)分解为…...
从零开始的目标检测和关键点检测(三):训练一个Glue的RTMPose模型
从零开始的目标检测和关键点检测(三):训练一个Glue的RTMPose模型 一、重写config文件二、开始训练三、ncnn部署 从零开始的目标检测和关键点检测(一):用labelme标注数据集 从零开始的目标检测和关键点检测…...
Qt6 中弹出消息框,一段时间后自动退出
以下代码功能,弹出模态消息框,然后,等待 3 秒,消息框自动退出 QMessageBox msgbox;msgbox.setText("sleep 3s");QTimer::singleShot(3000, &msgbox, &QMessageBox::close);msgbox.exec();...
elementUI树节点全选,反选,半选状态
// <template>部分 <div class"check-block"><el-divider></el-divider><el-checkbox :indeterminate"indeterminate" v-model"checkAll" change"handleCheckAllChange">全选</el-checkbox><e…...
Kafka、RabbitMQ、RocketMQ中间件的对比
消息中间件现在有不少,网上很多文章都对其做过对比,在这我对其做进一步总结与整理。 RocketMQ 淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件,使用Mysql作为消息存储媒介,可完全水平扩容,为了进一步降低成…...
Mac 创建并使用 .zshrc 文件
1,打开终端输入指令 touch .zshrc 2,你可能希望将 .bash_profile 文件中的内容复制到 .zshrc 文件中,那建议复制过来。 3,使用 .zshrc 文件 执行以下指令: source .zshrc 注:以后希望使用 .bash_prof…...
Unity3D移动开发如何依据性能选择Shader
前言 在Unity3D移动开发中,选择合适的Shader是非常重要的,它直接影响到游戏的性能和画面效果。本文将介绍如何依据性能选择Shader,并给出相应的技术详解以及代码实现。 对惹,这里有一个游戏开发交流小组,希望大家可以…...
基于stm32F4的智能宠物喂食器的设计:LVGL界面、定时喂食喂水通风
宠物喂食器 一、功能设计二、元器件选型三、UI设计四、原理图设计五、源代码设计六、成品展示 实物链接:https://m.tb.cn/h.5iCUX6H?tkPL65WXCEipQ CZ3457 一、功能设计 1、设计一个触摸屏作为人机交互 2、通过触摸屏设置时间定时喂食喂水通风 3、获取当前水槽的…...
jumpserver堡垒机docker方式安装部署
1、环境要求 请先自行创建 数据库 和 Redis, 版本要求参考上面环境要求说明 mysql>5.7 redis >5.0 2、创建数据库 mysql: create database jumpserver default charset utf8; GRANT ALL PRIVILEGES ON jumpserver.* TO jumpserver% IDENTIFIED BY nu4x599…...
在基于亚马逊云科技的湖仓一体架构上构建数据血缘的探索和实践
背景介绍 随着大数据技术的进步,企业和组织越来越依赖数据驱动的决策。数据的质量、来源及其流动性因此显得非常关键。数据血缘分析为我们提供了一种追踪数据从起点到终点的方法,有助于理解数据如何被转换和消费,同时对数据治理和合规性起到关…...
VScode clangd 插件浏览 linux 源码
文章目录 VScode clangd 插件浏览 linux 源码clangd 安装与配置VScode 插件安装clangd 安装方法一方法二 clangd 配置 cmake 生成bear 生成 compile_commands.json触发 clangd linux 内核脚本生成 compile_commands.json 文件三种方式对比 VScode clangd 插件浏览 linux 源码 …...
GZ035 5G组网与运维赛题第8套
2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项(高职组) 赛题第8套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通(35分) 子任务1:5G公共网络部署与调试(15分) 子…...
《golang设计模式》第三部分·行为型模式-02-命令模式(Command)
文章目录 1. 概述1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1. 概述 命令模式(Command)将类的业务行为以对象的方式封装,以便实现行为的参数化、撤销或重做等需求。 非命令模式的困惑: 类的行为在运行时是以实例方法…...
【linux进程控制(一)】进程终止--如何干掉一个进程?
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:Linux从入门到精通⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你学更多操作系统知识 🔝🔝 进程终止 1. 前言2. 文章整体…...
言情小说怎么推广?如何推广网络小说?
网络小说是一种文学形式,它的受众群体相当广泛,其实也面临着很强的竞争,因此,网络推广是小说宣传的一项重要工作,这里小马识途营销顾问就分享一下小说推广的渠道和方法。 1、软文推广 在推广小说的过程中,…...
TensorFlow 的应用场景有哪些
TensorFlow是一个开源的人工智能框架,由Google公司开发。它是一个强大的工具,可以用于数值计算、机器学习和深度学习等领域,具有灵活性、可扩展性、可移植性等特点。 TensorFlow的基本概念包括: Tensor:Tensor是Tens…...
JAVA提取嵌套夹带文件之Apache Tika
目录结构 前言tika简介Tika支持的文件格式MAVEN依赖JAVA程序JAVA测试程序测试文件测试结果部分文件提取失败参考连接 前言 Apache Tika提取文件整理如下,如有特定的文件需要提取可以先参照【部分文件提取失败】章节对照,以免浪费您的宝贵时间,…...
SSL数字证书服务
SSL/TLS 证书允许Web浏览器使用安全套接字层/传输层安全 (SSL/TLS) 协议识别并建立与网站的加密网络连接。 SSL数字证书主要功能 SSL证书在浏览器或用户计算机与服务器或网站之间建立加密连接。这种连接可以保护传输中的敏感数据免遭非授权方的拦截,从而使在线交易…...
浅谈安科瑞直流电表在荷兰光伏充电桩系统中的应用
摘要:本文介绍了安科瑞直流电表在荷兰光伏充电桩系统中的应用。主要用于充电桩的电流电压电能的计量。 Abstract: This article introduces the application of Acrel DC meters in PV charging pile system in Netherlands.The device is measuring current,volt…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
