LabwindowsCVI 串口编程及事例

       串口是一种常见的通信总线技术,其支持全双工模式,且只支持一对一的访问模式,大部分设备都支持串口通讯,可通过串口控制设备或采集数据。下面将介绍LabwindowsCVI对串口的支持。

 

OpenComConfig:

       OpenComConfig用于打开并配置Com设备,其函数原型如下所示:

int OpenComConfig (int portNumber, char deviceName[], long baudRate, int parity, int dataBits, int stopBits, int inputQueueSize, int outputQueueSize);

其中portNumber为Com口号,deviceName为设备名,baudRate为波特率,parity为奇偶校验,dataBits为数据位,stopBits位停止位,inputQueueSize为输入队列的大小,outputQueueSize为输出队列的大小。

 

CloseCom:

       CloseCom用于关闭Com口,其函数原型如下所示:

       int CloseCom (int portNumber);

       其中portNumber为打开的Com口。

 

ComRd:

       ComRd用于读取Com口的接收数据,其函数原型如下所示:

       int ComRd (int portNumber, char buffer[], size_t count);

       其中portNumber为打开的Com口,buffer为读取的数据缓存,count为要读取的数据的大小。注意当count的值大于输入队列数据缓存的大小,该函数将阻塞一段时间直到超时完成或输入队列里的数据大于count。

 

ComWrt:

       ComWrt用于往Com口发送数据,其函数原型如下所示:

       int ComWrt (int portNumber, char buffer[], size_t count);

       其中portNumber为打开的Com口,buffer为要发送的数据,count为要发送的数据大小。

 

FlushInQ:

       FlushInQ用于清除Com口输入队列的缓存数据,其函数原型如下所示:

       int FlushInQ (int portNumber);

       其中portNumber口为打开的Com口。

 

FlushOutQ:

       FlushOutQ用于清除Com口输出队列的缓存数据,其函数原型如下所示:

       int FlushOutQ (int portNumber);

       其中portNumber口为打开的Com口。

 

 

 

 

GetInQLen:

       GetInQLen用于得到Com口的输入队列数据缓存的大小,其函数原型如下所示:

int GetInQLen (int portNumber);

其中portNumber口为打开的Com口。

 

GetOutQLen:

       GetOutQLen用于得到Com口的输出队列数据缓存的大小,其函数原型如下所示:

int GetOutQLen (int portNumber);

其中portNumber口为打开的Com口。

 

ReturnRS232Err:

       ReturnRS232Err用于得到串口的错误码,其函数原型如下所示:

       int ReturnRS232Err (void);

      

GetRS232ErrorString

       GetRS232ErrorString用于得到串口错误码的字符串描述,其函数原型如下所示:

       char *GetRS232ErrorString (int errorNumber);

       其中errorNumber为ReturnRS232Err得到的错误码。

串口数据封包:

       为什么要对串口数据进行封包呢?1、识别数据包的开头和结尾;2、加强数据包的校验能力。一般封包协议如下所示:

 

包头(2byte)

0xAA55

长度(1 byte)

0~255

数据(0~255 byte)

校验(1 byte)

      

其中校验一般采用异或的方式,长度为包头到数据。

项目实践:

       新建一个LabwindowsCVI工程,创建一个后台工作线程,该线程执行Com数据的发送和接收,其代码如下所示:

#include
#include
#include
#include         
#include
#include "ComTest.h"

static int panelHandle;

CmtThreadFunctionID backgroundThreadFunctionID;
volatile int AppRunningFlag = 0;
CmtThreadPoolHandle threadPoolHandle;
char errorStringBuffer[256];
int CVICALLBACK BackgroundThreadFunction (void *functionData);

int PacketComData(char *data,uint8_t dataLen);
void ComDecodeProcess(uint8_t *data,int dataLen);

int CreateBackgroundThread(void)
{
    int ret = -1;
    ret = CmtNewThreadPool (1, &threadPoolHandle);    
    
    if(ret < 0)
    {
        CmtGetErrorMessage(ret,errorStringBuffer);
        printf("%s\r\n",errorStringBuffer);
    }
    else
    {
        ret = CmtScheduleThreadPoolFunctionAdv(threadPoolHandle,BackgroundThreadFunction,NULL,THREAD_PRIORITY_HIGHEST,NULL,EVENT_TP_THREAD_FUNCTION_END,NULL,RUN_IN_SCHEDULED_THREAD,&backgroundThreadFunctionID);
        
        if(ret < 0)
        {
            CmtGetErrorMessage(ret,errorStringBuffer);
            printf("%s\r\n",errorStringBuffer); 
        }
    }
    return ret;
}

int QuitBackgroundThread(void)
{
    CmtWaitForThreadPoolFunctionCompletion(threadPoolHandle,backgroundThreadFunctionID,OPT_TP_PROCESS_EVENTS_WHILE_WAITING);    
    return 0;
}


int portNum = 0;
int baudRate = 0;
int parity = 0;
int dataBits = 0;
int stopBits = 0;
int portOpenFlag = 0;

int sendDataLen = 0;
char sendData[512];
volatile int sendDataFlag = 0;

int sendDataCnt = 0;
int receiveDataCnt = 0;
char receiveData[513];
volatile int packetComDataFlag = 0; 


int CVICALLBACK BackgroundThreadFunction (void *functionData)
{
    int len = 0;
    
    AppRunningFlag = 1;
    while(AppRunningFlag)
    {
        Delay(0.01);
        if(sendDataFlag > 0)
        {
            if(portOpenFlag > 0)
            {
                if(packetComDataFlag > 0)
                {
                    PacketComData(sendData,sendDataLen);     
                }
                else
                {
                    ComWrt(portNum,sendData,sendDataLen);
                    sendDataCnt = sendDataCnt + sendDataLen;
                }
                SetCtrlVal(panelHandle,PANEL_NUMERIC_TX_CNT,sendDataCnt);
            }
            sendDataFlag = 0;
        }
        if(portOpenFlag > 0)
        {
            len = GetInQLen(portNum);
            if(len > 0)
            {
                if(len > 512)
                {
                    ComRd(portNum,receiveData,512);
                    if(packetComDataFlag > 0)
                    {
                        ComDecodeProcess(receiveData,512);    
                    }
                    else
                    {
                        receiveData[512] = 0;
                        receiveDataCnt = receiveDataCnt + 512;
                        SetCtrlVal(panelHandle,PANEL_TEXTBOX_RX,receiveData);
                        SetCtrlVal(panelHandle,PANEL_NUMERIC_RX_CNT,receiveDataCnt);
                    }
                }
                else
                {
                    ComRd(portNum,receiveData,len);
                    if(packetComDataFlag > 0)
                    {
                        ComDecodeProcess(receiveData,len);    
                    }
                    else
                    {
                        receiveData[len] = 0;
                        receiveDataCnt = receiveDataCnt + len;
                        SetCtrlVal(panelHandle,PANEL_TEXTBOX_RX,receiveData);
                        SetCtrlVal(panelHandle,PANEL_NUMERIC_RX_CNT,receiveDataCnt);    
                    }
                }

            }
        }
    }
    return 0;
}


int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0)
        return -1;    /* out of memory */
    if ((panelHandle = LoadPanel (0, "ComTest.uir", PANEL)) < 0)
        return -1;
    DisplayPanel (panelHandle);
    CreateBackgroundThread();
    RunUserInterface ();
    QuitBackgroundThread();
    DiscardPanel (panelHandle);
    return 0;
}

int CVICALLBACK quit (int panel, int control, int event,
                      void *callbackData, int eventData1, int eventData2)
{
    switch (event)
    {
        case EVENT_COMMIT:
            AppRunningFlag = 0;
            QuitUserInterface(0);
            break;
    }
    return 0;
}

int CVICALLBACK AppOpenCom (int panel, int control, int event,
                            void *callbackData, int eventData1, int eventData2)
{
    int onOffFlag = 0;
    int ret = 0;
    GetCtrlVal(panel,control,&onOffFlag);
    switch (event)
    {
        case EVENT_COMMIT:
            if(onOffFlag > 0)
            {
                if(portOpenFlag == 0)
                {
                    GetCtrlVal(panel,PANEL_NUMERIC_PORT,&portNum);
                    GetCtrlVal(panel,PANEL_NUMERIC_BR,&baudRate);
                    GetCtrlVal(panel,PANEL_RING_PARITY,&parity);
                    GetCtrlVal(panel,PANEL_RING_DB,&dataBits);
                    GetCtrlVal(panel,PANEL_RING_SB,&stopBits);
                    ret = OpenComConfig(portNum,"",baudRate,parity,dataBits,stopBits,512,512);
                    if(ret < 0)
                    {
                        portOpenFlag = 0;
                        SetCtrlVal(panel,control,0);
                        printf("%s\r\n",GetRS232ErrorString(ret));
                    }
                    else
                    {
                        portOpenFlag = 1;    
                    }
                }
            }
            else
            {
                if(portOpenFlag > 0)
                {
                    CloseCom(portNum);
                    portOpenFlag = 0;
                }
            }
            break;
    }
    return 0;
}

int CVICALLBACK AppClearWin (int panel, int control, int event,
                             void *callbackData, int eventData1, int eventData2)
{
    switch (event)
    {
        case EVENT_COMMIT:
            SetCtrlVal(panel,PANEL_NUMERIC_RX_CNT,0);
            SetCtrlVal(panel,PANEL_NUMERIC_TX_CNT,0);
            ResetTextBox(panel,PANEL_TEXTBOX_RX,"");
            sendDataCnt = 0;
            receiveDataCnt = 0;
            break;
    }
    return 0;
}


int CVICALLBACK AppSendData (int panel, int control, int event,
                             void *callbackData, int eventData1, int eventData2)
{
    switch (event)
    {
        case EVENT_COMMIT:
            GetCtrlVal(panel,PANEL_STRING_TX,sendData);
            sendDataLen = strlen(sendData);
            sendDataFlag = 1;
            break;
    }
    return 0;
}

 

int CVICALLBACK AppPacket (int panel, int control, int event,
                           void *callbackData, int eventData1, int eventData2)
{
    switch (event)
    {
        case EVENT_COMMIT:
            GetCtrlVal(panel,control,&packetComDataFlag);
            break;
    }
    return 0;
}

typedef enum
{
    COM_GET_HEADER1 = 0,
    COM_GET_HEADER2,
    COM_GET_LEN,
    COM_GET_DATA,
    COM_GET_CHECK
}ComDecodeState;
ComDecodeState comDecodeState = COM_GET_HEADER1;

uint8_t payloadLen = 0;
uint8_t payloadLenCnt = 0;
char payload[512];

uint8_t ComDecodeCheckCal(char *data,int dataLen)
{
    int i;
    uint8_t check = 0;
    
    for(i=0;i     {
        check =check ^ data[i];    
    }
    return check;
}

uint8_t checkSumRx = 0;
uint8_t checkSumCal = 0;

char frameDataRx[512];
int frameDataRxLen = 0;
void ComDecodeProcess(uint8_t *data,int dataLen)
{
    int i;
    for(i=0;i     {
        switch(comDecodeState)
        {
            case COM_GET_HEADER1:
                if(data[i] == 0xAA)
                {
                    comDecodeState = COM_GET_HEADER2;
                    frameDataRx[frameDataRxLen++] = data[i];
                }
                break;
            case COM_GET_HEADER2:
                if(data[i] == 0x55)
                {
                    comDecodeState = COM_GET_LEN;
                    frameDataRx[frameDataRxLen++] = data[i]; 
                }
                else
                {
                    comDecodeState = COM_GET_HEADER1;
                    frameDataRxLen = 0;
                }
                break;
            case COM_GET_LEN:
                comDecodeState = COM_GET_DATA;
                payloadLen = data[i];
                payloadLenCnt = 0;
                frameDataRx[frameDataRxLen++] = data[i]; 
                break;
            case COM_GET_DATA:
                if(payloadLenCnt < payloadLen)
                {
                    frameDataRx[frameDataRxLen++] = data[i];
                    payloadLenCnt++;
                    if(payloadLenCnt == payloadLen)
                    {
                        comDecodeState = COM_GET_CHECK;    
                    }
                }
                else
                {
                    comDecodeState = COM_GET_HEADER1;
                    frameDataRxLen = 0;
                }
                break;
            case COM_GET_CHECK:
                frameDataRx[frameDataRxLen++] = data[i];  
                checkSumRx = data[i];
                checkSumCal = ComDecodeCheckCal(frameDataRx,frameDataRxLen - 1);
                if(checkSumRx != checkSumCal)
                {
                    printf("checkSum error\r\n");        
                }
                else
                {
                    //校验成功
                    frameDataRx[frameDataRxLen - 1] = 0;
                    SetCtrlVal(panelHandle,PANEL_TEXTBOX_RX,&frameDataRx[3]); 
                }
                comDecodeState = COM_GET_HEADER1;
                frameDataRxLen = 0;
                break;
            default:
                comDecodeState = COM_GET_HEADER1;
                frameDataRxLen = 0;
                ;
        }
    }
}

char frameDataTx[512];
int frameDataTxLen = 0;

int PacketComData(char *data,uint8_t dataLen)
{
    int i;
    frameDataTx[0] = 0xAA;
    frameDataTx[1] = 0x55;
    frameDataTx[2] = dataLen;
    for(i=0;i     {
        frameDataTx[3 + i] = data[i];    
    }
    frameDataTx[3+i] = ComDecodeCheckCal(frameDataTx,dataLen + 3);
    
    if(portOpenFlag > 0)
    {
        ComWrt(portNum,frameDataTx,dataLen + 4);
        return 1;
    }
    else
    {
        return -1;    
    }
}

实践效果:

       找一个USB转TTL的转接板,插入电脑的USB口,并安装该转接板的驱动,然后用杜邦线将TXD和RXD连接起来,实现自发自收的功能。打开电脑的设备管理器,查看该转接板的串口号,从图中可以看出该串口号为 4,如下图所示:

LabwindowsCVI 串口编程及事例_第1张图片

 

       运行串口测试工程,配置串口号为4,然后打开串口,往发送文本框中输入要发送的数据Hello,然后单击发送,可以看到在接收文本框中可以看到显示Hello,如下图所示:

LabwindowsCVI 串口编程及事例_第2张图片

 

       上面是纯粹的串口发送和显示测试,没有进行串口数据封包,单击界面上的封包单选按钮,串口数据将被封包和解包,如下图所示:

LabwindowsCVI 串口编程及事例_第3张图片

你可能感兴趣的:(LabwindowsCVI编程)