#pragma once #include <Windows.h> #define DEFAULT_THREAD_TERMINATED_TIME 2000 class CAutoThread {
public:
// 构造(初始化)
CAutoThread(DWORD dwThreadTerminatedTime = DEFAULT_THREAD_TERMINATED_TIME) {
m_bTerminated = TRUE;
m_dwExitCode = (DWORD)-1;
m_hThreadHandle = NULL;
m_dwThreadTerminatedTime = dwThreadTerminatedTime;
}; // 析构(有需要时自动结束线程)
virtual ~CAutoThread() { ThreadStop(); } // 启动线程
BOOL ThreadStart() {
ThreadTerminated(m_dwThreadTerminatedTime); if (NULL == m_hThreadHandle) {
m_bTerminated = FALSE;
m_hThreadHandle = ::CreateThread(NULL, 0, CAutoThread::ThreadProc, (LPVOID)this, 0, &m_dwThreadId);
} return (m_hThreadHandle != NULL);
} // 结束线程
BOOL ThreadStop() {
ThreadTerminated(m_dwThreadTerminatedTime);
return (m_hThreadHandle == NULL);
} // 设置线程优先级
BOOL CeSetPriority(int nPriority) {
if (m_hThreadHandle) {
#ifdef _WIN32_WCE
return CeSetThreadPriority(m_hThreadHandle, nPriority);
#endif
}
return FALSE;
} // 结束线程
BOOL ThreadTerminated(DWORD dwMilliSeconds = DEFAULT_THREAD_TERMINATED_TIME) {
m_bTerminated = TRUE;
return WaitThreadComplete(dwMilliSeconds);
} // 等待线程结束
BOOL WaitThreadComplete(DWORD dwMilliSeconds) {
if (m_hThreadHandle) {
if (::WaitForSingleObject(m_hThreadHandle, dwMilliSeconds) == WAIT_OBJECT_0) {
// thread dead
::CloseHandle(m_hThreadHandle);
m_hThreadHandle = NULL;
return TRUE;
} else {
ForceTerminated();
}
}
return FALSE;
} // 强制结束线程
BOOL ForceTerminated() {
BOOL bReturn = FALSE;
if (m_hThreadHandle) {
bReturn = ::TerminateThread(m_hThreadHandle, (DWORD)-1); // terminate abnormal
m_dwExitCode = -1;
::CloseHandle(m_hThreadHandle);
m_hThreadHandle = NULL;
m_bTerminated = TRUE;
}
return bReturn;
} // 获取线程ID
DWORD GetThreadId() const { return m_dwThreadId; } // 线程是否结束
BOOL IsTerminated() const { return m_bTerminated; } // 获取线程句柄
HANDLE GetThreadHandle() const { return m_hThreadHandle; } // 获取线程退出码
BOOL GetExitCodeThread(LPDWORD lpExitCode) {
if (!m_hThreadHandle) {
*lpExitCode = m_dwExitCode;
return TRUE;
} else {
return FALSE;
}
}; // 投递线程消息
BOOL PostThreadMessage(DWORD u4Msg, WPARAM wParam, LPARAM lParam) {
return ::PostThreadMessage(m_dwThreadId, u4Msg, wParam, lParam);
} private:
virtual DWORD ThreadRun() = 0; // User have to implement this function. static DWORD WINAPI ThreadProc(LPVOID dParam) {
CAutoThread* pThreadPtr = (CAutoThread*)dParam;
pThreadPtr->m_dwExitCode = pThreadPtr->ThreadRun();
::ExitThread(pThreadPtr->m_dwExitCode);
return pThreadPtr->m_dwExitCode;
}; protected:
// 线程是否处于终止状态
BOOL m_bTerminated; private:
// 线程句柄
HANDLE m_hThreadHandle; // 线程ID
DWORD m_dwThreadId; // 线程退出码
DWORD m_dwExitCode; // 等待线程退出的最长事件
DWORD m_dwThreadTerminatedTime;
}; #define DEFAULT_SERIAL_BUFF_LEN 1024 #define DEFAULT_SERIAL_READ_WAIT 1 #define SAFE_DELETE(a) \
{ \
if (a) { \
delete a; \
a = NULL; \
} \
} #define SAFE_DELETE_ARRAY(a) \
{ \
if (a) { \
delete[] a; \
a = NULL; \
} \
} // 用于接收串口数据的回调对象
class CSerialObject {
public:
virtual ~CSerialObject(){}; virtual BOOL OnDataRecv(BYTE *pData, DWORD dwDataLen) = 0;
}; typedef BOOL (CSerialObject::*PSERIAL_DATA_CALLBACK_FUNC)(BYTE *pData, DWORD dwDataLen); class CSerial : public CAutoThread {
public:
CSerial(CSerialObject *pObject, PSERIAL_DATA_CALLBACK_FUNC pDataFunc,
DWORD dwBufLen = DEFAULT_SERIAL_BUFF_LEN,
DWORD dwReadWait = DEFAULT_SERIAL_READ_WAIT); virtual ~CSerial(void); BOOL InitSerial(CSerialObject *pObject, PSERIAL_DATA_CALLBACK_FUNC pDataFunc); BOOL Open(BYTE uComPort, DWORD dwBaudRate, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT); BOOL ChangeBaud(DWORD dwBaudRate, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT); BOOL Close(); BOOL WriteData(LPCVOID lpBuf, DWORD dwBufLen); BOOL IsOpen() const; BOOL ClearUart(); BOOL IsTimeOut(DWORD preTime); // 接收数据的缓存区
BYTE *m_pBuf; BOOL m_SendDataState; DWORD m_PreTime; protected:
DWORD ThreadRun(); private:
// 接收串口数据的对象的成员函数
PSERIAL_DATA_CALLBACK_FUNC m_pDataFunc; // 读取数据后,等待多长时间(毫秒)
DWORD m_dwReadWait; // 每次最多读取多少数据
DWORD m_dwBufLen; // 串口设备句柄
HANDLE m_hComDev; // 接收串口数据的对象
CSerialObject *m_pObject;
};
#include <stdio.h>

#include <thread>
using namespace std; #include "CSerial.h" #define RETAILMSG(cond,printf_exp) #define MIN_BUF_ARRAY_SIZE 2 // 构造串口
CSerial::CSerial(CSerialObject *pObject, PSERIAL_DATA_CALLBACK_FUNC pDataFunc, DWORD dwBufLen, DWORD dwReadWait)
: CAutoThread()
, m_hComDev(INVALID_HANDLE_VALUE)
, m_dwBufLen(dwBufLen)
, m_pBuf(NULL)
, m_dwReadWait(dwReadWait)
{
if (m_dwBufLen < MIN_BUF_ARRAY_SIZE) {
m_dwBufLen = MIN_BUF_ARRAY_SIZE;
} m_pBuf = new BYTE[m_dwBufLen]; if (m_pBuf) {
memset(m_pBuf, 0, m_dwBufLen);
} m_SendDataState = FALSE; InitSerial(pObject, pDataFunc);
} // 析构串口
CSerial::~CSerial(void) {
Close();
SAFE_DELETE_ARRAY(m_pBuf);
} // 初始化回调函数
BOOL CSerial::InitSerial(CSerialObject *pObject, PSERIAL_DATA_CALLBACK_FUNC pDataFunc) {
m_pDataFunc = pDataFunc;
m_pObject = pObject; return TRUE;
} // 打开串口
BOOL CSerial::Open(BYTE uComPort, DWORD dwBaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits) {
BOOL bRet = FALSE; // 先关闭已经打开的串口
if (INVALID_HANDLE_VALUE != m_hComDev) {
Close();
} // 打开串口
char wzPort[MAX_PATH] = {0};
sprintf(wzPort, "\\\\.\\COM%d", uComPort);
m_hComDev = CreateFile(wzPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // 成功打开
if (m_hComDev != INVALID_HANDLE_VALUE) {
// 设置
bRet = SetCommMask(m_hComDev, EV_RXCHAR | EV_TXEMPTY | EV_ERR);
RETAILMSG(!bRet, ("SetCommMask:%d ERROR:%d\r\n", bRet, GetLastError())); // 设置
bRet = PurgeComm(m_hComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
RETAILMSG(!bRet, ("SetupComm:%d ERROR:%d\r\n", bRet, GetLastError())); // 设置
COMMTIMEOUTS CommTimeOuts = {0};
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
// CommTimeOuts.ReadIntervalTimeout = 1;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
bRet = SetCommTimeouts(m_hComDev, &CommTimeOuts);
RETAILMSG(!bRet, ("SetCommTimeouts:%d ERROR:%d\r\n", bRet, GetLastError())); // 设置
DCB dcb = {0};
dcb.DCBlength = sizeof(DCB);
bRet = GetCommState(m_hComDev, &dcb);
RETAILMSG(!bRet, ("GetCommState:%d ERROR:%d\r\n", bRet, GetLastError())); dcb.fBinary = TRUE;
dcb.fParity = FALSE;
dcb.BaudRate = dwBaudRate;
dcb.ByteSize = ByteSize;
dcb.Parity = Parity;
dcb.StopBits = StopBits;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fOutxCtsFlow = 0;
dcb.fOutxDsrFlow = 0;
if (SetCommState(m_hComDev, &dcb)) {
bRet = SetCommMask(m_hComDev, EV_RXCHAR | EV_TXEMPTY | EV_ERR);
RETAILMSG(bRet, ("SetCommState success dwBaudRate:%d, wzPort:%s\r\n", dwBaudRate, wzPort));
bRet = TRUE;
ThreadStart();
} else {
RETAILMSG(1, ("SetCommState %s FAILED! ERROR:%d\r\n", wzPort, GetLastError()));
Close();
} ChangeBaud(115200);
} else {
RETAILMSG(1, ("Open %s FAILED! ERROR:%d\r\n", wzPort, GetLastError()));
} return bRet;
} BOOL CSerial::ChangeBaud(DWORD dwBaudRate, BYTE ByteSize, BYTE Parity, BYTE StopBits) {
BOOL bRet;
DCB dcb = {0};
dcb.DCBlength = sizeof(DCB); // 获取串口状态
bRet = GetCommState(m_hComDev, &dcb);
RETAILMSG(!bRet, ("GetCommState:%d ERROR:%d\r\n", bRet, GetLastError())); // 设置串口状态
dcb.fBinary = TRUE;
dcb.fParity = FALSE;
dcb.BaudRate = dwBaudRate;
dcb.ByteSize = ByteSize;
dcb.Parity = Parity;
dcb.StopBits = StopBits;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fOutxCtsFlow = 0;
dcb.fOutxDsrFlow = 0;
if (SetCommState(m_hComDev, &dcb)) {
bRet = SetCommMask(m_hComDev, EV_RXCHAR | EV_TXEMPTY | EV_ERR);
} else {
bRet = FALSE;
} return bRet;
} // 关闭串口
BOOL CSerial::Close() {
BOOL bRet = FALSE;
PurgeComm(m_hComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
ThreadStop();
CloseHandle(m_hComDev);
m_hComDev = INVALID_HANDLE_VALUE;
bRet = TRUE;
return bRet;
} // 发送数据
BOOL CSerial::WriteData(LPCVOID lpBuf, DWORD dwBufLen) {
BOOL bRet = FALSE;
if (lpBuf && dwBufLen && m_hComDev) {
DWORD dwWrite = 0;
m_SendDataState = TRUE;
m_PreTime = GetTickCount();
bRet = WriteFile(m_hComDev, lpBuf, dwBufLen, &dwWrite, NULL);
if (bRet && dwWrite != dwBufLen) {
bRet = FALSE;
}
}
return bRet;
} // 串口是否被打开了
BOOL CSerial::IsOpen() const { return INVALID_HANDLE_VALUE != m_hComDev; } // 清理串口
BOOL CSerial::ClearUart() {
PurgeComm(m_hComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
return 0;
} // 是否超时
BOOL CSerial::IsTimeOut(DWORD preTime) {
return (abs((int)(GetTickCount() - preTime)) >= 3000);
} DWORD CSerial::ThreadRun() {
while (!IsTerminated() && m_pBuf && m_pObject && m_hComDev != INVALID_HANDLE_VALUE && m_pDataFunc) {
DWORD dwRead = 0;
if (ReadFile(m_hComDev, m_pBuf, m_dwBufLen, &dwRead, NULL) && (dwRead > 0)) {
(m_pObject->*m_pDataFunc)(m_pBuf, dwRead);
} else {
this_thread::sleep_for(chrono::milliseconds(1));
}
} return 0;
}

测试可用的串口

#include <iostream>
using namespace std; #include "CSerial.h" #define DEFAULT_BAUDRATE 115200 int main() {
CSerial serial(NULL, NULL);
for (int i = 1; i < 20; i++) {
if (serial.Open(i, DEFAULT_BAUDRATE)) {
cout << "COM" << i << endl;
serial.Close();
}
}
}

最新文章

  1. R自动数据收集第一章概述——《List of World Heritage in Danger》
  2. -/bin/sh: ./led: not found的解决办法
  3. Appnium移动自动化框架初探
  4. Node.js之【express 安装问题】
  5. JPush 极光推送 消息推送 实例
  6. Java-20个非常有用的程序片段
  7. docker学习笔记17:Dockerfile 指令 ONBUILD介绍
  8. 【shell实例】定时21:00-21:05,循环调用DSQL脚本,其它时段自动退出
  9. android Button 属性
  10. xgboost使用调参
  11. Idea的快捷键,瞎摸索,开心就好,哈哈哈
  12. CCPC-Wannafly Winter Camp Day3 Div1 - 排列
  13. [Java初探08]__简单学习Java类和对象
  14. POJ1061 青蛙的约会(扩展欧几里得)题解
  15. easyUI的分页,只显示第X 共Y页。改为显示 第X 页 共Y页
  16. linux安全配置学习
  17. 如何在Windows环境搭建Object C开发环境
  18. Linux笔记-Linux命令初解2
  19. UTC时间转为正常日期
  20. try与catch

热门文章

  1. i春秋Zone
  2. Go1.20 新版覆盖率方案解读
  3. day22 存储过程 &amp; 游标 &amp; 事务
  4. JDK卸载
  5. 基于MATLAB的人民币识别系统
  6. 嵌入式Linux Qt移植详细过程
  7. GOCVHelper图像处理算法库实例整编
  8. Vue+ElementUI+Springboot实现前后端分离的一个demo
  9. OI是什么?
  10. 从最简单的线性DP开始