因为近段时间接触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. 对于tensorflow中的gradient_override_map函数的理解

    # #############添加############## def binarize(self, x): """ Clip and binarize tensor u ...

  2. simmon effect(psychology experiment) : this time, we add file_function who can creat a file in the window which contains our result

    #the real experiment for simon effect #load the library which is our need import pygame import sys i ...

  3. Conference deadlines

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

  4. Android 基础知识 -- BroadcastReceiver

    BroadcastReceiver 广播,是一种事件传递机制,可以跨应用进行事件传递(系统级). 在使用广播的时候,不宜添加过多的逻辑或者耗时(广播内不允许开辟线程)操作,超过10秒,导致ANR 1 ...

  5. linux--权限管理和用户管理

    权限 查看详细信息 ls -l - rw- r-- r-- 1 tom root 0 Jun 20 00:02 apple.txt 1 2 3 4 5 6 7 8 9 10 #1 文件的类型 #[-: ...

  6. Navicat Premium怎么设置字段的唯一性(UNIQUE)?

    参考链接:https://blog.csdn.net/Song_JiangTao/article/details/82192189 1.打开你想要设计的表 这里写图片描述2.清楚你想要设计哪个字段为唯 ...

  7. Laradock + tp5 + nginx 配置虚拟机域名始终跳转首页/502报错

    laradock默认配置文件如下: 配置运用于本地windows+phpstudy 部署的laravel项目未出现问题,如下: server { listen ; listen [::]:; serv ...

  8. php私有组件以及创建自己的composer私有组件(packagist+git+composer)

    1.私有组件 大多数时候我们使用的都是公开可用的开源组件,但有时候如果公司使用内部开发的PHP组件,而基于许可证和安全方面的问题不能将其开源,就需要使用私有组件.对Composer而言,这是小菜一碟. ...

  9. Proxy SwitchyOmega 使用黑名单和白名单

    “黑名单”会告诉代理工具,黑名单(国外)里面的网站要使用代理:“白名单”会告诉代理工具,白名单(大陆网站)里面的网站直接连接,其余使用代理. 黑名单PAC 黑名单PAC两条(任选其一):https:/ ...

  10. 2019 LOL 全球总决赛

                                        FPS 牛逼 涅槃重生