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 <QCoreApplication> #include <Windows.h> #include <stdio.h> #include <iostream> #include <io.h> #include <process.h> #include <malloc.h> 

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("rn");              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 <QCoreApplication> #include <Windows.h> #include <stdio.h> #include <iostream> #include <io.h> #include <process.h> #include <malloc.h> 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(" rn com is %d send strlen is %drn",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(" rn 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("rn");              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!rn");        }        else{            printf("open serial success!rn");         }         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为工程模板)

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

版权声明:玥玥 发表于 2021-04-28 8:08:41。
转载请注明:C++ WINDOWS下串口编程(QT为工程模板) | 女黑客导航