状态机源代码:
#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操作界面如下:
Voltage Upper和Voltage Lower设置电压设置范围,电压正向增加时,当前电压高于Light On Voltage时,Light会点亮;电压负向减小时,当前电压小于Light OFF Voltage时,Light会熄灭。