Arduino Uno的串口服务程序设置如文本的串口通信协议设计以及在Arduino上的应用-CSDN博客中所示。通过在串口上发送约定的文本协议,它实现的功能如下:
实现功能:
- 读取三路0.0V~5.0V模拟量输入,读取端口A0~A2
- 设置三路0.0V~5.0V的模拟量输出,输出管脚3,5,6
- 读取三路数字量输入,读取管脚2,4,7
- 设置三路数字量输出,输出管脚8,12,13
协议格式
1)读取三路0.0V~5.0V模拟量输入:
- 发送:VOLTS:GET?\r\n
- 接受:VOLTS:GET:2.5:1.5:3.2\r\n
2)设置三路0.0V~5.0V的模拟量输出:
- 发送:VOLTS:SET:2.1:2.2:3.2\r\n
- 接受:VOLTS:SET:2.1:2.2:3.2\r\n
3)读取三路数字量输入:
- 发送:DIGITS:GET?\r\n
- 接受:DIGITS:GET:1:1:0\r\n
4) 设置三路数字量输出:
- 发送:DIGITS:SET:1:0:1\r\n
- 接受:DIGITS:SET:1:0:1\r\n
开发EPICS IOC所需要模块
- Base
- asyn
- stream
1)使用makeBaseApp构建IOC应用程序框架
2)编辑configure/RELEASE添加base,asyn和stream模块所在的路径。
3)编辑arduino/arduinoApp/src下Makefile文件:
# 添加所需数据库定义文件
arduino_DBD += asyn.dbd
arduino_DBD += stream.dbd
arduino_DBD += drvAsynSerialPort.dbd
# 添加所需库文件
arduino_LIBS += asyn
arduino_LIBS += stream
4)在arduino/arduinoApp/Db路径下添加如下文件,
用于字符串收发的解析文件: arduino.proto
# arduino.proto
Terminator = CR LF;
write_dos
{
out "DIGITS:SET: %(A)d:%(B)d:%(C)d";
}
write_volts
{
out "VOLTS:SET:%(A).2f:%(B).6f:%(C).2f";
}
read_dis
{
out "DIGITS:GET?";
in "DIGITS:GET:%d:%(\$1)d:%(\$2)d";
}
read_volts
{
out "VOLTS:GET?";
in "VOLTS:GET:%f:%(\$1)f:%(\$2)f";
}
添加数据库记录文件:
1)bis.db:位输入记录
# bis.db
record (bi, "$(P)$(R)DI0")
{
field (DTYP, "stream")
field (ZNAM, "LOW")
field (ONAM, "HIGH")
field (INP, "@$(ARDUINO).proto read_dis($(P)$(R)DI1, $(P)$(R)DI2) $(PORT)")
field (SCAN, ".2 second")
}
record (bi, "$(P)$(R)DI1")
{
field (ZNAM, "LOW")
field (ONAM, "HIGH")
}
record (bi, "$(P)$(R)DI2")
{
field (ZNAM, "LOW")
field (ONAM, "HIGH")
}
2)bos.db:位输出记录
# bos.db
record(bo, "$(P)$(R)DO0")
{
field (DESC, "Digital Bit 0")
field (ZNAM, "LOW")
field (ONAM, "HIGH")
field(FLNK, "$(P)$(R)CALCOUTDOS")
}
record(bo, "$(P)$(R)DO1")
{
field (DESC, "Digital Bit 1")
field (ZNAM, "LOW")
field (ONAM, "HIGH")
field(FLNK, "$(P)$(R)CALCOUTDOS")
}
record(bo, "$(P)$(R)DO2")
{
field (DESC, "Digital Bit 0")
field (ZNAM, "LOW")
field (ONAM, "HIGH")
field(FLNK, "$(P)$(R)CALCOUTDOS")
}
record (calcout, "$(P)$(R)CALCOUTDOS") {
field (INPA, "$(P)$(R)DO0")
field (INPB, "$(P)$(R)DO1")
field (INPC, "$(P)$(R)DO2")
field (CALC, "0")
field (DTYP, "stream")
field (OUT, "@$(ARDUINO).proto write_dos $(PORT)")
}
3)volts_in.db:模拟量输入记录
# volts_in.db
record (ai, "$(P)$(R)VI0")
{
field (DTYP, "stream")
field (INP, "@$(ARDUINO).proto read_volts($(P)$(R)VI1, $(P)$(R)VI2) $(PORT)")
field (EGU, "V")
field (PREC, "2")
field (SCAN, ".2 second")
}
record (ai, "$(P)$(R)VI1")
{
field (EGU, "V")
field (PREC, "2")
}
record (ai, "$(P)$(R)VI2")
{
field (EGU, "V")
field (PREC, "2")
}
4)volts_out.db:模拟量输出记录
# volts_out.db
record (ao, "$(P)$(R)VO0")
{
field (DESC, "Set Volt 0")
field (EGU, "V")
field (PREC, "2")
field (DRVL, "0.00")
field (DRVH, "5.00")
field (LOPR, "0.0")
field (HOPR, "5.00")
field (FLNK, "$(P)$(R)CALCOUTVOLTS")
}
record (ao, "$(P)$(R)VO1")
{
field (DESC, "Set Volt 1")
field (EGU, "V")
field (PREC, "2")
field (DRVL, "0.00")
field (DRVH, "5.00")
field (LOPR, "0.0")
field (HOPR, "5.00")
field (FLNK, "$(P)$(R)CALCOUTVOLTS")
}
record (ao, "$(P)$(R)VO2")
{
field (DESC, "Set Volt 2")
field (EGU, "V")
field (PREC, "2")
field (DRVL, "0.00")
field (DRVH, "5.00")
field (LOPR, "0.0")
field (HOPR, "5.00")
field (FLNK, "$(P)$(R)CALCOUTVOLTS")
}
record (calcout, "$(P)$(R)CALCOUTVOLTS") {
field (INPA, "$(P)$(R)VO0")
field (INPB, "$(P)$(R)VO1")
field (INPC, "$(P)$(R)VO2")
field (CALC, "0")
field (DTYP, "stream")
field (OUT, "@$(ARDUINO).proto write_volts $(PORT)")
}
将以上文件写入到同一路径下的Makefile中:
...
DB += bos.db
DB += bis.db
DB += volts_out.db
DB += volts_in.db
DB += arduino.proto
...
5) 编辑启动脚本:arduino/iocBoot/iocarduino/st.cmd
...
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/db/")
drvAsynSerialPortConfigure("ARDUINO", "/dev/ttyACM0", 0, 0, 0)
asynSetOption("ARDUINO",0,"baud","9600")
asynSetOption("ARDUINO",0,"parity","none")
asynSetOption("ARDUINO",0,"bits","8")
asynSetOption("ARDUINO",0,"stop","1")
## Load record instances
dbLoadRecords("db/bos.db","P=ARDUINO:,R=CH:,PORT=ARDUINO,ARDUINO=arduino")
dbLoadRecords("db/bis.db","P=ARDUINO:,R=CH:,PORT=ARDUINO,ARDUINO=arduino")
dbLoadRecords("db/volts_out.db","P=ARDUINO:,R=CH:,PORT=ARDUINO,ARDUINO=arduino")
dbLoadRecords("db/volts_in.db","P=ARDUINO:,R=CH:,PORT=ARDUINO,ARDUINO=arduino")
...
6) 回到这个IOC的顶层目录,即arduino,执行make进行编译。
7)进入arduino/iocBoot/iocarduino,启动这个IOC:
../../bin/linux-x86_64/arduino st.cmd
8) 查看加载的记录:
epics> dbl
ARDUINO:CH:CALCOUTDOS
ARDUINO:CH:CALCOUTVOLTS
ARDUINO:CH:DO0
ARDUINO:CH:DO1
ARDUINO:CH:DO2
ARDUINO:CH:VO0
ARDUINO:CH:VO1
ARDUINO:CH:VO2
ARDUINO:CH:DI0
ARDUINO:CH:DI1
ARDUINO:CH:DI2
ARDUINO:CH:VI0
ARDUINO:CH:VI1
ARDUINO:CH:VI2
1、3个数字量输出:ARDUINO:CH:DO0 ARDUINO:CH:DO1 ARDUINO:CH:DO2
2、3个数字量输入:ARDUINO:CH:DI0 ARDUINO:CH:DI1 ARDUINO:CH:DI2
3、3个模拟量输出:ARDUINO:CH:VO0 ARDUINO:CH:VO1 ARDUINO:CH:VO2
4、3个模拟量输入::ARDUINO:CH:VI0 ARDUINO:CH:VI1 ARDUINO:CH:VI2
对应客户端图形界面: