关于Win32串口
因为近段时间接触Hid相对来说多一些,由此忽略了串口中获取cbInQue这个重要的东西,下面是错误代码
// Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
// #include "stdafx.h"
#include "Win32SerialPortLib.h"
#include <stdio.h> HANDLE hcomm;
EXTERN_C WIN32SERIALPORTLIB_API bool Open(char *com, int baud)
{
char szDCB[];
sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', , );
hcomm = CreateFileA(com,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
,
);
if (hcomm == INVALID_HANDLE_VALUE) return false;
return true;
} EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
{
DWORD readed;
BOOL rt = ReadFile(hcomm, data, len, &readed, NULL);
if (!rt)
{
PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
return ;
} return readed;
} EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
{
if (hcomm == INVALID_HANDLE_VALUE) return;
DWORD writed;
BOOL rt = WriteFile(hcomm, data, len, &writed, NULL);
if (!rt)
{
PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
return;
}
} EXTERN_C WIN32SERIALPORTLIB_API void Close()
{
if (hcomm != INVALID_HANDLE_VALUE)
{
CloseHandle(hcomm);
hcomm = INVALID_HANDLE_VALUE;
}
}
经过测试
// Win32SerialPortTest.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <thread>
#include <iostream>
#include "Win32SerialPort.h"
using namespace std; bool _stoprequired = false; void read_callback();
void printhex(unsigned char *data, int len); int _tmain(int argc, _TCHAR* argv[])
{
Open("COM5", );
thread read_t(read_callback);
read_t.detach(); cout << endl;
cout << "continue in main thread." << endl;
//ab 69 42 01 fe c0 00 00 c0
unsigned char data[] = { 0xab, 0x69, 0x42, 0x01, 0xfe, 0xc0, 0x00, 0x00, 0xc0 };
Write(data, sizeof(data) / sizeof(unsigned char)); // 获取标准输入输出设备句柄
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); DWORD dwRes, dwState = ;
INPUT_RECORD keyRec;
COORD crHome = { , }, crPos;
char ch;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
while (true)
{
ReadConsoleInput(hIn, &keyRec, , &dwRes);
if (keyRec.EventType == KEY_EVENT)
{
// Press key down
if (keyRec.Event.KeyEvent.bKeyDown)
{
// 基础功能键
switch (keyRec.Event.KeyEvent.wVirtualKeyCode)
{
// 回车
case VK_RETURN:
printf("\n");
break; // 空格
case VK_SPACE:
Write(data, sizeof(data) / sizeof(unsigned char));
break; case VK_BACK: // 按删除时删掉一个字符(只能当前行操作)
GetConsoleScreenBufferInfo(hOut, &bInfo);
crPos = bInfo.dwCursorPosition;
if (crPos.X != )
{
crPos.X -= ;
}
SetConsoleCursorPosition(hOut, crPos);
printf(" ");
SetConsoleCursorPosition(hOut, crPos);
break; case VK_ESCAPE: // 按ESC键时退出
_stoprequired = true;
Close();
Sleep();
CloseHandle(hOut); // 关闭标准输出设备句柄
CloseHandle(hIn); // 关闭标准输入设备句柄
return ; default:
break;
} // 打印字符
ch = keyRec.Event.KeyEvent.uChar.AsciiChar;
// 输出可以打印的字符(详参ASCII表)
if (ch > 0x20 && ch < 0x7e)
{
putchar(ch);
}
}
}
} return ;
} void read_callback()
{
unsigned char buff[];
while (!_stoprequired)
{
int n = Read(buff, );
if (n > )
{
printhex(buff, n);
}
//cout << "detach test." << endl;
//this_thread::sleep_for(chrono::seconds(1));
}
} void printhex(unsigned char *data, int len)
{
for (int i = ; i < len; i++)
{
printf("%2x ", data[i]);
}
printf("\n");
}
表现现象是Read函数不单单是阻塞,还会让Write函数也阻塞,这种情况是是没有留意到的地方,此处作一个记录.
异步IO版本,异步代码上方的注释为同步IO版本
// Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
// #include "stdafx.h"
#include "Win32SerialPortLib.h"
#include <stdio.h> HANDLE hcomm;
OVERLAPPED ovw;
OVERLAPPED ovr;
EXTERN_C WIN32SERIALPORTLIB_API HANDLE Open(char *com, int baud)
{
char szDCB[];
sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', , );
//hcomm = CreateFileA(com,
// GENERIC_READ | GENERIC_WRITE,
// 0,
// NULL,
// OPEN_EXISTING,
// 0,
// 0);
hcomm = CreateFileA(com,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
);
if (hcomm == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
// 设置缓冲大小
BOOL rt = SetupComm(hcomm, , );
if (!rt) return INVALID_HANDLE_VALUE;
// 设置超时
COMMTIMEOUTS commtimeouts;
commtimeouts.ReadIntervalTimeout = ;
commtimeouts.ReadTotalTimeoutConstant = ;
commtimeouts.ReadTotalTimeoutMultiplier = ;
commtimeouts.WriteTotalTimeoutConstant = ;
commtimeouts.WriteTotalTimeoutMultiplier = ;
rt = SetCommTimeouts(hcomm, &commtimeouts);
if (!rt) return INVALID_HANDLE_VALUE;
// 设置DCB
DCB dcb;
#ifdef UNICODE
DWORD num = MultiByteToWideChar(CP_ACP, , szDCB, -, NULL, );
wchar_t *pwStr = new wchar_t[num];
MultiByteToWideChar(CP_ACP, , szDCB, -, pwStr, num);
#else
DWORD num = strlen(szDCB) + ;
char *pwStr = new char[num];
strcpy(pwStr, szDCB);
#endif
rt = GetCommState(hcomm, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
rt = BuildCommDCB(pwStr, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
delete[] pwStr;
rt = SetCommState(hcomm, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
// 清空串口缓冲区
rt = PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT);
if (!rt) return INVALID_HANDLE_VALUE; return hcomm;
} EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
{
DWORD read_size = ;
if (hcomm == INVALID_HANDLE_VALUE) return ;
COMSTAT comstat;
DWORD error;
ClearCommError(hcomm, &error, &comstat);
// 串口有错误
if (error > )
{
PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
return read_size;
}
if (comstat.cbInQue > )
{
//BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, NULL);
//if (!rt) return 0;
BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, &ovr);
if (!rt)
{
rt = GetLastError();
if (rt == ERROR_IO_PENDING)
{
// 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
//rt = WaitForSingleObject(hcomm, 50);
//switch (rt)
//{
//case WAIT_OBJECT_0:
// cout << "指定的对象处于有信号状态" << endl;
// if (GetOverlappedResult(hcomm, &ovr, &read_size, FALSE))
// cout << "read " << read_size << " bytes" << endl;
// break;
//case WAIT_TIMEOUT:
// cout << "等待超时" << endl;
// break;
//case WAIT_FAILED:
// cout << "出现错误,CODE [" << GetLastError() << "]" << endl;
// break;
//case WAIT_ABANDONED:
// cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
// break;
//}
}
else
{
CancelIo(hcomm);
return ;
}
}
} return read_size;
} EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
{
DWORD write_size;
if (hcomm == INVALID_HANDLE_VALUE) return;
COMSTAT comstat;
DWORD error;
BOOL rt = ClearCommError(hcomm, &error, &comstat);
if (!rt) return;
// 串口有错误
if (error > )
{
PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
return;
} WriteFile(hcomm, data, len, &write_size, NULL);
rt = WriteFile(hcomm, data, len, &write_size, &ovw);
if (!rt)
{
rt = GetLastError();
if (rt == ERROR_IO_PENDING)
{
// 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
//rt = WaitForSingleObject(hcomm, 50);
//switch (rt)
//{
//case WAIT_OBJECT_0:
// cout << "指定的对象处于有信号状态" << endl;
// if (GetOverlappedResult(hcomm, &ovr, &write_size, FALSE))
// cout << "write " << write_size << " bytes" << endl;
// break;
//case WAIT_TIMEOUT:
// cout << "等待超时" << endl;
// break;
//case WAIT_FAILED:
// cout << "出现错误,CODE [" << GetLastError() << "]" << endl;
// break;
//case WAIT_ABANDONED:
// cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
// break;
//}
}
else
{
CancelIo(hcomm);
return;
}
}
} EXTERN_C WIN32SERIALPORTLIB_API void Close()
{
if (hcomm != INVALID_HANDLE_VALUE)
{
CancelIo(hcomm);
CloseHandle(hcomm);
hcomm = INVALID_HANDLE_VALUE;
}
}
关于Win32串口的更多相关文章
- Win32串口API
在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...
- win32串口编程
翻译自:ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.WIN32COM.v10.en/dnfiles/html/msdn_serial.htm 老外写的文章, ...
- [编译] 2、minGW gcc在windows搭建编译win32程序环境
1.普通下载一个MinGW程序.安装之后可以直接将MinGW目录拷贝到总工程的tool里面: demo_mesh_common tree -L 2 . ├── app ├── bin ├── buil ...
- MSComm控件与Win32 API操作串口有何区别?
MSComm控件与Win32 API操作串口有何区别? [问题点数:50分,结帖人shell_shell] 收藏帖子 回复 我是一个小兵,在战场上拼命! 结帖率 83.33% 我以前用MSCo ...
- 深入浅出VC++串口编程之基于Win32 API
1.API描述 在WIN32 API中,串口使用文件方式进行访问,其操作的API基本上与文件操作的API一致. 打开串口 Win32 中用于打开串口的API 函数为CreateFile,其原型为: H ...
- windows串口编程Win32,PComm串口开发
https://blog.csdn.net/u011430225/article/details/51496456 https://blog.csdn.net/eit520/article/detai ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》- 5.串口和网络统一IO设计
目 录 第五章 串口和网络统一IO设计... 2 5.1 统一IO接口... 2 5.1.1 串口IO.. 4 5.1.2 网络IO.. ...
- mfc 调用Windows的API函数实现同步异步串口通信(源码)
在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...
- delphi SPCOMM串口控件
在Delphi7.0中安装Spcomm串口通信控件的方法为:选择Delphi7.0的“Component”菜单,点击“Install Component...”菜单项,然后在弹出的Into exist ...
随机推荐
- Python的基本语法和数据类型(简明教程)
声明:借鉴Python 简明教程 一.注释 注释: 就是对代码的解释 方便大家阅读python代码,在编辑器中快捷键: notepad :ctrl + q pycharm: ctrl + / ...
- IDEA 同时打开两个项目,相互引用
- 小白的java学习之路 “ 选择结构(二)”
switch 选择结构: 为什么使用switch选择结构: switch选择结构可以更好地解决等值判断问题. switch选择结构的四个关键字: switch case default ...
- 手动安装 saltshaker-plus 版本选择特别说明(后期重点讲解Docker安装方式)
前后端都建议使用1.12版本
- linux笔记-硬件命令【2】
1- 磁盘 1.1- 查看电脑磁盘类型 cat /sys/block/sda/queue/rotational 0 #固态盘 cat /sys/block/sdb/queue/rotational 1 ...
- Ubuntu在当前用户目录下安装python 包
对于tar.gz文件: tar -zxvf setuptools-19.6.tar.gz cd setuptools-19.6.tar.gz python3 setup.py build python ...
- JavaScript 自适应轮播图
代码 话不多说,先上代码,方便复制粘贴.演示 <!DOCTYPE html> <html lang="en"> <head> <meta ...
- CTF伪协议+preg_replace()函数的代码执行
一道学习中所遇到的ctf 步骤: 我们点击题目链接,然后在页面先点击”云平台后台管理中心“ 然后url后面跟了参数page,题目提示了一个文件包含,我们试试index.php 看到了输出了ok,应该是 ...
- iPad成为Windows系统的第二屏幕
一.Windows端软件准备 1.Splashtop Wired XDisplay Agent (官网下载 快速下载) 2.iTunes (点击此处跳转至微软应用商店) 二.iPad端软件准 ...
- MySQL必会的50个常见面试练习题
下面的SQL题目都是比较基础,比较常见的数据库SQL面试题,在技术面试环节虽然碰到相同题目的机会比较少,但解题的基本思路都是差 不多的.下面是SQL面试题描述: Student(Sid,Sname,S ...