zoukankan      html  css  js  c++  java
  • 关于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("
    ");
     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("
    ");
    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 }
  • 相关阅读:
    InnoDB的锁机制浅析(二)—探索InnoDB中的锁(Record锁/Gap锁/Next-key锁/插入意向锁)
    InnoDB的锁机制浅析(一)—基本概念/兼容矩阵
    InnoDB的锁机制浅析(All in One)
    JMS Java消息服务(Java Message Service)
    命名和目录接口 JNDI-The Java Naming and Directory Interface
    Jenkins系列教程之
    Jenkins系列教程之
    Jenkins系列教程之
    【小笔记】大数据量excel解析工具性能对比
    【小笔记】Activiti扩展数据库支持类型
  • 原文地址:https://www.cnblogs.com/linxmouse/p/7841921.html
Copyright © 2011-2022 走看看