个人文章地址
1. 头文件
#pragma once
#include <string>
#include <memory>
#include <tuple>
#include <functional>
#include <thread>
template<typename T>
class Thread {
private:
// 线程指针
std::shared_ptr<std::thread> m_threadPtr = nullptr;
// 子线程状态
bool status = false;
private:
void Start(){
status = true;
}
void End(){
if (m_threadPtr != nullptr && m_threadPtr->joinable())
{
m_threadPtr->join();
}
m_threadPtr = nullptr;
status = false;
}
public:
bool Run(std::function<T> fn){
if (status)
{
return false;
}
m_threadPtr = std::make_shared<std::thread>(fn);
Start();
return true;
}
~Thread(){
if (m_threadPtr != nullptr)
{
End();
m_threadPtr = nullptr;
}
}
};
class Serial
{
private:
HANDLE m_portHandle = (HANDLE)-1;
// 配置串口信息
struct _DCB m_dcb;
// in:输入缓冲区大小
unsigned long in;
// out:输出缓冲区大小
unsigned long out;
// 超时配置
COMMTIMEOUTS TimeOuts;
std::shared_ptr<Thread<void()>> threadPtr = nullptr;
public:
private:
// 描述: 打开串口
// lpFileName: 串口名
// ways: 打开方式;0同步方式, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED 重叠方式
void OpenPort(LPCTSTR lpFileName, int ways);
public:
// 描述: 同步打开串口
// lpFileName: 串口名
void SyncOpenPort(LPCTSTR lpFileName);
// 描述: 配置串口信息
// rata: 波特率
// fParity: 奇偶校验;若此成员为1,允许奇偶校验检查
// byteSize:通信字节位数,4—8
// parity:指定奇偶校验方法;EVENPARITY 偶校验; NOPARITY 无校验; MARKPARITY 标记校验; ODDPARITY 奇校验;
// stopBits: 停止位的位数;ONESTOPBIT 1位停止位; TWOSTOPBITS 2位停止位; ON5STOPBITS 1.5位停止位;
void SetConfig(int rate, unsigned long fParity, unsigned char byteSize, unsigned char parity, unsigned char stopBits);
// 描述:设置输入输出缓冲区大小
// in:输入缓冲区大小
// out:输出缓冲区大小
void SetBuffSize(unsigned long in = 1024, unsigned long out = 1024);
// 设置超时配置
// rTimeOut:读间隔超时
// rMTimeOut:读时间系数
// rConstant:读时间常量
// wMTimeOut:写时间系数
// wConstant:写时间常量
void SetTimeOut(
unsigned long rTimeOut = 500,
unsigned long rMTimeOut = 500,
unsigned long rConstant = 5000,
unsigned long wMTimeOut = 500,
unsigned long wConstant = 100
);
// 同步读取串口信息
// 返回值: index 1:读取结果
// index 2: 读取的字节数
std::tuple<std::string, unsigned long> SyncRead();
// 同步写串口
// outStr:写入的字符串
void SyncWrite(std::string outStr);
// 关闭串口
void ClosePort();
// 关闭串口
~Serial();
// 描述:伪异步读串口
// fn: 读取到后执行的功能体
void FakeAsynRead(std::function<void(std::string)> fn);
};
2. 具体实现
#include "stdafx.h"
#include "Serial.h"
// 描述: 打开串口
// lpFileName: 串口名
// ways: 打开方式;0同步方式, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED 重叠方式
void Serial::OpenPort(LPCTSTR lpFileName, int ways){
if (m_portHandle != (HANDLE)-1)
{
CloseHandle(m_portHandle);
this->m_portHandle = (HANDLE)-1;
}
HANDLE hCom; //全局变量,串口句柄
hCom = CreateFile(lpFileName,//COM1口
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
ways, //同步方式
NULL);
if (hCom == (HANDLE)-1)
{
AfxMessageBox(_T("打开COM失败!"));
return;
}
this->m_portHandle = hCom;
}
// 描述: 同步打开串口
// lpFileName: 串口名
void Serial::SyncOpenPort(LPCTSTR lpFileName){
OpenPort(lpFileName, 0);
}
// 描述: 配置串口信息
// rata: 波特率
// fParity: 奇偶校验;若此成员为1,允许奇偶校验检查
// byteSize:通信字节位数,4—8
// parity:指定奇偶校验方法;EVENPARITY 偶校验; NOPARITY 无校验; MARKPARITY 标记校验; ODDPARITY 奇校验;
// stopBits: 停止位的位数;ONESTOPBIT 1位停止位; TWOSTOPBITS 2位停止位; ON5STOPBITS 1.5位停止位;
void Serial::SetConfig(int rate, unsigned long fParity, unsigned char byteSize, unsigned char parity, unsigned char stopBits){
this->m_dcb.BaudRate = rate;
this->m_dcb.fParity = fParity;
this->m_dcb.ByteSize = byteSize;
this->m_dcb.Parity = parity;
this->m_dcb.StopBits = stopBits;
SetCommState(this->m_portHandle, &this->m_dcb);
}
// 描述:设置输入输出缓冲区大小
// in:输入缓冲区大小
// out:输出缓冲区大小
void Serial::SetBuffSize(unsigned long in, unsigned long out){
SetupComm(this->m_portHandle, // 通信设备的句柄
this->in = in, // 输入缓冲区的大小(字节数)
this->out = out // 输出缓冲区的大小(字节数)
);
}
// 设置超时配置
// rTimeOut:读间隔超时
// rMTimeOut:读时间系数
// rConstant:读时间常量
// wMTimeOut:写时间系数
// wConstant:写时间常量
void Serial::SetTimeOut(
unsigned long rTimeOut,
unsigned long rMTimeOut,
unsigned long rConstant,
unsigned long wMTimeOut,
unsigned long wConstant
){
TimeOuts.ReadIntervalTimeout = rTimeOut; //读间隔超时
TimeOuts.ReadTotalTimeoutMultiplier = rMTimeOut; //读时间系数
TimeOuts.ReadTotalTimeoutConstant = rConstant;//读时间常量
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier = wMTimeOut;// 写时间系数
TimeOuts.WriteTotalTimeoutConstant = wConstant; //写时间常量
//设置超时
SetCommTimeouts(this->m_portHandle, &TimeOuts);
}
// 同步读取串口信息
// 返回值: index 1:读取结果
// index 2: 读取的字节数
std::tuple<std::string, unsigned long> Serial::SyncRead(){
char *str = new char[this->in + 1]{'\0'};
unsigned long wCount;//读取的字节数
BOOL bReadStat;
bReadStat = ReadFile(this->m_portHandle, str, this->in, &wCount, NULL);
if (!bReadStat) {
AfxMessageBox(_T("读串口失败!"));
}
str[wCount] = '\0';
auto rs = std::string(str);
delete[]str;
return std::tuple<std::string, unsigned long>(rs, wCount);
}
// 同步写串口
// outStr:写入的字符串
void Serial::SyncWrite(std::string outStr){
// 写缓冲区大小
unsigned long dwBytesWrite = outStr.size();
COMSTAT ComStat;
// 错误标志
unsigned long dwErrorFlags;
//写状态
BOOL bWriteStat;
// 清楚错误信息
ClearCommError(this->m_portHandle, &dwErrorFlags, &ComStat);
// 开始写
bWriteStat = WriteFile(this->m_portHandle, outStr.c_str(), dwBytesWrite, &dwBytesWrite, NULL);
if (!bWriteStat) {
AfxMessageBox(_T("写串口失败!"));
}
// 清空串口的输入输出缓冲区
PurgeComm(this->m_portHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
}
// 关闭串口
void Serial::ClosePort(){
if (this->m_portHandle != (HANDLE)-1)
{
CloseHandle(this->m_portHandle);
this->m_portHandle = (HANDLE)-1;
}
}
// 关闭串口
Serial::~Serial(){
if (this->m_portHandle != (HANDLE)-1)
{
CloseHandle(this->m_portHandle);
this->m_portHandle = (HANDLE)-1;
}
}
// 描述:伪异步读串口
// fn: 读取到后执行的功能体
void Serial::FakeAsynRead(std::function<void(std::string)> fn){
Serial* isMy = this;
std::function<void()> asynFun = [=](){
std::string rs = std::get<0>(isMy->SyncRead());
fn(rs);
};
threadPtr = std::make_shared<Thread<void()>>();
threadPtr->Run(asynFun);
}