关于Win32串口

因为近段时间接触Hid相对来说多一些,由此忽略了串口中获取cbInQue这个重要的东西,下面是错误代码

 1 // Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include "Win32SerialPortLib.h"
 6 #include <stdio.h>
 7 
 8 HANDLE hcomm;
 9 EXTERN_C WIN32SERIALPORTLIB_API bool Open(char *com, int baud)
10 {
11     char szDCB[50];
12     sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', 8, 1);
13     hcomm = CreateFileA(com,
14         GENERIC_READ | GENERIC_WRITE,
15         0,
16         NULL,
17         OPEN_EXISTING,
18         0,
19         0);
20     if (hcomm == INVALID_HANDLE_VALUE) return false;
21     return true;
22 }
23 
24 EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
25 {
26     DWORD readed;
27     BOOL rt = ReadFile(hcomm, data, len, &readed, NULL);
28     if (!rt)
29     {
30         PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
31         return 0;
32     }
33 
34     return readed;
35 }
36 
37 EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
38 {
39     if (hcomm == INVALID_HANDLE_VALUE) return;
40     DWORD writed;
41     BOOL rt = WriteFile(hcomm, data, len, &writed, NULL);
42     if (!rt)
43     {
44         PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
45         return;
46     }
47 }
48 
49 EXTERN_C WIN32SERIALPORTLIB_API void Close()
50 {
51     if (hcomm != INVALID_HANDLE_VALUE)
52     {
53         CloseHandle(hcomm);
54         hcomm = INVALID_HANDLE_VALUE;
55     }
56 }
View Code

经过测试


 

  1 // Win32SerialPortTest.cpp : 定义控制台应用程序的入口点。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include <thread>
  6 #include <iostream>
  7 #include "Win32SerialPort.h"
  8 using namespace std;
  9 
 10 bool _stoprequired = false;
 11 
 12 void read_callback();
 13 void printhex(unsigned char *data, int len);
 14 
 15 int _tmain(int argc, _TCHAR* argv[])
 16 {
 17     Open("COM5", 9600);
 18     thread read_t(read_callback);
 19     read_t.detach();
 20 
 21     cout << endl;
 22     cout << "continue in main thread." << endl;
 23     //ab 69 42 01 fe c0 00 00 c0
 24     unsigned char data[] = { 0xab, 0x69, 0x42, 0x01, 0xfe, 0xc0, 0x00, 0x00, 0xc0 };
 25     Write(data, sizeof(data) / sizeof(unsigned char));
 26     
 27     // 获取标准输入输出设备句柄  
 28     HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 29     HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
 30 
 31     DWORD           dwRes, dwState = 0;
 32     INPUT_RECORD    keyRec;
 33     COORD           crHome = { 0, 0 }, crPos;
 34     char            ch;
 35     CONSOLE_SCREEN_BUFFER_INFO bInfo;
 36     while (true)
 37     {
 38         ReadConsoleInput(hIn, &keyRec, 1, &dwRes);
 39         if (keyRec.EventType == KEY_EVENT)
 40         {
 41             // Press key down
 42             if (keyRec.Event.KeyEvent.bKeyDown)
 43             {
 44                 // 基础功能键  
 45                 switch (keyRec.Event.KeyEvent.wVirtualKeyCode)
 46                 {
 47                     // 回车
 48                 case VK_RETURN:
 49                     printf("\n");
 50                     break;
 51 
 52                     // 空格
 53                 case VK_SPACE:
 54                     Write(data, sizeof(data) / sizeof(unsigned char));
 55                     break;
 56 
 57                 case VK_BACK:           // 按删除时删掉一个字符(只能当前行操作)  
 58                     GetConsoleScreenBufferInfo(hOut, &bInfo);
 59                     crPos = bInfo.dwCursorPosition;
 60                     if (crPos.X != 0)
 61                     {
 62                         crPos.X -= 1;
 63                     }
 64                     SetConsoleCursorPosition(hOut, crPos);
 65                     printf(" ");
 66                     SetConsoleCursorPosition(hOut, crPos);
 67                     break;
 68 
 69                 case VK_ESCAPE:         // 按ESC键时退出
 70                     _stoprequired = true;
 71                     Close();
 72                     Sleep(50);
 73                     CloseHandle(hOut);  // 关闭标准输出设备句柄  
 74                     CloseHandle(hIn);   // 关闭标准输入设备句柄  
 75                     return 0;
 76 
 77                 default:
 78                     break;
 79                 }
 80 
 81                 // 打印字符  
 82                 ch = keyRec.Event.KeyEvent.uChar.AsciiChar;
 83                 // 输出可以打印的字符(详参ASCII表)  
 84                 if (ch > 0x20 && ch < 0x7e)
 85                 {
 86                     putchar(ch);
 87                 }
 88             }
 89         }
 90     }
 91     
 92     return 0;
 93 }
 94 
 95 void read_callback()
 96 {
 97     unsigned char buff[256];
 98     while (!_stoprequired)
 99     {
100         int n = Read(buff, 256);
101         if (n > 0)
102         {
103             printhex(buff, n);
104         }
105         //cout << "detach test." << endl;
106         //this_thread::sleep_for(chrono::seconds(1));
107     }
108 }
109 
110 void printhex(unsigned char *data, int len)
111 {
112     for (int i = 0; i < len; i++)
113     {
114         printf("%2x ", data[i]);
115     }
116     printf("\n");
117 }
View Code

 

表现现象是Read函数不单单是阻塞,还会让Write函数也阻塞,这种情况是是没有留意到的地方,此处作一个记录.

 


 

 异步IO版本,异步代码上方的注释为同步IO版本


  1 // Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "Win32SerialPortLib.h"
  6 #include <stdio.h>
  7 
  8 HANDLE hcomm;
  9 OVERLAPPED ovw;
 10 OVERLAPPED ovr;
 11 EXTERN_C WIN32SERIALPORTLIB_API HANDLE Open(char *com, int baud)
 12 {
 13     char szDCB[50];
 14     sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', 8, 1);
 15     //hcomm = CreateFileA(com,
 16     //    GENERIC_READ | GENERIC_WRITE,
 17     //    0,
 18     //    NULL,
 19     //    OPEN_EXISTING,
 20     //    0,
 21     //    0);
 22     hcomm = CreateFileA(com,
 23         GENERIC_READ | GENERIC_WRITE,
 24         0,
 25         NULL,
 26         OPEN_EXISTING,
 27         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
 28         0);
 29     if (hcomm == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
 30     // 设置缓冲大小
 31     BOOL rt = SetupComm(hcomm, 4096, 4096);
 32     if (!rt) return INVALID_HANDLE_VALUE;
 33     // 设置超时
 34     COMMTIMEOUTS commtimeouts;
 35     commtimeouts.ReadIntervalTimeout = 0;
 36     commtimeouts.ReadTotalTimeoutConstant = 0;
 37     commtimeouts.ReadTotalTimeoutMultiplier = 0;
 38     commtimeouts.WriteTotalTimeoutConstant = 0;
 39     commtimeouts.WriteTotalTimeoutMultiplier = 0;
 40     rt = SetCommTimeouts(hcomm, &commtimeouts);
 41     if (!rt) return INVALID_HANDLE_VALUE;
 42     // 设置DCB
 43     DCB dcb;
 44 #ifdef UNICODE
 45     DWORD num = MultiByteToWideChar(CP_ACP, 0, szDCB, -1, NULL, 0);
 46     wchar_t *pwStr = new wchar_t[num];
 47     MultiByteToWideChar(CP_ACP, 0, szDCB, -1, pwStr, num);
 48 #else
 49     DWORD num = strlen(szDCB) + 1;
 50     char *pwStr = new char[num];
 51     strcpy(pwStr, szDCB);
 52 #endif
 53     rt = GetCommState(hcomm, &dcb);
 54     if (!rt) return INVALID_HANDLE_VALUE;
 55     rt = BuildCommDCB(pwStr, &dcb);
 56     if (!rt) return INVALID_HANDLE_VALUE;
 57     delete[] pwStr;
 58     rt = SetCommState(hcomm, &dcb);
 59     if (!rt) return INVALID_HANDLE_VALUE;
 60     // 清空串口缓冲区
 61     rt = PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT);
 62     if (!rt) return INVALID_HANDLE_VALUE;
 63 
 64     return hcomm;
 65 }
 66 
 67 EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
 68 {
 69     DWORD read_size = 0;
 70     if (hcomm == INVALID_HANDLE_VALUE) return 0;
 71     COMSTAT comstat;
 72     DWORD error;
 73     ClearCommError(hcomm, &error, &comstat);
 74     // 串口有错误
 75     if (error > 0)
 76     {
 77         PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
 78         return read_size;
 79     }
 80     if (comstat.cbInQue > 0)
 81     {
 82         //BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, NULL);
 83         //if (!rt) return 0;
 84         BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, &ovr);
 85         if (!rt)
 86         {
 87             rt = GetLastError();
 88             if (rt == ERROR_IO_PENDING)
 89             {
 90                 // 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
 91                 //rt = WaitForSingleObject(hcomm, 50);
 92                 //switch (rt)
 93                 //{
 94                 //case WAIT_OBJECT_0:
 95                 //    cout << "指定的对象处于有信号状态" << endl;
 96                 //    if (GetOverlappedResult(hcomm, &ovr, &read_size, FALSE))
 97                 //        cout << "read " << read_size << " bytes" << endl;
 98                 //    break;
 99                 //case WAIT_TIMEOUT:
100                 //    cout << "等待超时" << endl;
101                 //    break;
102                 //case WAIT_FAILED:
103                 //    cout << "出现错误,CODE [" << GetLastError() << "]" << endl;
104                 //    break;
105                 //case WAIT_ABANDONED:
106                 //    cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
107                 //    break;
108                 //}
109             }
110             else
111             {
112                 CancelIo(hcomm);
113                 return 0;
114             }
115         }
116     }
117 
118     return read_size;
119 }
120 
121 EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
122 {
123     DWORD write_size;
124     if (hcomm == INVALID_HANDLE_VALUE) return;
125     COMSTAT comstat;
126     DWORD error;
127     BOOL rt = ClearCommError(hcomm, &error, &comstat);
128     if (!rt) return;
129     // 串口有错误
130     if (error > 0)
131     {
132         PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
133         return;
134     }
135 
136     WriteFile(hcomm, data, len, &write_size, NULL);
137     rt = WriteFile(hcomm, data, len, &write_size, &ovw);
138     if (!rt)
139     {
140         rt = GetLastError();
141         if (rt == ERROR_IO_PENDING)
142         {
143             // 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
144             //rt = WaitForSingleObject(hcomm, 50);
145             //switch (rt)
146             //{
147             //case WAIT_OBJECT_0:
148             //    cout << "指定的对象处于有信号状态" << endl;
149             //    if (GetOverlappedResult(hcomm, &ovr, &write_size, FALSE))
150             //        cout << "write " << write_size << " bytes" << endl;
151             //    break;
152             //case WAIT_TIMEOUT:
153             //    cout << "等待超时" << endl;
154             //    break;
155             //case WAIT_FAILED:
156             //    cout << "出现错误,CODE [" << GetLastError() << "]" << endl;
157             //    break;
158             //case WAIT_ABANDONED:
159             //    cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
160             //    break;
161             //}
162         }
163         else
164         {
165             CancelIo(hcomm);
166             return;
167         }
168     }
169 }
170 
171 EXTERN_C WIN32SERIALPORTLIB_API void Close()
172 {
173     if (hcomm != INVALID_HANDLE_VALUE)
174     {
175         CancelIo(hcomm);
176         CloseHandle(hcomm);
177         hcomm = INVALID_HANDLE_VALUE;
178     }
179 }
posted @ 2017-11-16 00:13  非法关键字  阅读(503)  评论(0编辑  收藏  举报