#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();
}
}
}

Windows 串口代码的更多相关文章

  1. storysnail的Windows串口编程笔记

    storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...

  2. Windows GUI代码与Windows消息问题调试利器

    Windows GUI代码与Windows消息问题调试利器 记得很久前有这么一种说法: 人类区别于动物的标准就是工具的使用.同样在软件开发这个行业里面,对于工具的使用也是高手和入门级选手的主要区别,高 ...

  3. 如何实现Windows Phone代码与Unity相互通信(事件方式)

    源地址:http://www.cnblogs.com/petto/p/3909063.html 一些废话 昨天写一篇今天写一篇.不是我闲的蛋疼,是今天一天碰到了好几个恼人的问题,浪费一天时间搞定.本文 ...

  4. 利用Python编写Windows恶意代码!自娱自乐!勿用于非法用途!

    本文主要展示的是通过使用python和PyInstaller来构建恶意软件的一些poc. 利用Python编写Windows恶意代码!自娱自乐!勿用于非法用途!众所周知的,恶意软件如果影响到了他人的生 ...

  5. Windows数字代码签名的作用和流程

    什么是数字代码签名?数字签名代码是一种技术,它使用数字证书来识别软件的发布商和使用hash算法来确保软件的完整性.数字签名使用公共密匙签名书法被创建,它使用两种不同的密匙:公共密匙和私有密匙,我们称其 ...

  6. 没有真实串口设备时使用"虚拟串口驱动"调试你的串口代码

    目录 前言 示例代码 总结 前言 很多时候需要编写串口代码,但是又没有真实串口设备来调试代码.以及本身就是要操作2个串口的情况,可以使用"虚拟串口驱动"工具方便的调试代码. 使用方 ...

  7. 转 Windows串口过滤驱动程序的开发

    在Windows系统上与安全软件相关的驱动开发过程中,“过滤(filter)”是极其重要的一个概念.过滤是在不影响上层和下层接口的情况下,在Windows系统内核中加入新的层,从而不需要修改上层的软件 ...

  8. windows串口编程Win32,PComm串口开发

    https://blog.csdn.net/u011430225/article/details/51496456 https://blog.csdn.net/eit520/article/detai ...

  9. 低功耗蓝牙4.0BLE编程-nrf51822开发(11)-蓝牙串口代码分析

    代码实例:点击打开链接 实现的功能是从uart口发送数据至另一个蓝牙串口,或是从蓝牙读取数据通过uart打印出数据. int main(void) { // Initialize leds_init( ...

  10. 如何实现Windows Phone代码与Unity相互通信(插件方式)

    原地址:http://www.cnblogs.com/petto/p/3915943.html 一些废话 原文地址: http://imwper.com/unity/petto/%E5%A6%82%E ...

随机推荐

  1. 第2-3-7章 个人网盘服务接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5.8 导入其他接口代码 5.8.1 接口导入-分页查询附件 5.8.2 接口导入-根据业务类型/业务id查询附件 5.9 导入网盘服务接口 5.9.1 导入FileController 5.9 ...

  2. 使用c#的 async/await编写 长时间运行的基于代码的工作流的 持久任务框架

    持久任务框架 (DTF) 是基于async/await 工作流执行框架.工作流的解决方案很多,包括Windows Workflow Foundation,BizTalk,Logic Apps, Wor ...

  3. 如何在 K8S 集群范围使用 imagePullSecret?

    在这篇文章中,我将向你展示如何在 Kubernetes 中使用 imagePullSecrets. imagePullSecrets 简介 Kubernetes 在每个 Pod 或每个 Namespa ...

  4. Springboot 整合 SpringCache 使用 Redis 作为缓存

    一直以来对缓存都是一知半解,从没有正经的接触并使用一次,今天腾出时间研究一下缓存技术,开发环境为OpenJDK17与SpringBoot2.7.5 SpringCache基础概念 接口介绍 首先看看S ...

  5. (四) 一文搞懂 JMM - 内存模型

    4.JMM - 内存模型 1.JMM内存模型 JMM与happen-before 1.可见性问题产生原因 下图为x86架构下CPU缓存的布局,即在一个CPU 4核下,L1.L2.L3三级缓存与主内存的 ...

  6. 多进程TCP服务端并发- 进程join方法 - IPC机制

    目录 同步与异步 阻塞与非阻塞 综合使用 创建进程的多种方式 进程间数据隔离 进程join方法 IPC机制 生产者消费者模型 进程对象的多种方法 僵尸进程与孤儿进程 守护进程 多线程实现TCP服务端并 ...

  7. jupyter 数据显示设置

    #设置显示行数pd.set_option('display.max_row',None)#设置显示列数pd.set_option('display.max_column',None)#设置显示宽度pd ...

  8. 组件封装----useImperativeHandle和ref

    useImperativeHandle(ref, createHandle, [deps]) 作用: 减少暴露给父组件获取的DOM元素属性, 只暴露给父组件需要用到的DOM方法 参数1: 父组件传递的 ...

  9. Vue 响应式原理模拟以及最小版本的 Vue的模拟

    在模拟最小的vue之前,先复习一下,发布订阅模式和观察者模式 对两种模式有了了解之后,对Vue2.0和Vue3.0的数据响应式核心原理 1.Vue2.0和Vue3.0的数据响应式核心原理 (1).  ...

  10. 从工具到实践:如何在GitHub上保障开源项目安全?

    1998年,Christine Peterson创造了 "开源软件"这个词.她解释道:"这是刻意为之,为了让其他人更容易理解这个领域".同年,O'Reilly组 ...