因为近段时间接触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串口的更多相关文章

  1. Win32串口API

    在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...

  2. win32串口编程

    翻译自:ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.WIN32COM.v10.en/dnfiles/html/msdn_serial.htm 老外写的文章, ...

  3. [编译] 2、minGW gcc在windows搭建编译win32程序环境

    1.普通下载一个MinGW程序.安装之后可以直接将MinGW目录拷贝到总工程的tool里面: demo_mesh_common tree -L 2 . ├── app ├── bin ├── buil ...

  4. MSComm控件与Win32 API操作串口有何区别?

    MSComm控件与Win32 API操作串口有何区别? [问题点数:50分,结帖人shell_shell]   收藏帖子 回复 我是一个小兵,在战场上拼命!   结帖率 83.33% 我以前用MSCo ...

  5. 深入浅出VC++串口编程之基于Win32 API

    1.API描述 在WIN32 API中,串口使用文件方式进行访问,其操作的API基本上与文件操作的API一致. 打开串口 Win32 中用于打开串口的API 函数为CreateFile,其原型为: H ...

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

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

  7. [连载]《C#通讯(串口和网络)框架的设计与实现》- 5.串口和网络统一IO设计

    目       录 第五章           串口和网络统一IO设计... 2 5.1           统一IO接口... 2 5.1.1    串口IO.. 4 5.1.2    网络IO.. ...

  8. mfc 调用Windows的API函数实现同步异步串口通信(源码)

    在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...

  9. delphi SPCOMM串口控件

    在Delphi7.0中安装Spcomm串口通信控件的方法为:选择Delphi7.0的“Component”菜单,点击“Install Component...”菜单项,然后在弹出的Into exist ...

随机推荐

  1. Atlantis HDU - 1542 线段树+扫描线 求交叉图形面积

    //永远只考虑根节点的信息,说明在query时不会调用pushdown //所有操作均是成对出现,且先加后减 // #include <cstdio> #include <cstri ...

  2. 清北学堂—2020.1提高储备营—Day 1 morning(模拟、枚举、搜索)

    qbxt Day 1 morning --2020.1.17 济南 主讲:李佳实 目录一览 1.模拟和枚举 2.基础搜索算法(DFS.BFS.记忆化搜索)以及进阶搜索算法(纯靠自学) 总知识点:基础算 ...

  3. phpcms搜索给分页代码添加参数方法

    在使用PHPCMS开发网站时遇到了一个搜索功能,需要在搜索结果分页链接上添加一些传递的参数,不然不能够正确翻页. 方法: 找到\phpcms\libs\functions\global.func.ph ...

  4. Java使用POI读取Word中的表格

    个人博客 地址:https://www.wenhaofan.com/a/20190627135921 代码 package live.autu.word; import java.io.FileInp ...

  5. PHP0009:PHP基础-mysql

    以管理员省份启动记事本 修改host文件 插入外部sql数据

  6. JN_0014:win10命令窗口以管理员方式启动

    1,先打开命令窗口 2,固定到任务栏 3,右键任务栏图标 4,右键命令提示符, 5,选择以管理员方式启动.

  7. 关于Comparable和Comparator那些事

    在实际项目开发过程中,我们经常需要对某个对象或者某个集合中的元素进行排序,常用的两种方式是实现某个接口.常见的可以实现比较功能的接口有Comparable接口和 Comparator接口,那么这两个又 ...

  8. 技术之心 | 云信和TA们携手打响防疫战

      1月27日,教育部发布<关于2020年春季学期延期开学的通知>,各地高等院校.中小学.幼儿园纷纷推迟开学.疫情当前,学生们的鼠年寒假变得无比漫长. 网易云信众多教育客户以行动践行教育的 ...

  9. Conference deadlines

    1. NLP/IR/DM/ML Conference Deadlines(Updating) Two Principles of Deadlines:1. All deadlines converge ...

  10. 原生JS操作class 极致版

    // 获取class function getClass(el) { return el.getAttribute('class') } // 设置class function setClass(el ...