本文將依托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("\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 <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(" \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);
}
測驗結果:

寫的不太好請指出,謝謝每一位前輩的付出,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/281206.html
標籤:其他
