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

news2025/1/21 0:53:33

本实例程序实现了对优利德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 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 <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

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/udp6721.dbd"
udp6721_registerRecordDeviceDriver pdbbase

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:SubSleep

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1165472.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

绿色通道 快速理赔,渤海财险用实干书写服务品牌

7月底&#xff0c;受台风“杜苏芮”影响&#xff0c;北京市连续强降雨&#xff0c;西部、西南部、南部遭遇特大暴雨&#xff0c;房山、门头沟、丰台等地陆续出现山洪暴发现象。      灾害无情人有情&#xff0c;为更好地保障人民群众生命财产安全&#xff0c;渤海财险北京分…

【PWN · 栈迁移|off-by-one|伪随机|爆破】[HDCTF 2023]Makewish

一道精巧、包含很多要点的题目 一、题目 二、思路浅析 通过ctypes酷通过伪随机数检测&#xff0c;没用srand指定随机种子时&#xff0c;默认srand(1)。 通过puts_name的off-by-one来泄露canary 进入vuln时&#xff0c;发现只能刚好填充到rbp前面&#xff0c;但是会将最后一个…

虚拟机设置linux系统固定网络IP

文章目录 虚拟机设置linux系统固定网络IP1.设置虚拟机网络ip2.windows网络适配器设置1.windows112.其他windows版本 3.linux系统IP设置 虚拟机设置linux系统固定网络IP 1.设置虚拟机网络ip 2.windows网络适配器设置 1.windows11 2.其他windows版本 后面设置内容参考windows11…

基于OrangePi Zero 2实现垃圾分类智能垃圾桶项目(11)将指令来源和次数保存到数据库中(SQLite),指令来源和发出时间以及垃圾类型保存在文件中

SQLite&#xff08;嵌入式数据库&#xff09; 概念&#xff1a; 一种轻量级的关系型数据库管理系统&#xff0c;可以在应用程序中作为一个单独的组件运行&#xff0c;因此也被称为嵌入式数据库。与传统的客户端-服务器架构不同&#xff0c;SQLite 数据库存储在单个文件中&…

虹科案例 | AR内窥镜手术应用为手术节约45分钟?

相信医疗从业者都知道&#xff0c;在手术室中有非常多的医疗器械屏幕&#xff0c;特别是内窥镜手术室中医生依赖这些内窥镜画面来帮助病患进行手术。但手术室空间有限&#xff0c;屏幕缩放位置相对固定&#xff0c;在特殊场景下医生观看内窥镜画面时无法关注到病患的状态。这存…

axios 实现请求 loading 效果

前景提要&#xff1a; ts 简易封装 axios&#xff0c;统一 API 实现在 config 中配置开关拦截器 loading 分为全屏 loading 和局部 loading。 axios 中设置 loading 只能设置全屏 loading&#xff0c;因为局部 loading 需要当前局部的 dom&#xff0c;在 axios 中显然拿不到发…

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序)

目录 概念 插入排序 直接插入排序 希尔排序 选择排序 直接选择排序 双向选择排序 堆排序 交换排序 冒泡排序 快速排序 Hoare法 挖坑法 前后指针法 快排的优化 三数取中法 非递归快排 归并排序 分治算法二路归并 非递归归并 应用 排序总结 其他排序 计数…

记一次有趣的免杀探索

文章目录 前记查杀排查源码修改免杀效果测试 前记 evilhiding昨天被提issue不能绕过火绒了&#xff0c;于是今天更新了evilhiding v1.1&#xff0c;已经可以继续免杀了。 期待各位的stars&#xff0c;项目地址如下&#xff1a; https://github.com/coleak2021/evilhiding查杀…

【OJ比赛日历】快周末了,不来一场比赛吗? #11.04-11.10 #10场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-11-04&#xff08;周六&#xff09; #2场比赛2023-11-05…

科技云报道:大模型会给操作系统带来什么样的想象?

科技云报道原创。 在人工智能的发展历程中&#xff0c;大模型的出现标志着一个里程碑。 特别是近年来&#xff0c;诸如GPT-4、BERT等大模型的出现&#xff0c;不仅在自然语言处理、图像识别等领域取得了令人瞩目的成就&#xff0c;还推动了人工智能技术向更广泛的应用场景拓展…

IAR更新内置JLink

一、背景 IAR8.32,基于GD32F303CET6的工程&#xff0c;能正常使用JLINK进行debug and download&#xff0c;但在调试GD32F303CGT6时程序无法正常download且校验失败 GD32F303CET6&#xff1a;Flash--512K,RAM--64K GD32F303CET6&#xff1a;Flash--1M,RAM--96K 二、原因分析…

GZ035 5G组网与运维赛题第10套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第10套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; 子…

开关电源综合电气试验项目是什么?常规电源测试的标准和规范有哪些?

开关电源综合电气试验内容 1. 绝缘电阻和抗电强度测试 2. 输入浪涌电流测试 3. 输出电压、输入功率、输入功率因素、工作效率测试 4. 输出电压纹波及噪声测试 5. 输出过流保护测试 6. 短路保护测试 7. 输出电压过压保护测试 8. 过冲幅度及暂态恢复时间测试 9. 开机启动时间及关…

3dMax章鱼插件Octopus

3dMax章鱼插件Octopus 3dMax章鱼插件&#xff0c;不仅在视口中以饼状的形式&#xff0c;呼出各种属性参数&#xff0c;方便调用&#xff0c;而且是一个可编写脚本的框架&#xff0c;因此您有很多机会创建自己的菜单并轻松分发。整个OCTOPUS系统可以使用maxscript进行自定义&…

Linux shell编程学习笔记20:case ... esac、continue 和break语句

一、case ... esac语句说明 在实际编程中&#xff0c;我们有时会请到多条件多分支选择的情况&#xff0c;用if…else语句来嵌套处理不烦琐&#xff0c;于是JavaScript等语言提供了多选择语句switch ... case。与此类似&#xff0c;Linux Shell脚本编程中提供了case...in...esa…

睿趣科技:想知道开抖音小店的成本

随着互联网的发展&#xff0c;越来越多的人开始尝试通过开设网店来创业。抖音作为目前最受欢迎的短视频平台之一&#xff0c;也提供了开店的功能。那么&#xff0c;开一家抖音小店需要多少成本呢&#xff1f; 首先&#xff0c;我们需要了解的是&#xff0c;抖音小店的开店费用是…

Git 指令白雪警告!在IDEA中配置使用Git管理提交代码,无需繁杂指令

目录 1. 前言 2. Git 路径配置步骤 3. IDEA中使用Git管理项目 3.1 第一种做法 3.2 第二种做法 4. IDEA中提交代码和推送代码 5. 分支相关操作 5.1 创建分支 5.2 切换分支&#xff0c;删除分支 6. 拉取更新代码并处理分支冲突 1. 前言 相信有很多小伙伴在学习 Git 指…

libuv进程通信与管道描述符

libuv 提供了大量的子进程管理&#xff0c;抽象了平台差异并允许使用流或命名管道与子进程进行通信。Unix 中的一个常见习惯是每个进程只做一件事&#xff0c;并且把它做好。在这种情况下&#xff0c;一个进程通常会使用多个子进程来完成任务&#xff08;类似于在 shell 中使用…

【软件测试】个人博客项目测试报告

目录 1.报告概要 2、测试环境 3、手动测试用例编写 4、自动化测试用例 1.报告概要 测试对象&#xff1a;基于SSM项目的博客系统。 测试目的&#xff1a;检测博客项目是否符合预期&#xff0c;并且对测试知识进行练习和巩固。 测试点&#xff1a;主要针对常用的功能进行测…

rhcsa-vim

命令行的三种模式 将ets下的passwd文件复制到普通用户下面 编辑模式的快捷方式 a--光标后插入 A--行尾插入 o--光标所在上一行插入 O--光标所在上一行插入 i--光标前插入 I--行首插入 s--删除光标所在位然后进行插入模式 S--删除光标所在行然后进行插入 命令模式的快捷…