封装WIN32 串口API (基于消息机制)

接上一篇文章,放出我对Win32 串口API 的封装代码

(BBA是我个人限定名) 完整工程已上传到我的资源

#include <Windows.h>

#include <thread>  

using namespace std;
#define BBA_SERIAL_EVENT 10002
class BBA_Serial
{

public:
BBA_Serial();
~BBA_Serial();
int OpenSerial(const WCHAR *SerialPort, int BaudRate, int ByteSize,
int Parity, int StopBits);
int CloseSerial();


int Read(char *RX_Buffer, int len);
int Write(char *TX_Buffer, int len);
int OpenListenThread(HWND hWnd);
int GetListenThreadState();
bool SetEventDone();
bool EventClear();
protected:

private:
HANDLE hCom; //串口句柄
thread m_threadEvent; //监听事件线程对象
bool ListThreadState; //监听事件线程关闭
//HANDLE threadHandle; //监听线程句柄
HWND hWnd; //事件通知的窗口句柄
DWORD dwMask; //记录事件类型
OVERLAPPED lpOverlapped; //事件类型
OVERLAPPED EventOverlapped; //异步通信事件记录
void EventListenThread(void* lpParam); //事件监听线程

};





#include "stdafx.h"

#include "BBA_Serial.h"
BBA_Serial::BBA_Serial()
{

}

BBA_Serial::~BBA_Serial()
{

}

int BBA_Serial::OpenSerial(const WCHAR *SerialPort, int BaudRate, int ByteSize,
int Parity, int StopBits)
{
hCom = CreateFile(SerialPort, //COM口
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //重叠方式
NULL);


if (hCom == INVALID_HANDLE_VALUE)
{
//std::cout << "打开COM失败!\n";
return FALSE;
}
SetupComm(hCom, 1024, 1024);//输入缓冲区和输出缓冲区的大小都是1024


COMMTIMEOUTS TimeOuts;//设定读超时
TimeOuts.ReadIntervalTimeout = 1000; //读间隔超时
TimeOuts.ReadTotalTimeoutMultiplier = 500; //读时间系数
TimeOuts.ReadTotalTimeoutConstant = 5000; //读时间常量
TimeOuts.WriteTotalTimeoutMultiplier = 500; //写时间系数
TimeOuts.WriteTotalTimeoutConstant = 2000; //写时间常量
SetCommTimeouts(hCom, &TimeOuts);//设置超时
//总超时的计算公式是:总超时=时间系数×要求读 / 写的字符数+时间常量
//例如,要读入10个字符,那么读操作的总超时的计算公式为:
//读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant


DCB dcb;
GetCommState(hCom, &dcb);
dcb.BaudRate = BaudRate;//波特率为9600
dcb.ByteSize = ByteSize;//每个字节有8位
dcb.Parity = Parity;//无奇偶校验位
dcb.StopBits = StopBits;//一个停止位//TWOSTOPBITS;//两个停止位
SetCommState(hCom, &dcb);


//在读写串口之前,还要用PurgeComm()函数清空缓冲区,该函数原型:
PurgeComm(hCom, //串口句柄
PURGE_TXCLEAR |
PURGE_RXCLEAR);// 需要完成的操作 );
//参数dwFlags指定要完成的操作,可以是下列值的组合:
//PURGE_TXABORT 中断所有写操作并立即返回,即使写操作还没有完成。
//PURGE_RXABORT 中断所有读操作并立即返回,即使读操作还没有完成。
//PURGE_TXCLEAR 清除输出缓冲区
//PURGE_RXCLEAR 清除输入缓冲区
return 0;
}


int BBA_Serial::CloseSerial()
{
ListThreadState = 0;
//SetEvent(hCom);
CloseHandle(hCom);
m_threadEvent.~thread();
return 0;
}


int BBA_Serial::Read(char *RX_Buffer, int len)
{
DWORD dwBytesRead;


COMSTAT ComStat; // 指向通讯状态缓冲区


DWORD dwErrorFlags; // 接收错误码变量


OVERLAPPED m_osRead; //当前操作的状态,例如串口是否正在传输


memset(&m_osRead, 0, sizeof(OVERLAPPED));


m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


//PurgeComm(hCom,PURGE_TXCLEAR |PURGE_RXCLEAR); //清空缓冲区
//读写前先清除串口的错误
ClearCommError(hCom, &dwErrorFlags, &ComStat);


//if ((DWORD)ComStat.cbInQue == 0) return FALSE;
len = min(len, (DWORD)ComStat.cbInQue);

if (!len) return FALSE;
//cout << dwBytesRead;
BOOL bReadStatus;


bReadStatus = ReadFile(hCom,
RX_Buffer,
len, //要读入的个数
&dwBytesRead //实际读入的个数
, &m_osRead);


//如果ReadFile函数返回FALSE,即读失败
if (!bReadStatus)
{
//GetLastError()函数返回ERROR_IO_PENDING,表明串口正在进行读操作
if (GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_osRead.hEvent, 2000);
//使用WaitForSingleObject函数等待,直到读操作完成或延时已达到2秒钟
//当串口读操作进行完毕后,m_osRead的hEvent事件会变为有信号
//PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
return len;
}
}
return len;
}
int BBA_Serial::Write(char *TX_Buffer, int len)
{
DWORD dwBytesWritten; //实际写入的数据个数
DWORD dwErrorFlags; //错误标志
COMSTAT ComStat; //串口状态


OVERLAPPED m_osWrite; //记录串口事件
memset(&m_osWrite, 0x00, sizeof(OVERLAPPED));
m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

BOOL bWriteStat; //写入结果


//PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR); //清空缓冲区
//读写前先清除串口的错误
ClearCommError(hCom, &dwErrorFlags, &ComStat);


if ((DWORD)ComStat.cbOutQue + len>1023) return -1; //输入缓冲区字节数

bWriteStat = WriteFile(hCom,
TX_Buffer,
len, //要写入的个数
&dwBytesWritten, //实际写入的个数
&m_osWrite);

if (!bWriteStat)
{

if (GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(m_osWrite.hEvent, 1000);
return 0;
}
return -1;
}
return 0;
}


int BBA_Serial::OpenListenThread(HWND hWnd)
{
//PostMessage(hWnd, 1, WPARAM wParam, LPARAM lParam);
this->hWnd = hWnd;
ListThreadState = 1;
m_threadEvent=thread(&BBA_Serial::EventListenThread, this, (void*)&hWnd);
//listenThreadID = listenThread.get_id();

m_threadEvent.detach();
return 0;
}


void BBA_Serial::EventListenThread(void* lpParam)
{
//DWORD error;
//COMSTAT comStat;
//DWORD rec;
memset(&lpOverlapped, 0, sizeof(OVERLAPPED));
lpOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);


//memset(&EventOverlapped, 0, sizeof(OVERLAPPED));
//EventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


SetCommMask(hCom, EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY); //设置监控串口事件

while (ListThreadState)
{

//ResetEvent(lpOverlapped.hEvent);

WaitCommEvent(hCom, &dwMask, &lpOverlapped);
//rec=ClearCommError(hCom, &error, &comStat);
//if (!rec) continue;
WaitForSingleObject(lpOverlapped.hEvent, INFINITE);
PostMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
//WaitForSingleObject(EventOverlapped.hEvent, INFINITE); //等待接收事件完成处理
//EventClear();

//ClearCommError(hCom, &error, &comStat);

                //以下为单独处理一种类型消息(主要用于测试),由上面的消息路由已经足够实现消息控制串口读写和各种事件

//switch (dwMask)
//{
// case EV_DSR:
// SendMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// break;
// case EV_ERR:
// SendMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// break;
// case EV_RING:
// SendMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// break;
// case EV_RLSD:
// SendMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// break;
// case EV_RXCHAR:
// if (comStat.cbInQue == 0) break;
// PostMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// WaitForSingleObject(EventOverlapped.hEvent, INFINITE); //等待接收事件完成处理
// EventClear();
// break;
// case EV_RXFLAG:
// SendMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// break;
// case EV_TXEMPTY:
// SendMessage(hWnd, BBA_SERIAL_EVENT, NULL, (LPARAM)dwMask);
// break;
//}
}
}


bool BBA_Serial::SetEventDone()
{
SetEvent(EventOverlapped.hEvent);
return 0;
}


bool BBA_Serial::EventClear()
{
ResetEvent(EventOverlapped.hEvent);
return 0;
}
int BBA_Serial::GetListenThreadState()
{
return ListThreadState;

}


直接引入MFC或各种win32 窗口工程都能兼容


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用C++代码封装win32操作类, 与MFC相似,对于学习SDK与C++是巨好的参考 Tutorials Menu of tutorials Tutorial 1: The Simplest Window Tutorial 2: Using Classes and Inheritance Tutorial 3: Using Messages to Create a Scribble Window Tutorial 4: Repainting the Window Tutorial 5: Wrapping a Frame around our Scribble Window Tutorial 6: Customising Window Creation Tutorial 7: Customising the Toolbar Tutorial 8: Loading and Saving Files Tutorial 9: Printing Tutorial 10: Finishing Touches Tutorial 1: The Simplest Window The following code uses Win32++ to create a window. This is all the code you need (in combination with Win32++) to create and display a simple window. Note that in order to add the Win32++ code to our program, we use an #include statement as shown below. #include "../Win32++/Wincore.h" INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPTSTR, int) { //Start Win32++ CWinApp MyApp; //Create a CWnd object CWnd MyWindow; //Create (and display) the window MyWindow.Create(); //Run the application return MyApp.Run(); } This program has four key steps: Start Win32++. We do this here by creating a CWinApp object called MyApp. Create a CWnd object called MyWindow. Create a default window by calling the Create function. Start the message loop, by calling the Run function. If you compile and run this program, you'll find that the application doesn't end when the window is closed. This is behaviour is normal. An illustration of how to use messages to control the windows behaviour (including closing the application) will be left until tutorial 3.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值