串口是一种常见的通信总线技术,其支持全双工模式,且只支持一对一的访问模式,大部分设备都支持串口通讯,可通过串口控制设备或采集数据。下面将介绍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,如下图所示:
运行串口测试工程,配置串口号为4,然后打开串口,往发送文本框中输入要发送的数据Hello,然后单击发送,可以看到在接收文本框中可以看到显示Hello,如下图所示:
上面是纯粹的串口发送和显示测试,没有进行串口数据封包,单击界面上的封包单选按钮,串口数据将被封包和解包,如下图所示: