EPICS sequencer状态机示例

状态机源代码:

#define PVSYS    "pvsys=ca"
#define LIGHT    "{prefix}:light"
#define LIGHTON  "{prefix}:lightOn"
#define LIGHTOFF "{prefix}:lightOff"
#define VOLTAGE  "{prefix}:voltage"
#define LOLIMIT  "{prefix}:loLimit"
#define HILIMIT  "{prefix}:hiLimit"

program demo( PVSYS )

%%#include "errlog.h"

/*
    如果可congruent选项(+r)被指定给SNC,则所有变量成为一个结构体的组成。
*/
option  +r;

/*
    在声明一个变量后,可以为它分配一个数据库通道。在此之后,那个变量可以用于执行数据库操作。
*/
/* 灯控制的控制变量和转变点 */
int     light;
assign  light    to LIGHT;  /* 连接记录bo light */

double  lightOn;
assign  lightOn  to LIGHTON; /* 连接记录ao lightOff VAL=4.5 */
monitor lightOn;

double  lightOff;
assign  lightOff to LIGHTOFF; /* 连接记录ao lighton VAL=5.5 */
monitor lightOff;

/* 电压控制的控制变量和极限 */
double  voltage;
assign  voltage  to VOLTAGE; /*连接记录ao voltage, 范围:1.0 <- 2.0 <- 8.0 <- 9.0 */
/*
   要使状态程序事件驱动,输入变量可以被监控。受到监控的变量随当前数据库值自动被更新。
   变量必须首先被分配给一个数据库通道。
*/
monitor voltage;

double  loLimit;
assign  loLimit  to LOLIMIT; /*连接记录ao loLimit, VAL=0.0 */
monitor loLimit;
/* 声明事件标记 */
evflag  loFlag;
/*
    关联一个事件标记和一个数据库通道。
    一个事件标记可以关联一个数据库通道。
    当在那个通道上一个monitor返回时,相应的事件标记被设置。
*/
sync    loLimit  to loFlag;

double  hiLimit;
assign  hiLimit  to HILIMIT; /*连接记录ao liLimit, VAL=10.0 */
monitor hiLimit;
evflag  hiFlag;
sync    hiLimit  to hiFlag;


/* 灯控制状态集light:light初始值为OFF,进入LIGHT_OFF对应的状态 */
ss light {
    state START {
        when () {
            light = 0;
            pvPut( light );
        } state LIGHT_OFF
    }
/*  voltage初始为0,如果voltage大于了lightOn,则设置light为ON, 进入LIGHT_ON状态 */
    state LIGHT_OFF {
        when ( voltage > lightOn ) {
            light = 1;
            pvPut( light );
            printf( "light_off -> light_on\n" );
        } state LIGHT_ON
    }
/*  如果voltage小于了lightOn,则设置light为OFF, 进入LIGHT_OFF状态 */
    state LIGHT_ON {
        when ( voltage < lightOff ) {
            light = 0;
            pvPut( light );
            printf( "light_on -> light_off\n" );
        } state LIGHT_OFF
    }
}

/* 电压变化状态集 t */
ss ramp {
/* 初始voltage设置为loLimit中设定的值,进入电压RAMP_UP状态 */
    state START {
        when () {
            voltage = loLimit;
            pvPut( voltage );
            printf("start -> ramp_up\n");
        } state RAMP_UP
    }
/*
    在RAMP_UP状态时,voltage大于hiLimit,则从RAMP_UP状态跳转到RAMP_DOWN状态;
    否则,每隔0.5秒种,voltage自增0.1,并且更新voltage连接的记录,如果通道写失败,输出报错信息,
    下一个状态仍然是RAMP_UP
*/
    state RAMP_UP {
        when ( voltage > hiLimit ) {
            printf("ramp_up -> ramp_down\n");
        } state RAMP_DOWN

        when ( delay( 0.5 ) ) {
            voltage += 0.1;
            if ( pvPut( voltage ) < 0 )
                printf( "pvPut( voltage ) failed\n" );
            else
                printf( "voltage increment to:%3.2f\n", voltage );
        } state RAMP_UP
    }
/*
    在RAMP_DOWN状态时,voltage小于loLimit,则从RAMP_DOWN状态跳转到RAMP_UP状态;
    否则,每隔0.5秒种,voltage自减0.1,并且更新voltage连接的记录,如果通道写失败,输出报错信息,
    下一个状态仍然是RAMP_DOWN
*/
    state RAMP_DOWN {
        when ( voltage < loLimit ) {
            printf("ramp_down -> ramp_up\n");
        } state RAMP_UP

        when ( delay( 0.5 ) ) {
            voltage -= 0.1;
            if ( pvPut( voltage ) < 0 )
                printf( "pvPut( voltage ) failed\n" );
            else
               printf( "voltage decrement to: %3.2f\n", voltage );
        } state RAMP_DOWN
    }
}

/*
    hi / lo limit极限约束状态集:清除事件标记并且返回事件标记是否被设置。
    它用于在'转变'从句中使用。
*/
ss limit {
    state START {
    /* 设置了loFlag标记, 低限制大于高限制,设置高限值*/
        when ( efTestAndClear( loFlag ) && loLimit > hiLimit ) {
            hiLimit = loLimit;
            pvPut( hiLimit );
        } state START
    /* 设置了hiFlag标记, 高限制大于低限制,设置低限值*/
        when ( efTestAndClear( hiFlag ) && hiLimit < loLimit ) {
            loLimit = hiLimit;
            pvPut( loLimit );
        } state START
    }
}

 记录数据库文件:

# VAL=4.5
record(ao,"$(PREFIX):lightOff") {
    field(DOL,"4.5")
    field(PREC,"2")
    field(HOPR,"10.0")
    field(LOPR,"0.0")
    field(PINI,"YES")
}

# VAL=5.5
record(ao,"$(PREFIX):lightOn") {
    field(DOL,"5.5")
    field(PREC,"2")
    field(HOPR,"10.0")
    field(LOPR,"0.0")
    field(PINI,"YES")
}

# VAL= 0.0
record(ao,"$(PREFIX):loLimit") {
    field(DOL,"0.0")
    field(PREC,"2")
    field(HOPR,"10.0")
    field(LOPR,"0.0")
    field(PINI,"YES")
}

# VAL=0.0 范围:1.0 <- 2.0 <- 8.0 <- 9.0
record(ao,"$(PREFIX):voltage") {
    field(DOL,"0.0")
    field(PREC,"2")
    field(HOPR,"10.0")
    field(LOPR,"0.0")
    field(HIHI,"9.0")
    field(LOLO,"1.0")
    field(HIGH,"8.0")
    field(LOW,"2.0")
    field(HHSV,"MAJOR")
    field(LLSV,"MAJOR")
    field(HSV,"MINOR")
    field(LSV,"MINOR")
}

# VAL=10.0
record(ao,"$(PREFIX):hiLimit") {
    field(DOL,"10.0")
    field(PREC,"2")
    field(HOPR,"10.0")
    field(LOPR,"0.0")
    field(PINI,"YES")
}

# 1->OFF 0->ON
record(bo,"$(PREFIX):light") {
    field(ZNAM,"OFF")
    field(ONAM,"ON")
    field(ZSV,"MINOR")
}

启动脚本:

#!../../bin/linux-aarch64/seqtest

#- You may have to change seqtest to something else
#- everywhere it appears in this file

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/seqtest.dbd"
seqtest_registerRecordDeviceDriver pdbbase

## Load record instances
dbLoadRecords("db/seqtest.db","PREFIX=Test")

cd "${TOP}/iocBoot/${IOC}"
iocInit

## Start any sequence programs
seq &demo "prefix=Test"

 启动以上IOC,CSS操作界面如下:

EPICS sequencer状态机示例_第1张图片Voltage Upper和Voltage Lower设置电压设置范围,电压正向增加时,当前电压高于Light On Voltage时,Light会点亮;电压负向减小时,当前电压小于Light OFF Voltage时,Light会熄灭。

你可能感兴趣的:(EPICS教程,EPICS)