个人文章地址
#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); };
#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); }