设备之间连接如下图:
Arduino的程序文本的串口通信协议设计以及在Arduino上的应用_arduino串口通信协议-优快云博客中说明:
1、DO0~DO2对应设置Arduino的数字量输出-管脚[8,12,13]。
2、DI0~DI2对应读取Arduino的数字量输入-管脚[2,4,7]。
3、AO0~AO2对应设置Arduino的模拟量输出-管脚[3,5,6]。
4、AI0~AI2对应设置Arduino的模拟量输入-管脚[A0,A1,A2]。
arduino上连线如下:
- DO0 <-> DI0
- DO1 <-> DI1
- DO2 <-> DI2
- AI0 <-> GND
- AI1 <-> 5V
- AI2 <-> 3.3V
IOC应用程序开发如下:
1、建立IOC程序框架:
root@lubancat:/usr/local/EPICS/program# mkdir asynArduino
root@lubancat:/usr/local/EPICS/program# cd asynArduino/
root@lubancat:/usr/local/EPICS/program/asynArduino# makeBaseApp.pl -t ioc asynArduino
root@lubancat:/usr/local/EPICS/program/asynArduino# makeBaseApp.pl -i -t ioc asynArduino
Using target architecture linux-aarch64 (only one available)
The following applications are available:
asynArduino
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name?
root@lubancat:/usr/local/EPICS/program/asynArduino#
2、编辑configure/RELEASE文件,添加EPICS_BASE和ASYN环境变量所指向的支持目录:
# RELEASE - Location of external support modules
#
...
EPICS_BASE = /usr/local/EPICS/base
SUPPORT=/usr/local/EPICS/synApps/support
ASYN=$(SUPPORT)/asyn
...
-include $(TOP)/configure/RELEASE.local
3、进入 asynArduinoApp/src/源文件目录:
root@lubancat:/usr/local/EPICS/program/asynArduino# cd asynArduinoApp/src/
编写arduino.h和arduino.cpp源文件,源代码如下:
/*
arduino.h
*/
#ifndef arduino_H
#define arduino_H
#include <epicsEvent.h>
#include <epicsTypes.h>
#define DEFAULT_TIMEOUT 2.0
#define POLL_TIME 0.5
#define MAX_CHANNELS 3
#define NUM_ANALOG_IN 3
#define NUM_ANALOG_OUT 3
#define NUM_IO_BITS 3
#define MAX_SIGNALS NUM_IO_BITS
#define INPUTBUFFERLEN 100
#define arduinoDOString "ARDUINO_DO_STRING"
#define arduinoDIString "ARDUINO_DI_STRING"
#define arduinoAOString "ARDUINO_AO_STRING"
#define arduinoAIString "ARDUINO_AI_STRING"
static const char *driverName = "asynArduinoDriver";
class asynArduinoController : public asynPortDriver{
public:
asynArduinoController(const char *portName, const char *serverPort ,int channels, int numParams,
int interfaceMask, int interruptMask);
virtual ~asynArduinoController(){};
/* overriding methods from asynPortDriver */
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
virtual asynStatus writeUInt32Digital(asynUser *pasynUser,
epicsUInt32 value, epicsUInt32 mask);
virtual void report(FILE *fp, int details);
/* new method*/
virtual asynStatus sendReceive(const char*, char*, unsigned int );
virtual asynStatus sendOnly(const char *outputBuff);
virtual bool resetConnection(){return false;};
void arduinoPoller();
virtual asynStatus startPoller(double pollPeriod);
static void callPoller(void*);
static void callShutdown(void * ptr){((asynArduinoController*)ptr)->shutdown();};
void shutdown();
int shuttingDown_;
protected:
#define FIRST_ARDUINO_PARAM arduinoDO_;
int arduinoDO_;
int arduinoDI_;
int arduinoAO_;
int arduinoAI_;
#define LAST_ARDUINO_PARAM arduinoAI_;
double pollPeriod_;
epicsMutex *baseMutex;
asynUser *pasynUserController_;
char inputBuffer[INPUTBUFFERLEN];
char pollInputBuffer[INPUTBUFFERLEN];
asynStatus sendReceiveLock(const char* outbuffer, char* inbuffer, unsigned int );
asynStatus sendOnlyLock(const char * outbuffer);
};
#define NUM_ARDUINO_DRIVER_PARAMS (&LAST_ARDUINO_PARAM - &FIRST_ARDUINO_PARAM + 1)
#endif
/* arduino.cpp */
#include <stdlib.h>
#include <string.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <epicsExit.h>
#include <asynPortDriver.h>
#include <asynOctetSyncIO.h>
#include "arduino.h"
#include <epicsExport.h>
#include <shareLib.h>
#ifndef VERSION_INT
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#endif
#define ARDUINO_ASYN_VERSION_INT VERSION_INT(ASYN_VERSION,ASYN_REVISION,ASYN_MODIFICATION,0)
#define VERSION_INT_4_32 VERSION_INT(4,32,0,0)
#define DEBUG
asynArduinoController::asynArduinoController(const char *portName, const char * serverPort, int channels, int numParams,
int interfaceMask, int interruptMask)
: asynPortDriver(portName, channels,
#if ARDUINO_ASYN_VERSION_INT < VERSION_INT_4_32
NUM_ARDUINO_DRIVER_PARAMS+channels,
#endif
interfaceMask | asynFloat64Mask | asynUInt32DigitalMask | asynDrvUserMask,
interruptMask | asynFloat64Mask | asynUInt32DigitalMask,
ASYN_MULTIDEVICE | ASYN_CANBLOCK , 1 , 0 , 0),
shuttingDown_(0), pollPeriod_(POLL_TIME)
{
static const char *functionName = "asynArduinoController";
asynStatus status;
/* Create the base set of motor parameters */
createParam(arduinoDOString, asynParamUInt32Digital, &arduinoDO_);
createParam(arduinoDIString, asynParamUInt32Digital, &arduinoDI_);
createParam(arduinoAOString, asynParamFloat64, &arduinoAO_);
createParam(arduinoAIString, asynParamFloat64, &arduinoAI_);
baseMutex = new epicsMutex;
status = pasynOctetSyncIO->connect(serverPort, 0, &pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s:%s: cannot connect to virtual motor controller\n",
driverName, functionName, portName);
}
epicsAtExit(asynArduinoController::callShutdown, this);
}
asynStatus asynArduinoController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
{
int addr;
int function = pasynUser->reason;
asynStatus status= asynSuccess;
static const char *functionName = "writeIFloat64";
int i;
double volt;
char temp[20];
this->getAddress(pasynUser, &addr);
setDoubleParam(addr, function, value);
if (function == arduinoAO_){
sprintf(pollInputBuffer, "VOLTS:SET:");
for (i = NUM_ANALOG_OUT -1; i >=0 ; i--){
getDoubleParam(i, function, &volt);
sprintf(temp, "%.2f:", volt);
strcat(pollInputBuffer, temp);
}
int len = strlen(pollInputBuffer);
pollInputBuffer[len-1] = '\0';
//printf("send:%s\n", pollInputBuffer);
status = sendOnlyLock(pollInputBuffer);
}
callParamCallbacks(addr);
if (status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s, port %s, wrote %.2f to address %d\n",
driverName, functionName, this->portName, value, addr);
} else {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s:%s, port %s, ERROR writing %.2f to address %d, status=%d\n",
driverName, functionName, this->portName, value, addr, status);
}
return status;
}
asynStatus asynArduinoController::writeUInt32Digital(asynUser *pasynUser, epicsUInt32 value, epicsUInt32 mask)
{
int function = pasynUser->reason;
asynStatus status = asynSuccess;
int i;
char temp[100];
static const char *functionName = "writeUInt32Digital";
setUIntDigitalParam(function, value, mask);
//printf("function=%d, arduinoDO_=%d\n", function, arduinoDO_);
//printf("value=0x%x, mask=0x%x\n", value, mask);
if (function == arduinoDO_) {
//printf("In arduinoDO_\n");
sprintf(temp, "DIGITS:SET:");
getUIntDigitalParam(function, &value, 0x7);
for (i=0; i<NUM_IO_BITS; i++) {
if (value & 0x1){
strcat(temp, "1:");
}
else{
strcat(temp, "0:");
}
value = value >> 1;
}
int len = strlen(temp);
temp[len-1] = '\0';
#ifdef DEBUG
//printf("value=0x%x, mask=0x%x\n", value, mask);
//printf("send: %s\n", temp);
#endif
status = sendOnlyLock(temp);
}
callParamCallbacks(0);
if (status == asynSuccess) {
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s, port %s, wrote value=0x%x, mask=0x%x\n",
driverName, functionName, this->portName, value, mask);
}
else {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s:%s, port %s, ERROR writing value=0x%x, mask=0x%x,status=%d\n",
driverName, functionName, this->portName, value, mask, status);
}
return status;
}
void asynArduinoController::report(FILE *fp, int level)
{
int channel;
double ao, ai;
unsigned bo, bi;
fprintf(fp, "driver:%s, portName:%s \n",driverName, this->portName);
getUIntDigitalParam(arduinoDO_, &bo, 0x7);
getUIntDigitalParam(arduinoDI_, &bi, 0x7);
fprintf(fp, "BO:%3o, BI:%3o\n", bo, bi );
for (channel=0; channel < maxAddr; channel++) {
if (level > 0)
{
getDoubleParam(channel, arduinoAO_, &ao);
getDoubleParam(channel, arduinoAI_, &ai);
fprintf(fp, "channel:%d, AO:%.2f, AI:%.2f\n",channel, ao, ai);
}
}
}
asynStatus asynArduinoController::sendReceive(const char * outputBuffer, char * inputBuffer, unsigned int inputSize)
{
/*
printf("output: %s\n", outBuffer);
if (strncmp(outBuffer, "VOLTS:GET?", strlen("VOLTS:GET?"))){
strcpy(inputBuffer, "VOLTS:GET:1.23:2.34:3.56");
}
else if (strncmp(outBuffer, "DIGITS:GET?", strlen("DIGITS:GET?"))){
strcpy(inputBuffer, "DIGTIS:GET:0:1:0");
}
else{
sprintf(inputBuffer, "SendBack: %s", outBugger);
}
return asynSuccess;
*/
size_t nwrite, nread;
asynStatus status;
int eomReason;
// const char *functionName="sendReceive";
status = pasynOctetSyncIO->writeRead(pasynUserController_,
outputBuffer, strlen(outputBuffer), inputBuffer, inputSize,
DEFAULT_TIMEOUT, &nwrite, &nread, &eomReason);
return status;
}
asynStatus asynArduinoController::sendOnly(const char *outputBuff)
{
/* printf("output: %s\n", outputBuff);
return asynSuccess;
*/
size_t nwrite;
asynStatus status;
// const char *functionName="sendOnly";
status = pasynOctetSyncIO->write(pasynUserController_, outputBuff,
strlen(outputBuff), DEFAULT_TIMEOUT, &nwrite);
return status ;
}
asynStatus asynArduinoController::sendOnlyLock(const char *outputBuff)
{
asynStatus status;
baseMutex->lock();
status = sendOnly(outputBuff);
baseMutex->unlock();
return status;
}
asynStatus asynArduinoController::sendReceiveLock(const char *outputBuff, char *inputBuff, unsigned int inputSize)
{
asynStatus status;
if (inputSize > 0) inputBuff[0] = '\0';
baseMutex->lock();
status = sendReceive(outputBuff, inputBuff, inputSize);
baseMutex->unlock();
return status;
}
void asynArduinoController::shutdown(){
lock();
shuttingDown_ = 1;
unlock();
}
void asynArduinoController::arduinoPoller()
{
static const char *functionName = "arduinoPoller";
int addr;
asynStatus status;
double ai[3];
double aiold[3];
epicsUInt32 biOld, bi;
int bit[3];
while(1) {
lock();
if (shuttingDown_) {
unlock();
break;
}
sprintf(inputBuffer,"VOLTS:GET?");
//printf("%s\n", inputBuffer);
status = sendReceiveLock(inputBuffer, pollInputBuffer, sizeof(pollInputBuffer));
//printf("%s\n", pollInputBuffer);
sscanf(pollInputBuffer, "VOLTS:GET:%lf:%lf:%lf", &ai[2], &ai[1], &ai[0]);
//printf("ai0:%lf,ai1:%lf,ai2:%lf\n", ai[0], ai[1], ai[2]);
for (addr = 0; addr < NUM_ANALOG_IN; addr++){
getDoubleParam(addr, arduinoAI_, &aiold[addr]);
if (aiold[addr] != ai[addr]){
setDoubleParam(addr, arduinoAI_, ai[addr]);
callParamCallbacks(addr);
}
}
getUIntDigitalParam(arduinoDI_, &biOld, 0x7);
bi = 0;
sprintf(inputBuffer,"DIGITS:GET?");
status = sendReceiveLock(inputBuffer, pollInputBuffer, sizeof(pollInputBuffer));
//printf("%s\n", pollInputBuffer);
sscanf(pollInputBuffer, "DIGITS:GET:%d:%d:%d", &bit[0], &bit[1],&bit[2]);
for (addr = 0; addr < NUM_IO_BITS; addr++){
bi = bi << 1;
if (bit[2-addr]){
bi = bi | 0x1;
}
else{
bi = bi & 0x6;
}
//printf("%d->0x%x\n",2-addr, bi);
}
//printf("b0:%d,b1:%d,b2:%d\n", bit[0],bit[1],bit[2]);
//printf("Old: 0x%x New: 0x%x\n", biOld, bi);
if (biOld != bi){
setUIntDigitalParam(arduinoDI_, bi , 0x7);
callParamCallbacks(0);
}
if (shuttingDown_) {
unlock();
break;
}
unlock();
/* wait here for the next poll
waiting may be interrupted by pollEvent or interrupt messages*/
//epicsThreadSleep(2.0);
epicsThreadSleep(pollPeriod_);
}
} /* End while */
void asynArduinoController::callPoller(void *drvPvt)
{
asynArduinoController *pController = (asynArduinoController*)drvPvt;
pController->arduinoPoller();
}
asynStatus asynArduinoController::startPoller(double pollPeriod)
{
char threadName[20];
pollPeriod_ = pollPeriod;
sprintf(threadName, "thead-%s", "arduinoPoller");
printf("call startPoller .... \n");
epicsThreadCreate(threadName,
epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC)&asynArduinoController::callPoller, (void *) this);
return asynSuccess;
}
extern "C" int asynArduinoControllerConfig(
const char *portName,
const char *serverPortName,
int nChannels,
int nParams,
int interfaceMask,
int interruptMask)
{
asynArduinoController *pController = new asynArduinoController(portName,
serverPortName, nChannels, nParams, interfaceMask, interruptMask);
pController->startPoller(POLL_TIME);
return(asynSuccess);
}
extern "C"
{
static const iocshArg asynArduinoControllerArg0 = {"asyn port name", iocshArgString};
static const iocshArg asynArduinoControllerArg1 = {"server port name", iocshArgString};
static const iocshArg asynArduinoControllerArg2 = {"number of channels", iocshArgInt};
static const iocshArg asynArduinoControllerArg3 = {"nummber of params", iocshArgInt};
static const iocshArg asynArduinoControllerArg4 = {"interface Mask", iocshArgInt};
static const iocshArg asynArduinoControllerArg5 = {"interrupt Mask", iocshArgInt};
static const iocshArg * const asynArduinoControllerArgs[6] = {&asynArduinoControllerArg0,
&asynArduinoControllerArg1,
&asynArduinoControllerArg2,
&asynArduinoControllerArg3,
&asynArduinoControllerArg4,
&asynArduinoControllerArg5 };
static const iocshFuncDef asynArduinoControllerFuncDef = {"asynArduinoControllerConfig", 6, asynArduinoControllerArgs};
static void asynArduinoControllerCallFunc(const iocshArgBuf *args)
{
asynArduinoControllerConfig(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival);
}
static void asynArduinoRegister(void)
{
iocshRegister(&asynArduinoControllerFuncDef, asynArduinoControllerCallFunc);
}
epicsExportRegistrar(asynArduinoRegister);
}
添加 arduinoSupport.dbd 文件,其内容如下:
/* cat arduinoSupport.dbd /*
registrar(asynArduinoRegister)
编辑同一目录下的Makefile文件,添加所需的数据库定义文件和库文件
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=============================
# Build the IOC application
PROD_IOC = asynArduino
# asynArduino.dbd will be created and installed
DBD += asynArduino.dbd
# asynArduino.dbd will be made up from these files:
asynArduino_DBD += base.dbd
# Include dbd files from all support applications:
asynArduino_DBD += asyn.dbd
asynArduino_DBD += arduinoSupport.dbd
asynArduino_DBD += drvAsynSerialPort.dbd
asynArduino_DBD += drvAsynIPPort.dbd
# Add all the support libraries needed by this IOC
asynArduino_LIBS += asyn
asynArduino_SRCS += arduino.cpp
# asynArduino_registerRecordDeviceDriver.cpp derives from asynArduino.dbd
asynArduino_SRCS += asynArduino_registerRecordDeviceDriver.cpp
# Build the main IOC entry point on workstation OSs.
asynArduino_SRCS_DEFAULT += asynArduinoMain.cpp
asynArduino_SRCS_vxWorks += -nil-
# Add support from base/src/vxWorks if needed
#asynArduino_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
# Finally link to the EPICS Base libraries
asynArduino_LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
4、切换到目录asynArduino/asynArduinoApp/Db下,编写四个模板文件:
1)aiFloat64.template:
record(ai, "$(P)$(R)AI$(N)") {
field(DTYP,"asynFloat64")
field(INP,"@asyn($(PORT) $(OFFSET))ARDUINO_AI_STRING")
field(HOPR,"$(HOPR)")
field(LOPR,"$(LOPR)")
field(PREC,"$(PREC)")
field(SCAN,"$(SCAN)")
}
2)ao.template
record(ao, "$(P)$(R)AO$(N)") {
field(DTYP,"asynFloat64")
field(OUT,"@asyn($(PORT),$(OFFSET),1.0)ARDUINO_AO_STRING")
field(HOPR,"$(HOPR)")
field(LOPR,"$(LOPR)")
field(PREC,"$(PREC)")
}
3)bi_bit.template
record(bi,"$(P)$(R)BI$(N)") {
field(DTYP,"asynUInt32Digital")
field(INP,"@asynMask($(PORT),0,$(MASK), 1.0)ARDUINO_DI_STRING")
field(SCAN,"$(SCAN)")
field(ZNAM,"$(ZNAM)")
field(ONAM,"$(ONAM)")
field(ZSV,"$(ZSV)")
field(OSV,"$(OSV)")
}
4) bo_bit.template
record(bo,"$(P)$(R)BO$(N)") {
field(DTYP,"asynUInt32Digital")
field(OUT,"@asynMask($(PORT),0,$(MASK),1.0)ARDUINO_DO_STRING")
field(ZNAM,"$(ZNAM)")
field(ONAM,"$(ONAM)")
}
5)编辑相同目录下的Makefile文件:
....
DB += bo_bit.template
DB += bi_bit.template
DB += aiFloat64.template
DB += ao.template
...
5、切换到本IOC的顶层目录,并且执行make命令,编译整个程序:
root@lubancat:/usr/local/EPICS/program/asynArduino# make
make -C ./configure install
make[1]: Entering directory '/usr/local/EPICS/program/asynArduino/configure'
...
make[2]: Leaving directory '/usr/local/EPICS/program/asynArduino/iocBoot/iocasynArduino'
make[1]: Leaving directory '/usr/local/EPICS/program/asynArduino/iocBoot'
6、切换到IOC启动目录 iocBoot/iocasynArduino/
root@lubancat:/usr/local/EPICS/program/asynArduino# cd iocBoot/iocasynArduino/
root@lubancat:/usr/local/EPICS/program/asynArduino/iocBoot/iocasynArduino# pwd
/usr/local/EPICS/program/asynArduino/iocBoot/iocasynArduino
编写四个替换文件:
1)ais.substitutions
file "../../db/aiFloat64.template" { pattern
{P, R, N, PORT, OFFSET, LOPR, HOPR, PREC, SCAN}
{TEST:, ARDUINO:, 0, AA 0, 0.0 5.0 3, "I/O Intr"}
{TEST:, ARDUINO:, 1, AA 1, 0.0 5.0 3, "I/O Intr"}
{TEST:, ARDUINO:, 2, AA 2, 0.0 5.0 3, "I/O Intr"}
}
2)aos.substitutions
file "../../db/ao.template" { pattern
{P, R, N PORT, OFFSET, LOPR, HOPR, PREC}
{TEST:, ARDUINO:, 0, AA, 0, 0.0, 5.0, 3}
{TEST:, ARDUINO:, 1, AA, 1, 0.0, 5.0, 3}
{TEST:, ARDUINO:, 2, AA, 2, 0.0, 5.0, 3}
}
3) bis.substitutions
file "../../db/bi_bit.template" { pattern
{P, R, N, PORT, MASK, ZNAM, ONAM, ZSV, OSV, SCAN}
{TEST:, ARDUINO:, 0, AA, 0x1, Low, High, NO_ALARM, MAJOR, "I/O Intr"}
{TEST:, ARDUINO:, 1, AA, 0x2, Low, High, NO_ALARM, MAJOR, "I/O Intr"}
{TEST:, ARDUINO:, 2, AA, 0x4, Low, High, NO_ALARM, MAJOR, "I/O Intr"}
}
4) bos.substitutions
file "../../db/bo_bit.template" { pattern
{P, R, N PORT, MASK, ZNAM, ONAM}
{TEST:, ARDUINO:, 0, AA, 0x1, Low, High}
{TEST:, ARDUINO:, 1, AA, 0x2, Low, High}
{TEST:, ARDUINO:, 2, AA, 0x4, Low, High}
}
5) 编辑启动脚本st.cmd,添加硬件连接语句以及记录加载语句:
#!../../bin/linux-x86_64/asynArduino
#- You may have to change asynArduino to something else
#- everywhere it appears in this file
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/asynArduino.dbd"
asynArduino_registerRecordDeviceDriver pdbbase
# Use the following commands for serial RTU or ASCII
#drvAsynSerialPortConfigure(const char *portName,
# const char *ttyName,
# unsigned int priority,
# int noAutoConnect,
# int noProcessEos);
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")
asynOctetSetInputEos( "Arduino",0,"\r\n")
asynOctetSetOutputEos("Arduino",0,"\r\n")
asynArduinoControllerConfig("AA", "Arduino", 3, 0, 0, 0)
## Load record instances
#dbLoadRecords("db/xxx.db","user=xxx")
cd "${TOP}/iocBoot/${IOC}"
dbLoadTemplate("bos.substitutions")
dbLoadTemplate("bis.substitutions")
dbLoadTemplate("ais.substitutions")
dbLoadTemplate("aos.substitutions")
iocInit
7、在启动目录中执行../../bin/linux-aarch64/asynArduino st.cmd 启动这个IOC,并且用dbl命令查看已经加载的记录。
root@lubancat:/usr/local/EPICS/program/asynArduino/iocBoot/iocasynArduino# ../../bin/linux-aarch64/asynArduino st.cmd
#!../../bin/linux-x86_64/asynArduino
< envPaths
epicsEnvSet("IOC","iocasynArduino")
epicsEnvSet("TOP","/usr/local/EPICS/program/asynArduino")
epicsEnvSet("SUPPORT","/usr/local/EPICS/synApps/support")
epicsEnvSet("ASYN","/usr/local/EPICS/synApps/support/asyn")
epicsEnvSet("EPICS_BASE","/usr/local/EPICS/base")
cd "/usr/local/EPICS/program/asynArduino"
...
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2024-05-31T11:45+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
## Start any sequence programs
#seq sncxxx,"user=blctrl"
epics> dbl
TEST:ARDUINO:AI0
TEST:ARDUINO:AI1
TEST:ARDUINO:AI2
TEST:ARDUINO:AO0
TEST:ARDUINO:AO1
TEST:ARDUINO:AO2
TEST:ARDUINO:BI0
TEST:ARDUINO:BI1
TEST:ARDUINO:BI2
TEST:ARDUINO:BO0
TEST:ARDUINO:BO1
TEST:ARDUINO:BO2
8、启动窗口文件,查看各记录的状态,并且记录在DO和AO尝试输入,并且查看相应状态。