仿真数字正弦波发生器程序

1)构建这个IOC程序的程序框架:

orangepi@orangepi5:/usr/local/EPICS/program/simScope$ ls
bin  configure  db  dbd  iocBoot  lib  Makefile  simScopeApp

2)修改configure下RELEASE文件,添加所需的支持模块,此IOC程序需要asyn模块支持,因此添加以下两行:

...

# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
SUPPORT=/usr/local/EPICS/synApps/support
ASYN=$(SUPPORT)/asyn

...

3) 进入simScopeApp/src/目录下,编写以下以下三个文件:

simScope.cpp  simScope.h  simScopeSupport.dbd

a) simScope.h:

#include 

#define NUM_VERT_SELECTIONS     4

/* drvInfo string*/
#define P_RunString                     "SCOPE_RUN"                     /* asynInt32 r/w start/stop backgroud thread */
#define P_MaxPointsString               "SCOPE_MAX_POINTS"              /* asynInt32 r/o max number of data points   */
#define P_TimePerDivString              "SCOPE_TIME_PER_DIV"            /* asynFloat64 r/w Time Per Div              */
#define P_TimePerDivSelectString        "SCOPE_TIME_PER_DIV_SELECT"     /* asynInt32 r/w   Time Per Div Choices      */
#define P_VertGainString                "SCOPE_VERT_GAIN"               /* asynFloat64 r/w Vert Gain                 */
#define P_VertGainSelectString          "SCOPE_VERT_GAIN_SELECT"        /* asynInt32 r/w Vert Gain Choices           */
#define P_VoltsPerDivString             "SCOPE_VOLTS_PER_DIV"           /* asynFloat64 r/w Volts Per Div             */
#define P_VoltsPerDivSelectString       "SCOPE_VOLTS_PER_DIV_SELECT"    /* asynInt32 r/w Volts Per Div Choices       */
#define P_VoltOffsetString              "SCOPE_VOLT_OFFSET"             /* asynFloat64 r/w Volt Offset               */
#define P_TriggerDelayString            "SCOPE_TRIGGER_DELAY"           /* asynFloat64 r/w Trigger Delay             */
#define P_NoiseAmplitudeString          "SCOPE_NOISE_AMPLITUDE"         /* asynFloat64 r/w Noise Amplitude           */
#define P_UpdateTimeString              "SCOPE_UPDATE_TIME"             /* asynFloat64 r/w Update Time               */
#define P_WaveformString                "SCOPE_WAVEFORM"                /* asynFloat64Array r/o waveform data array  */
#define P_TimeBaseString                "SCOPE_TIME_BASE"               /* asynFloat64Array r/o time base array      */
#define P_MinValueString                "SCOPE_MIN_VALUE"               /* asynFloat64 r/o min data */
#define P_MaxValueString                "SCOPE_MAX_VALUE"               /* asynFloat64 r/o max data */
#define P_MeanValueString               "SCOPE_MEAN_VALUE"              /* asynFloat64 r/o mean data */

class simScope : public asynPortDriver
{
public:
        simScope(const char * portName, int maxArraySize);
        /* There method overwritten from asynPortDriver */
        virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
        virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
        virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn);
        virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severties[], size_t nElements, size_t *nIn);

        void simTask(void);

protected:
        /* index for parameter in the parameter library */
        int P_Run;
        int P_MaxPoints;
        int P_TimePerDiv;
        int P_TimePerDivSelect;
        int P_VertGain;
        int P_VertGainSelect;
        int P_VoltsPerDiv;
        int P_VoltsPerDivSelect;
        int P_VoltOffset;
        int P_TriggerDelay;
        int P_NoiseAmplitude;
        int P_UpdateTime;
        int P_Waveform;
        int P_TimeBase;
        int P_MinValue;
        int P_MaxValue;
        int P_MeanValue;

private:
        /* event to send sigal to background thread */
        epicsEventId eventId_;
        /* waveform data array     */
        epicsFloat64 *pData_;
        /* waveform timebase array */
        epicsFloat64 *pTimeBase_;
        /* string array for Volts Per Div Choices*/
        char *voltsPerDivStrings_[NUM_VERT_SELECTIONS];
        /* value array for Volts Per Div Choices */
        int voltsPerDivValues_[NUM_VERT_SELECTIONS];
        /* severities array for Volts Per Div Choices */
        int voltsPerDivSeverities_[NUM_VERT_SELECTIONS];

        /* set Vert Gain */
        void setVertGain();
        /* set Volts Per Div according to voltsPerDivSelect */
        void setVoltsPerDiv();
        /* set Time Per Div according to TimePerDivSelect   */
        void setTimePerDiv();
};

b) simScope.cpp:

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include  "simScope.h"
#include 

#define FREQUENCY               1000    /* volt signal frequency */
#define AMPLITUDE               1.0     /* volt signal amplitude */
#define NUM_DIVISIONS           10      /* horizontal and vertical axis' divisions */
#define MIN_UPDATE_TIME         0.05    /* the min update time for the waveform data */

#define MAX_ENUM_STRING_SIZE    20
/* This driver's Name */
static const char * driverName = "simScope";

static int allVoltsPerDivSelections[NUM_VERT_SELECTIONS] = {1,2,5,10};
/* For C Call */
void simTask(void * pdrvPvt);

simScope::simScope(const char * portName, int maxPoints)
        :asynPortDriver(portName,
                        1,
                        asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask,
                        asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynEnumMask,
                        0, /* asynFlags  */
                        1, /* autoconnect*/
                        0, /* Default priority   */
                        0) /* Default stack size */
{
        asynStatus status;
        int i;
        const char *functionName = "simScope";

        /* make sure the number of points at least 100 points */
        if (maxPoints < 100){
                maxPoints = 100;
        }
        printf("Come to Contruct the simScope instance\n");

        /* allocate space for waveform data */
        pData_ = (epicsFloat64 *)calloc( maxPoints, sizeof(epicsFloat64));
        /* allocate space for timebase */
        pTimeBase_ = (epicsFloat64 *)calloc(maxPoints, sizeof(epicsFloat64));
        /* set the interval between pTimeBase_ elements */
        for (i = 0; i < maxPoints; i++){ // the number of divisions is NUM_DIVISIONS
                pTimeBase_[i] = (epicsFloat64)i/ (maxPoints - 1)  * NUM_DIVISIONS ;
        }

        // create the event for sending signal to the background thread
        eventId_ = epicsEventCreate(epicsEventEmpty);

        printf("Come before create parameters\n");
        /* create the parameters for communicating with epics Records */
        createParam(P_RunString,                asynParamInt32,         &P_Run);
        createParam(P_MaxPointsString,          asynParamInt32,         &P_MaxPoints);
        createParam(P_TimePerDivString,         asynParamFloat64,       &P_TimePerDiv);
        createParam(P_TimePerDivSelectString,   asynParamInt32,         &P_TimePerDivSelect);
        createParam(P_VertGainString,           asynParamFloat64,       &P_VertGain);
        createParam(P_VertGainSelectString,     asynParamInt32,         &P_VertGainSelect);
        createParam(P_VoltsPerDivString,        asynParamFloat64,       &P_VoltsPerDiv);
        createParam(P_VoltsPerDivSelectString,  asynParamInt32,         &P_VoltsPerDivSelect);
        createParam(P_VoltOffsetString,         asynParamFloat64,       &P_VoltOffset);
        createParam(P_TriggerDelayString,       asynParamFloat64,       &P_TriggerDelay);
        createParam(P_NoiseAmplitudeString,     asynParamFloat64,       &P_NoiseAmplitude);
        createParam(P_UpdateTimeString,         asynParamFloat64,       &P_UpdateTime);
        createParam(P_WaveformString,           asynParamFloat64Array,  &P_Waveform);
        createParam(P_TimeBaseString,           asynParamFloat64Array,  &P_TimeBase);
        createParam(P_MinValueString,           asynParamFloat64,       &P_MinValue);
        createParam(P_MaxValueString,           asynParamFloat64,       &P_MaxValue);
        createParam(P_MeanValueString,          asynParamFloat64,       &P_MeanValue);

        /* alloc space for vert per divistion strings */
        for (i = 0; i < NUM_VERT_SELECTIONS; i++){
                voltsPerDivValues_[i] = 0;
                voltsPerDivSeverities_[i] = 0;
                voltsPerDivStrings_[i] = (char *)calloc(MAX_ENUM_STRING_SIZE,   sizeof(char));
        }

        setIntegerParam(P_MaxPoints,            maxPoints);
        setIntegerParam(P_Run,                  0);
        setIntegerParam(P_VertGainSelect,       10);
        /* set the arrays voltsPerDivValues_,  voltsPerDivString_ according to P_VertGainSelect parameter*/
        setVertGain();
        setDoubleParam(P_VoltsPerDiv,           1.0);
        setDoubleParam(P_VoltOffset,            0.0);
        setDoubleParam(P_TriggerDelay,          0.0);
        setDoubleParam(P_NoiseAmplitude,        0.1);
        setDoubleParam(P_UpdateTime,            1);
        setDoubleParam(P_TimePerDiv,            0.001);
        setDoubleParam(P_MinValue,              0.0);
        setDoubleParam(P_MaxValue,              0.0);
        setDoubleParam(P_MeanValue,             0.0);

        printf("Come after Create Parameters and set defaults for these parameters\n");
        printf("Come before create background thread\n");
        status = (asynStatus)(epicsThreadCreate("simScope",
                        epicsThreadPriorityMedium,
                        epicsThreadGetStackSize(epicsThreadStackMedium),
                        (EPICSTHREADFUNC)::simTask,
                        (void *)this) == NULL);
        printf("Come after create background thread\n");

        if (status){
                printf("%s:%s: epicsThreadCreate failure\n", driverName, functionName);
                return;
        }

        printf("Come to the end of contructing simScope Intances: portName: %s, maxPoints:%d\n", portName, maxPoints);
}

void simScope::setVertGain()
{
        epicsInt32 igain, i;
        double gain;

        // P_VertGainSelect for mbbo  to Vert Gain
        getIntegerParam(P_VertGainSelect,       &igain);
        gain =(epicsFloat64) igain;
        setDoubleParam(P_VertGain, gain);

        printf("VertGainSelect: %d, VertGain: %lf\n", igain, gain);

        for (i = 0; i < NUM_VERT_SELECTIONS; i++){
                epicsSnprintf(voltsPerDivStrings_[i], MAX_ENUM_STRING_SIZE, "%.2f",allVoltsPerDivSelections[i] / gain);
                voltsPerDivValues_[i] = (int)(allVoltsPerDivSelections[i] / gain * 1000 + 0.5);
                printf("%d: V/Div=%d, %s\n", i+1, voltsPerDivValues_[i], voltsPerDivStrings_[i]);
        }

        //doCallbacksEnum(voltsPerDivStrings_, voltsPerDivValues_, voltsPerDivSeverities_, NUM_VERT_SELECTIONS, P_VoltsPerDivSelect, 0);
        doCallbacksEnum(voltsPerDivStrings_, voltsPerDivValues_, voltsPerDivSeverities_, NUM_VERT_SELECTIONS, P_VoltsPerDivSelect, 0);
}




void simScope::setVoltsPerDiv()
{
        epicsInt32 mVPerDiv;

        getIntegerParam(P_VoltsPerDivSelect,    &mVPerDiv);
        setDoubleParam(P_VoltsPerDiv,           mVPerDiv / 1000.0);
        printf("VoltsPerDivSelect: %d, VoltsPerDiv: %lf\n", mVPerDiv, mVPerDiv/1000.0);
}


/*
 * P_TimePerDivSelect parameter is in micro second
 * P_TimePerDiv parameter is in second
 * */
void simScope::setTimePerDiv()
{
        epicsInt32 microSecPerDiv;

        getIntegerParam(P_TimePerDivSelect,     µSecPerDiv);
        setDoubleParam(P_TimePerDiv,            microSecPerDiv / 1000000.0);
}

asynStatus simScope::writeInt32(asynUser * pasynUser, epicsInt32 value)
{
        int function = pasynUser->reason;
        asynStatus status = asynSuccess;
        const char * paramName;
        const char * functionName = "writeInt32";

        /* set the value for the parameter */
        status = (asynStatus) setIntegerParam(function, value);
        /*  get name of the parameter */
        getParamName(function, ¶mName);

        if (function == P_Run){
                if (value) epicsEventSignal(eventId_);
        }
        else if (function == P_VertGainSelect){
                setVertGain();
        }
        else if (function == P_VoltsPerDivSelect){
                setVoltsPerDiv();
        }
        else if (function == P_TimePerDivSelect){
                setTimePerDiv(); // set P_TimePerDiv parameter according to P_TimePerDivSelect parameter
        }
        else{
        }

        status = (asynStatus) callParamCallbacks();

        if (status){
                epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s:%s: status=%d, functino=%d,parameter name=%s, value=%d", driverName, functionName, status, function, paramName, value);
        }
        else{
                asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d,parameter name=%s, value=%d", driverName, functionName, function, paramName, value);
        }

        return status;
}

asynStatus simScope::writeFloat64(asynUser * pasynUser, epicsFloat64 value)
{
        int function = pasynUser->reason;
        asynStatus status;
        epicsInt32 run;
        const char * paramName;
        const char * functionName = "writeFloat64";

        status = (asynStatus)setDoubleParam(function, value);

        getParamName(function, ¶mName);

        if (function == P_UpdateTime){
                if (value < MIN_UPDATE_TIME){
                        asynPrint(pasynUser, ASYN_TRACE_WARNING, "%s:%s warning, update time too small, changed from %f to %f\n", driverName, functionName, value, MIN_UPDATE_TIME);
                        value = MIN_UPDATE_TIME;
                        setDoubleParam(P_UpdateTime, value);
                }

                getIntegerParam(P_Run, &run);
        }
        else{
        }

        status = (asynStatus) callParamCallbacks();
        if (status){
                epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s:%s: status=%d, function=%d, parameter name=%s, value=%f",
                                driverName, functionName, status, function, paramName, value);
        }
        else{
                asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d, parameter name = %s, value = %f\n", driverName, functionName, function, paramName, value);
        }

        return status;
}

asynStatus simScope::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value , size_t nElements, size_t *nIn)
{
        int function = pasynUser->reason;
        size_t nCopy;
        epicsInt32 maxPoints;
        asynStatus status = asynSuccess;
        epicsTimeStamp timeStamp;
        const char *functionName = "readFloat64Array";
        const char * paramName;

        getTimeStamp(&timeStamp);
        pasynUser->timestamp = timeStamp;
        getIntegerParam(P_MaxPoints, &maxPoints);
        nCopy = maxPoints;
        getParamName(function, ¶mName);

        if (nElements < nCopy) nCopy = nElements;
        if (function == P_Waveform){
                memcpy(value, pData_, nCopy * sizeof(epicsFloat64));
                * nIn = nCopy;
        }
        else if (function == P_TimeBase){
                memcpy(value, pTimeBase_, nCopy * sizeof(epicsFloat64));
                * nIn = nCopy;
        }

        if(status){
                epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s:%s: status=%d, function=%d, parameter name=%s", driverName,  functionName, status, function, paramName);
        }
        else{
                asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d, parameter name=%s\n", driverName, functionName, function, paramName);
        }

        return status;
}

asynStatus simScope::readEnum(asynUser * pasynUser, char *strings[], int values[], int severities[], size_t nElements, size_t *nIn)
{
        int function = pasynUser->reason;
        size_t i;

        if (function == P_VoltsPerDivSelect){
                for (i = 0; ((i < NUM_VERT_SELECTIONS) && (i < nElements)); i++){
                        if (strings[i]) free(strings[i]);
                        strings[i] = epicsStrDup(voltsPerDivStrings_[i]);
                        values[i] = voltsPerDivValues_[i];
                        severities[i] = 0;
                }
        }
        else{
                *nIn = 0;
                return asynError;
        }

        *nIn = i;

        return asynSuccess;
}

void simScope::simTask()
{
        double timePerDiv, voltsPerDiv, voltOffset, triggerDelay, noiseAmplitude;
        double updateTime, minValue, maxValue, meanValue;
        double time, timeStep;
        double noise, yScale;
        epicsInt32 run, i, maxPoints;
        double pi = 3.1415926;

        printf("Enter in the simTask() functinon:\n");
        lock();

        printf("Enter in loop forever:\n");
        while (1){
                getDoubleParam(P_UpdateTime, &updateTime);
                getIntegerParam(P_Run, &run);

                printf("updateTime: %f, run: %d\n", updateTime, run);
                unlock();

                if (run) {
                        epicsEventWaitWithTimeout(eventId_, updateTime);
                }
                else{
                        printf("Wait for running signal\n");
                        epicsEventWait(eventId_);
                        printf("Receive the running signal\n");
                }

                lock();

                getIntegerParam(P_Run, &run);

                if (!run){
                        continue;
                }

                getIntegerParam(P_MaxPoints, &maxPoints);
                getDoubleParam(P_TimePerDiv, &timePerDiv);
                getDoubleParam(P_VoltsPerDiv, &voltsPerDiv);
                getDoubleParam(P_VoltOffset, &voltOffset);
                getDoubleParam(P_TriggerDelay, &triggerDelay);
                getDoubleParam(P_NoiseAmplitude, &noiseAmplitude);

                getDoubleParam(P_UpdateTime, &updateTime);
                printf("maxpoints:%d, timeperdiv:%f, voltsPerDiv:%f, voltoffset:%f, triggerdelay:%f, noiseampitude:%f, updatetime:%f\n",
                                maxPoints, timePerDiv, voltsPerDiv, voltOffset, triggerDelay, noiseAmplitude, updateTime);
                time = triggerDelay;
                timeStep = timePerDiv * NUM_DIVISIONS / maxPoints;
                minValue = 1e6;
                maxValue = -1e6;
                meanValue = 0.;

                yScale = 1.0 / voltsPerDiv;
                printf("timeStep:%f\n", timeStep);

                for (i = 0; i < maxPoints; i++){
                        noise = noiseAmplitude * (rand() / (double)RAND_MAX - 0.5);
                        pData_[i] = AMPLITUDE * (sin(time * FREQUENCY * 2 * pi)) + noise;
                        if (pData_[i] < minValue){
                                minValue = pData_[i];
                        }
                        if (pData_[i] > maxValue){
                                maxValue = pData_[i];
                        }
                        meanValue += pData_[i];
                        pData_[i] = NUM_DIVISIONS / 2 + yScale * (pData_[i] + voltOffset);
                        time += timeStep;
                }

                updateTimeStamp();
                meanValue = meanValue / maxPoints;

                setDoubleParam(P_MinValue, minValue);
                setDoubleParam(P_MaxValue, maxValue);
                setDoubleParam(P_MeanValue, meanValue);

                printf("min:%f, max:%f, mean:%f\n", minValue, maxValue, meanValue);
                callParamCallbacks();
                doCallbacksFloat64Array(pData_, maxPoints, P_Waveform, 0);
        }
}

void simTask(void * drvPvt)
{
        simScope * pPvt = (simScope *)drvPvt;
        pPvt->simTask();
}


extern "C"{
int simScopeConfigure(const char * portName, int maxPoints)
{
        new simScope(portName, maxPoints);
        return asynSuccess;
}

static const iocshArg initArg0 = {"portName", iocshArgString};
static const iocshArg initArg1 = {"max points", iocshArgInt};
static const iocshArg * const initArgs[] = {&initArg0, &initArg1};

static const iocshFuncDef initFuncDef = {"simScopeConfigure", 2, initArgs};

static void initCallFunc(const iocshArgBuf * args)
{
        simScopeConfigure(args[0].sval, args[1].ival);
}

void simScopeRegister(void)
{
        iocshRegister(&initFuncDef, initCallFunc);
}

epicsExportRegistrar(simScopeRegister);
}

c)  simScopeSupport.dbd:

registrar("simScopeRegister")

d) 修改所编写源文件目录下的Makefile文件,指定需要链接的库文件以及源文件及支持文件:

TOP=../..

include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================

#=============================
# Build the IOC application

PROD_IOC = simScope
# simScope.dbd will be created and installed
DBD += simScope.dbd

# simScope.dbd will be made up from these files:
simScope_DBD += base.dbd
simScope_DBD += simScopeSupport.dbd

# Include dbd files from all support applications:
simScope_DBD += asyn.dbd

# Add all the support libraries needed by this IOC
simScope_LIBS += asyn


simScope_SRCS += simScope.cpp
# simScope_registerRecordDeviceDriver.cpp derives from simScope.dbd
simScope_SRCS += simScope_registerRecordDeviceDriver.cpp

# Build the main IOC entry point on workstation OSs.
simScope_SRCS_DEFAULT += simScopeMain.cpp
simScope_SRCS_vxWorks += -nil-

# Add support from base/src/vxWorks if needed
#simScope_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary

# Finally link to the EPICS Base libraries
simScope_LIBS += $(EPICS_BASE_IOC_LIBS)

#===========================

include $(TOP)/configure/RULES
#----------------------------------------
#  ADD RULES AFTER THIS LINE

4) 3) 进入simScopeApp/Db/目录下下编写记录支持数据库文件simScope.db并且将其添加到相同路径下的Makefile文件中:

# These records control run/stop --> P_Run
record(bo, "$(P)$(R)Run")
{
        field(PINI,     "1")
        field(DTYP,     "asynInt32")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_RUN")
        field(ZNAM,     "Stop")
        field(ONAM,     "Run")
}

record(bi, "$(P)$(R)Run_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynInt32")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_RUN")
        field(ZNAM,     "Done")
        field(ONAM,     "Running")
        field(OSV,      "MINOR")
        field(SCAN,     "I/O Intr")
}

## This record is the number of points in the data array ---> P_MaxPoints
## readonly, set in startup
record(longin, "$(P)$(R)MaxPoints_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynInt32")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_MAX_POINTS")
        field(SCAN,     "I/O Intr")
}

# There recrods are the choices for the Time Per Div Select ---> P_TimePerDivSelect
record(mbbo, "$(P)$(R)TimePerDivSelect")
{
        field(PINI,     "1")
        field(DTYP,     "asynInt32")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_TIME_PER_DIV_SELECT")
        field(ZRST,     "0.01 msec")
        field(ZRVL,     "10")
        field(ONST,     "0.02 msec")
        field(ONVL,     "20")
        field(TWST,     "0.05 msec")
        field(TWVL,     "50")
        field(THST,     "0.1 msec")
        field(THVL,     "100")
        field(FRST,     "0.2 msec")
        field(FRVL,     "200")
        field(FVST,     "0.5 msec")
        field(FVVL,     "500")
        field(SXST,     "1 msec")
        field(SXVL,     "1000")
        field(SVST,     "2 msec")
        field(SVVL,     "2000")
        field(EIST,     "5 msec")
        field(EIVL,     "5000")
        field(NIST,     "10 msec")
        field(NIVL,     "10000")
        field(TEST,     "20 msec")
        field(TEVL,     "20000")
        field(ELST,     "50 msec")
        field(ELVL,     "50000")
        field(TVST,     "100 msec")
        field(TVVL,     "100000")
}
#
## P_TimePerDiv
record(ai, "$(P)$(R)TimePerDiv_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_TIME_PER_DIV")
        field(PREC,     "5")
        field(SCAN,     "I/O Intr")
}
#
## These records is for Vert Gain
## P_VertGainSelect
record(mbbo,    "$(P)$(R)VertGainSelect")
{
        field(PINI,     "1")
        field(DTYP,     "asynInt32")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_VERT_GAIN_SELECT")
        field(ZRST,     "1 X")
        field(ZRVL,     "1")
        field(ONST,     "2 X")
        field(ONVL,     "2")
        field(TWST,     "5 X")
        field(TWVL,     "5")
        field(THST,     "10 X")
        field(THVL,     "10")
        field(FRST,     "100 X")
        field(FRVL,     "100")
}

# P_VertGain
record(ai,      "$(P)$(R)VertGain_RBV")
{
        field(PINI,     "1")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_VERT_GAIN")
        field(DTYP,     "asynFloat64")
        field(PREC,     "1")
        field(SCAN,     "I/O Intr")
}
#
#
record(mbbo, "$(P)$(R)VoltsPerDivSelect")
{
   field(PINI, "1")
   field(DTYP, "asynInt32")
   field(OUT,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_VOLTS_PER_DIV_SELECT")
   field(ZRST, "Garbage")
   field(ZRVL, "0")
}
#
record(mbbi, "$(P)$(R)VoltsPerDivSelect_RBV")
{
   field(DTYP, "asynInt32")
   field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_VOLTS_PER_DIV_SELECT")
   field(ZRST, "Garbage")
   field(ZRVL, "0")
   field(SCAN, "I/O Intr")
}
#
record(ai, "$(P)$(R)VoltsPerDiv_RBV")
{
   field(PINI, "1")
   field(DTYP, "asynFloat64")
   field(INP,  "@asyn($(PORT),$(ADDR),$(TIMEOUT))SCOPE_VOLTS_PER_DIV")
   field(PREC, "2")
   field(SCAN, "I/O Intr")
}
## This record to set the offset
## P_VoltOffset
record(ao,      "$(P)$(R)VoltOffset")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_VOLT_OFFSET")
        field(PREC,     "3")
}

record(ai,      "$(P)$(R)VoltOffset_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_VOLT_OFFSET")
        field(PREC,     "3")
        field(SCAN,     "I/O Intr")
}

# This record to set trigger delay time
record(ao,      "$(P)$(R)TriggerDelay")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_TRIGGER_DELAY")
        field(PREC,     "5")
}

record(ai,      "$(P)$(R)TriggerDelay_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_TRIGGER_DELAY")
        field(PREC,     "5")
        field(SCAN,     "I/O Intr")
}

# This record to control noise in the signal
# P_NoiseAmplitude
record(ao,      "$(P)$(R)NoiseAmplitude")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_NOISE_AMPLITUDE")
        field(PREC,     "3")
}


record(ai,      "$(P)$(R)NoiseAmplitude_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_NOISE_AMPLITUDE")
        field(PREC,     "3")
        field(SCAN,     "I/O Intr")
}
#
# This record to control the update time
record(ao,      "$(P)$(R)UpdateTime")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(OUT,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_UPDATE_TIME")
        field(PREC,     "3")
}

record(ai,      "$(P)$(R)UpdateTime_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_UPDATE_TIME")
        field(PREC,     "3")
        field(SCAN,     "I/O Intr")
}

# This record is waveform
record(waveform,        "$(P)$(R)Waveform_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64ArrayIn")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_WAVEFORM")
        field(NELM,     "$(NPOINTS)")
        field(FTVL,     "DOUBLE")
        field(LOPR,     "0")
        field(HOPR,     "10")
        field(SCAN,     "I/O Intr")
}

# This record is time base
record(waveform,        "$(P)$(R)TimeBase_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64ArrayIn")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_TIME_BASE")
        field(NELM,     "$(NPOINTS)")
        field(FTVL,     "DOUBLE")
        field(LOPR,     "0")
        field(HOPR,     "10")
        field(SCAN,     "I/O Intr")
}

# This record is min value
record(ai,      "$(P)$(R)MinValue_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_MIN_VALUE")
        field(PREC,     "4")
        field(SCAN,     "I/O Intr")
}


record(ai,      "$(P)$(R)MaxValue_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_MAX_VALUE")
        field(PREC,     "4")
        field(SCAN,     "I/O Intr")
}

record(ai,      "$(P)$(R)MeanValue_RBV")
{
        field(PINI,     "1")
        field(DTYP,     "asynFloat64")
        field(INP,      "@asyn($(PORT), $(ADDR), $(TIMEOUT))SCOPE_MEAN_VALUE")
        field(PREC,     "4")
        field(SCAN,     "I/O Intr")
}

Makefile中添加:DB += simScope.db

5)回到这个IOC的顶层目录,即:simScope,执行make命令,进行程序编译。

6)进入启动目录iocBoot/iocsimScope,修改启动脚本文件st.cmd:

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

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

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/simScope.dbd"
simScope_registerRecordDeviceDriver pdbbase
simScopeConfigure("testSimScope", 1000)

## Load record instances
dbLoadRecords("db/simScope.db","P=SimScope:,R=Device1:,PORT=testSimScope,ADDR=0,TIMEOUT=1, NPOINTS=1000")

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

7) 启动这个IOC程序:

../../bin/linux-aarch64/simScope st.cmd

8) 查看这个IOC下的所有加载记录:

epics> dbl
SimScope:Device1:TimePerDiv_RBV
SimScope:Device1:VertGain_RBV
SimScope:Device1:VoltsPerDiv_RBV
SimScope:Device1:VoltOffset_RBV
SimScope:Device1:TriggerDelay_RBV
SimScope:Device1:NoiseAmplitude_RBV
SimScope:Device1:UpdateTime_RBV
SimScope:Device1:MinValue_RBV
SimScope:Device1:MaxValue_RBV
SimScope:Device1:MeanValue_RBV
SimScope:Device1:VoltOffset
SimScope:Device1:TriggerDelay
SimScope:Device1:NoiseAmplitude
SimScope:Device1:UpdateTime
SimScope:Device1:Run_RBV
SimScope:Device1:Run
SimScope:Device1:MaxPoints_RBV
SimScope:Device1:VoltsPerDivSelect_RBV
SimScope:Device1:TimePerDivSelect
SimScope:Device1:VertGainSelect
SimScope:Device1:VoltsPerDivSelect
SimScope:Device1:Waveform_RBV
SimScope:Device1:TimeBase_RBV

9) 使用CSS显示以上运行的记录数据库:

在Settings区域,可以选择设置垂直增益,每个刻度电压值,电压偏移,触发延时,正弦波更新周期,以及每个水平刻度表示的时间量。

在User Operate区域中,可以启动/停止波形的产生。

在Running Status区域可以显示运行状态。

在Statics Info区域中显示波形数据的统计信息。

仿真数字正弦波发生器程序_第1张图片

你可能感兴趣的:(EPICS教程,Linux,C,EPICS,C语言,linux)