C++ WINDOWS下串口编程(QT为工程模板)

本文将依托QT工程,编写Windows下串口编程例子,此案例用到了两个串口COM1以及COM2

-Windows下串口编程需要底层提供的结构体以及函数,函数库

——DCB 结构体

typedef  struct  _DCB {
        
        DWORD DCBlength;           
        DWORD BaudRate;            
        DWORD fBinary:  1 ;          
        DWORD fParity:  1 ;          
        DWORD fOutxCtsFlow: 1 ;      
        DWORD fOutxDsrFlow: 1 ;      
        DWORD fDtrControl: 2 ;       
        DWORD fDsrSensitivity: 1 ;  
        DWORD fTXContinueOnXoff: 1 ; 
        DWORD fOutX:  1 ;            
        DWORD fInX:  1 ;             
        DWORD fErrorChar:  1 ;       
        DWORD fNull:  1 ;            
        DWORD fRtsControl: 2 ;       
        DWORD fAbortOnError: 1 ;     
        DWORD fDummy2: 17 ;         
        WORD wReserved;                     
        WORD XonLim;                 
        WORD XoffLim;                
        BYTE ByteSize;               
        BYTE Parity;                 
        BYTE StopBits;               
         char  XonChar;                
         char  XoffChar;               
         char  ErrorChar;              
         char  EofChar;                
         char  EvtChar;                
        WORD wReserved1;         
    } DCB; 

挑选几个常用的进行介绍:

DWORD DCBlength:DCB结构体长度
DWORD BaudRate:波特率
BYTE ByteSize:数据位
BYTE Parity:积偶校验位
BYTE StopBits:停止位

若使用一般串口通信则不需要进行流控,设置上述参数即可。

——函数及库说明:

1. 工程包含的库

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

2.使用流程

LPCWSTR lpFileName = "COM1";
HANDLE m_hcoml;
m_hcoml = CreateFile(lpFileName,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//打开串口  

(1) lpFileName:串口号
(2) dwDesiredAccess:GENERIC_READ | GENERIC_WRITE --读写模式
(3) pSecurityAttributes:NULL(0) --指向安全指针
(4) dwCreationDisposition:OPEN_EXISTING --打开已存在的串口
(5) dwFlagsAndAttributes:文件属性 --此处为同步模式,异步模式则填写FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED

SetupComm(m_hcoml,1024,1024);

设置缓冲区大小,此处为1024;

DCB dcb;
dcb.BaudRate = 115200;
dcb.Parity = NOPARITY;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;

波特率为115200,无奇偶校验,8位数据位,1位停止位

COMMTIMEOUTS timeouts;
timeouts.WriteTotalTimeoutMultiplier = 5000;
timeouts.WriteTotalTimeoutConstant = 5000;
timeouts.ReadIntervalTimeout = 10;
timeouts.ReadTotalTimeoutConstant = 10;
timeouts.ReadTotalTimeoutMultiplier = 10;
SetCommTimeouts(m_hcoml,&timeouts);

设置读写超时,根据实际需求填写即可。

PurgeComm(m_hcoml,PURGE_TXCLEAR | PURGE_RXCLEAR);

清空缓存区

SetCommMask(m_hcoml,EV_RXCHAR|EV_CTS|EV_DSR);

进行事件设置
EV_RXCHAR //收到数据
EV_CTS //清除发送信号有变化 CTS引脚电平有变化)
EV_DSR // 数据设备就绪状态有变化(DSR引脚电平有变化)

SetCommState(m_hcoml,&dcb);

函数设置COM口的设备控制块

//此处简写,后文会有完整代码贴出
typedef struct the{
     
    HANDLE *m_hcoml;
    OVERLAPPED *roverlapped;
    int comflag;
}thread_para;

thread_para *tp;
.....
.....
BOOL b_result;
unsigned char buffer[30]={
     0x1,0x2,0x3,0x4,0x5};
b_result = WriteFile(*(tp->m_hcoml),buffer,30,&strlength,tp->roverlapped);
      if(!b_result){
     
          WaitForSingleObject(tp->roverlapped->hEvent,INFINITE);
          GetOverlappedResult(tp->m_hcoml,tp->roverlapped,&strlength,false);
        }

串口发送函数–WriteFile
参数解释:
(1) HANDLE hFile:*(tp->m_hcoml)文件句柄
(2) LPCVOID lpBuffer:buffer// 数据缓存区指针
(3) DWORD nNumberOfBytesToWrite:30// 你要写的字节数
(4) LPDWORD lpNumberOfBytesWritten:&strlength // 用于保存实际写入字节数的存储区域的指针
(5) LPOVERLAPPED lpOverlapped :tp->roverlapped // OVERLAPPED结构体指针

检测事件状态–WaitForSingleObject
(1) HANDLE hObject:tp->roverlapped->hEvent//指明一个内核对象的句柄
(2) DWORD dwMilliseconds: INFINITE //等待时间,此处定义无限

检索某重叠操作:GetOverlappedResult
这个函数还不知道为什么用,既然别人都用了,那也按照大家的套路这么用吧。。

typedef struct the{
     
    HANDLE *m_hcoml;
    OVERLAPPED *roverlapped;
    int comflag;
}thread_para;

thread_para *tp;
.....
.....
BOOL b_result;
DWORD rec_size;
unsigned char recvbuffer[1024]={
     0};
 while(1){
     
    b_result = ReadFile(*(tp->m_hcoml),recbuffer,1024,&rec_size,tp->roverlapped);
         if(rec_size > 0){
     
             printf("com is %d,recv size is: %d data is ",tp->comflag,(size_t)rec_size);
             for(int i = 0;i<(unsigned long)rec_size;i++)
             printf("%2x",recbuffer[i]);
             printf("\r\n");
             memset(recbuffer,0x0,sizeof(recbuffer));
         }
       ::Sleep(10);
    }

串口发送函数–ReadFile
(1) HANDLE hFile:*(tp->m_hcoml)文件句柄
(2) LPCVOID lpBuffer:recvbuffer// 数据缓存区指针
(3) DWORD nNumberOfBytesToWrite:1024// 你要写的字节数
(4) LPDWORD lpNumberOfBytesWritten:& DWORD rec_size; // 用于保存实际写入字节数的存储区域的指针
(5) LPOVERLAPPED lpOverlapped :tp->roverlapped // OVERLAPPED结构体指针

3 详细代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int serialportthread(LPCWSTR lpFileName);
DWORD WINAPI sercom1(LPVOID lpParameter);
DWORD WINAPI sercom2(LPVOID lpParameter);
DWORD WINAPI sercomsendthread(void *data);
DWORD WINAPI sercomrecvthread(void *data);
void threadset();


typedef struct serportdata{
     
    LPCWSTR lparameter;
    int number;
}serport;

typedef struct the{
     
    HANDLE *m_hcoml;
    OVERLAPPED *roverlapped;
    int comflag;
}thread_para;





int main(int argc, char *argv[])
{
     
    threadset();
}

DWORD WINAPI sercom1(LPVOID lpParameter)
{
     
    serport *spc = (serport*)lpParameter;
    serialportthread(spc->lparameter);//传COM口参数
    return 0;
}


DWORD WINAPI sercom2(LPVOID lpParameter)
{
     
    serport *spc = (serport*)lpParameter;
    serialportthread(spc->lparameter);//传COM口参数
    return 0;
}

DWORD WINAPI sercomsendthread(void *data)
{
     
    thread_para *tp = (thread_para *)data;

    DWORD strlength = 5;
    DWORD rec_size;
    unsigned char buffer[30]={
     0x1,0x2,0x3,0x4,0x5};
    unsigned char recbuffer[1024]={
     0};
    BOOL b_result;

    while(1){
     
        ResetEvent(tp->roverlapped->hEvent);
        b_result = WriteFile(*(tp->m_hcoml),buffer,30,&strlength,tp->roverlapped);
        if(!b_result){
     
          WaitForSingleObject(tp->roverlapped->hEvent,INFINITE);
         GetOverlappedResult(tp->m_hcoml,tp->roverlapped,&strlength,false);
        }
         printf(" \r\n com is %d send strlen is %d\r\n",tp->comflag,strlength);
         ::Sleep(100);
            //if发生中断,break--此处没写,跟根据实际情况跳出
    }
    ExitThread(0);
}

DWORD WINAPI sercomrecvthread(void *data)
{
     
    thread_para *tp = (thread_para *)data;

    DWORD strlength = 5;
    DWORD rec_size;
    unsigned char buffer[5]={
     0x1,0x2,0x3,0x4,0x5};
    unsigned char recbuffer[1024]={
     0};
    BOOL b_result;
    while(1){
     
    b_result = ReadFile(*(tp->m_hcoml),recbuffer,1024,&rec_size,tp->roverlapped);
         if(rec_size > 0){
     
             printf(" \r\n com is %d,recv size is: %d data is ",tp->comflag,(size_t)rec_size);
             for(int i = 0;i<(unsigned long)rec_size;i++)
             printf("%2x",recbuffer[i]);
             printf("\r\n");
             memset(recbuffer,0x0,sizeof(recbuffer));
         }
       ::Sleep(10);
            //if发生中断,break--此处没写,跟根据实际情况跳出
    }
    ExitThread(0);
}


void threadset()
{
     
    serport Sp1,Sp2;
    Sp1.number = 1;
    Sp2.number = 2;
    Sp1.lparameter = __TEXT("COM1");
    Sp2.lparameter = __TEXT("COM2");

    LPSECURITY_ATTRIBUTES lpThreadAttributescom1 = 0;
    SIZE_T dwStackSizecom1 = 0;
    LPTHREAD_START_ROUTINE lpStartAddresscom1 = sercom1;
    LPVOID lpParametercom1 = (LPVOID)&Sp1;
    DWORD dwCreationFlagscom1 = 0;
    LPDWORD lpThreadIdcom1 = 0;
    HANDLE threadcom1;

    LPSECURITY_ATTRIBUTES lpThreadAttributescom2 = 0;
    SIZE_T dwStackSizecom2 = 0;
    LPTHREAD_START_ROUTINE lpStartAddresscom2 = sercom2;
    LPVOID lpParametercom2 = (LPVOID)&Sp2;
    DWORD dwCreationFlagscom2 = 0;
    LPDWORD lpThreadIdcom2 = 0;
    HANDLE threadcom2;

    threadcom1 = CreateThread(lpThreadAttributescom1,dwStackSizecom1,lpStartAddresscom1,lpParametercom1,dwCreationFlagscom1,lpThreadIdcom1);
    //创建COM1口初始化线程
    threadcom2 = CreateThread(lpThreadAttributescom2,dwStackSizecom2,lpStartAddresscom2,lpParametercom2,dwCreationFlagscom2,lpThreadIdcom2);
    //创建COM2口初始化线程
    while(1)
    {
     
        ::Sleep(10000);
    }
    //::exit(0);
}

int serialportthread(LPCWSTR lpFileName)
{
     
       HANDLE m_hcoml;

       m_hcoml = CreateFile(lpFileName,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
       if(m_hcoml == (HANDLE)-1)
       {
     
           printf("open serial faild!\r\n");
       }
       else{
     
           printf("open serial success!\r\n");

       }

       SetupComm(m_hcoml,1024,1024);

       DCB dcb;
       if(!GetCommState(m_hcoml,&dcb))
       {
     
           printf("fiald");
       }


       dcb.BaudRate = 115200;
       dcb.Parity = NOPARITY;
       dcb.ByteSize = 8;
       dcb.StopBits = ONESTOPBIT;


       COMMTIMEOUTS timeouts;

       timeouts.WriteTotalTimeoutMultiplier = 5000;
       timeouts.WriteTotalTimeoutConstant = 5000;

       timeouts.ReadIntervalTimeout = 10;
       timeouts.ReadTotalTimeoutConstant = 1;
       timeouts.ReadTotalTimeoutMultiplier = 1;

       SetCommTimeouts(m_hcoml,&timeouts);

       PurgeComm(m_hcoml,PURGE_TXCLEAR | PURGE_RXCLEAR);
       SetCommMask(m_hcoml,EV_RXCHAR|EV_CTS|EV_DSR);
       SetCommState(m_hcoml,&dcb);

       OVERLAPPED wroverlapped;
       ZeroMemory(&wroverlapped,sizeof(wroverlapped));
       wroverlapped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

       OVERLAPPED rroverlapped;
       ZeroMemory(&rroverlapped,sizeof(rroverlapped));
       rroverlapped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

       thread_para spcomsend;
       thread_para spcomrecv;

       spcomsend.m_hcoml = &m_hcoml;
       spcomsend.roverlapped = &wroverlapped;

       spcomrecv.m_hcoml = &m_hcoml;
       spcomrecv.roverlapped = &rroverlapped;

       LPSECURITY_ATTRIBUTES lpThreadAttributescom1 = 0;
       SIZE_T dwStackSizecom1 = 0;
       LPTHREAD_START_ROUTINE lpStartAddresscom1 = sercomsendthread;
       LPVOID lpParametercom1 = (LPVOID)&spcomsend;
       DWORD dwCreationFlagscom1 = 0;
       LPDWORD lpThreadIdcom1 = 0;
       HANDLE threadsend;

       LPSECURITY_ATTRIBUTES lpThreadAttributescom2 = 0;
       SIZE_T dwStackSizecom2 = 0;
       LPTHREAD_START_ROUTINE lpStartAddresscom2 = sercomrecvthread;
       LPVOID lpParametercom2 = (LPVOID)&spcomrecv;
       DWORD dwCreationFlagscom2 = 0;
       LPDWORD lpThreadIdcom2 = 0;
       HANDLE threadrecv;

       const char *p = (const char *)lpFileName;
       if(p[0] == 'C' && p[2] == 'O' && p[4] == 'M' && p[6] == '1'){
     
            spcomsend.comflag = 1;
            spcomrecv.comflag = 1;
       }//若此线程是COM1口,令comflag = 1;

       if(p[0] == 'C' && p[2] == 'O' && p[4] == 'M' && p[6] == '2'){
     
            spcomsend.comflag = 2;
            spcomrecv.comflag = 2;
       }//若此线程是COM2口,令comflag = 2;

       threadsend = CreateThread(lpThreadAttributescom1,dwStackSizecom1,lpStartAddresscom1,lpParametercom1,dwCreationFlagscom1,lpThreadIdcom1);
       //创建COM X口发送线程
       threadrecv = CreateThread(lpThreadAttributescom2,dwStackSizecom2,lpStartAddresscom2,lpParametercom2,dwCreationFlagscom2,lpThreadIdcom2);
       //创建COM X口接收线程
       while(1){
     
        ::Sleep(100);
           //if发生中断,break--此处没写,跟根据实际情况跳出
       }
        ExitThread(0);
}


测试结果:
C++ WINDOWS下串口编程(QT为工程模板)_第1张图片

写的不太好请指出,谢谢每一位前辈的付出。

你可能感兴趣的:(c++)