Windows 串口代码
#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 串口代码的更多相关文章
- storysnail的Windows串口编程笔记
storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...
- Windows GUI代码与Windows消息问题调试利器
Windows GUI代码与Windows消息问题调试利器 记得很久前有这么一种说法: 人类区别于动物的标准就是工具的使用.同样在软件开发这个行业里面,对于工具的使用也是高手和入门级选手的主要区别,高 ...
- 如何实现Windows Phone代码与Unity相互通信(事件方式)
源地址:http://www.cnblogs.com/petto/p/3909063.html 一些废话 昨天写一篇今天写一篇.不是我闲的蛋疼,是今天一天碰到了好几个恼人的问题,浪费一天时间搞定.本文 ...
- 利用Python编写Windows恶意代码!自娱自乐!勿用于非法用途!
本文主要展示的是通过使用python和PyInstaller来构建恶意软件的一些poc. 利用Python编写Windows恶意代码!自娱自乐!勿用于非法用途!众所周知的,恶意软件如果影响到了他人的生 ...
- Windows数字代码签名的作用和流程
什么是数字代码签名?数字签名代码是一种技术,它使用数字证书来识别软件的发布商和使用hash算法来确保软件的完整性.数字签名使用公共密匙签名书法被创建,它使用两种不同的密匙:公共密匙和私有密匙,我们称其 ...
- 没有真实串口设备时使用"虚拟串口驱动"调试你的串口代码
目录 前言 示例代码 总结 前言 很多时候需要编写串口代码,但是又没有真实串口设备来调试代码.以及本身就是要操作2个串口的情况,可以使用"虚拟串口驱动"工具方便的调试代码. 使用方 ...
- 转 Windows串口过滤驱动程序的开发
在Windows系统上与安全软件相关的驱动开发过程中,“过滤(filter)”是极其重要的一个概念.过滤是在不影响上层和下层接口的情况下,在Windows系统内核中加入新的层,从而不需要修改上层的软件 ...
- windows串口编程Win32,PComm串口开发
https://blog.csdn.net/u011430225/article/details/51496456 https://blog.csdn.net/eit520/article/detai ...
- 低功耗蓝牙4.0BLE编程-nrf51822开发(11)-蓝牙串口代码分析
代码实例:点击打开链接 实现的功能是从uart口发送数据至另一个蓝牙串口,或是从蓝牙读取数据通过uart打印出数据. int main(void) { // Initialize leds_init( ...
- 如何实现Windows Phone代码与Unity相互通信(插件方式)
原地址:http://www.cnblogs.com/petto/p/3915943.html 一些废话 原文地址: http://imwper.com/unity/petto/%E5%A6%82%E ...
随机推荐
- MySQL JDBC驱动版本与数据库版本的对应关系及注意事项
MySQL JDBC驱动版本与数据库版本的对应关系及注意事项 事情发生 学了三遍的servlet,经典老师又教的第一万遍登陆注册,并且让实现,并且让演示,我们老师可能和之前的小学期公司老师 完全没有沟 ...
- easyui combobox的级联设置
<body> <input id="title" class="easyUI-combobox" //onSelect:在该combobox被 ...
- day10 Test
public class Test{ public static void main(String[] args){ fun1(); } /**1. * 有2个数组,第一个数组内容为:[黑龙江省,浙江 ...
- 【十次方微服务后台开发】Day02:加密与JWT鉴权、微服务注册中心、配置中心、熔断器、网关、消息总线、部署与持续集成、容器管理与监控Rancher、influxDB、grafana
一.密码加密与微服务鉴权JWT 1.BCrypt密码加密 Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用B ...
- NCTF2022 - pwn 部分 wp
总的来说我出的几题不是很难,主要是想把自己感觉有意思的一些东西分享给大家. ezlogin 程序设计周大作业稍加改编出的题目.洞在Tea里,有个数组越界写,为了避开\x00截断,我给了*可以对其进行替 ...
- lv逻辑卷
一.逻辑卷的使用 1.逻辑卷的概念 LVM(逻辑卷管理) 适合于管理大存储设备,并允许用户动态调整文件系统的大小.此外,LVM 的快照功能可以帮助我们快速备份数据.LVM 为我们提供了逻辑概念上的磁盘 ...
- ADB命令快速入门
什么是ADB adb的全称为Android Debug Bridge,就是起到调试桥的作用.通过adb我们可以方便调试Android程序. 环境搭建 1需要java环境: 安装完JDK需要配置环境变量 ...
- 浅谈字节码增强技术系列2-Asm与Cglib
作者:董子龙 前言 记得那是2022年秋天的第一场雨,比2021年来的稍晚一些,在那个秋雨朦胧的下午,正在工位上奋笔疾书的我突然听到了前面波哥对着手机听筒说出来的"温柔"的话语:说 ...
- 搭建漏洞环境及实战——搭建DVWA漏洞环境
DVWA是一款开源的渗透测试漏洞练习平台,其中内涵XSS.SQL注入.文件上传.文件包含.CSRF和暴力破解等各个难度的测试环境. 1.在安装时需要在数据库里创建一个数据库名,进入MySQL管理中的p ...
- npm Error: Cannot find module 'are-we-there-yet'
npm 损坏了,are-we-there-yet是npm所依赖的npmlog依赖的一个包,重新安装npm即可 踩坑,直接安装还是报错,不管执行哪个命令都是报下面这个错 网上百度了很多,有的说把node ...