zoukankan      html  css  js  c++  java
  • WIN32控制台下的串口通信程序

    Winodws平台下,文件、通信设备、命名管道、邮件槽、磁盘、控制台等都是以文件的形式存在,它们的创建于打开操作都是利用CreateFile()函数。在MSDN中CreateFile()的声明方式为:

    [cpp] view plain copy

    1. HANDLE WINAPI CreateFile(  

    2.   _In_     LPCTSTR               lpFileName,  //文件名“COM1”,"COM2"等  

    3.   _In_     DWORD                 dwDesiredAccess,  //访问模式,读、写  

    4.   _In_     DWORD                 dwShareMode,  //共享模式,常为0表示独占方式  

    5.   _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,   //安全属性通常为NULL  

    6.   _In_     DWORD                 dwCreationDisposition,   //创建或打开方式  

    7.   _In_     DWORD                 dwFlagsAndAttributes,  //文件属性或标志  

    8.   _In_opt_ HANDLE                hTemplateFile  //临时文件,又或者模板,通常为NULL  

    9. );  

    以下Win32控制台程序演示CreateFile()函数的调用方式,

    [cpp] view plain copy

    1. #include <iostream>  

    2. #include <cstdlib>  

    3. #include <Windows.h>  

    4.   

    5. using namespace std;  

    6.   

    7. bool OpenPort();  //打开串口  

    8. bool OpenPort()  

    9. {  

    10.     HANDLE hComm;  

    11.     hComm = CreateFile(L"COM3",   //串口编号  

    12.         GENERIC_READ | GENERIC_WRITE,  //允许读写  

    13.         0,   //通讯设备必须以独占方式打开  

    14.         NULL,  

    15.         OPEN_EXISTING,   //通讯设备已存在  

    16.         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,   //重叠方式  

    17.         NULL);   //通讯设备不能用模板打开  

    18.     if (hComm == INVALID_HANDLE_VALUE)  

    19.     {  

    20.         CloseHandle(hComm);  

    21.         return FALSE;  

    22.     }  

    23.     else  

    24.         return TRUE;  

    25.   

    26. }  

    27. int main()  

    28. {  

    29.     bool open;  

    30.     open = OpenPort();  

    31.     if (open)  

    32.         cout << "Open serial port successfully!" << endl;  

    33.     else  

    34.         cout << "Open serial port unsuccessfully!" << endl;  

    35.     return EXIT_SUCCESS;  

    36. }  

    我的主机只有一个串口COM1,使用虚拟串口软件额外创建了两个窗口COM2和COM3,修改COM口均能测试成功,如下所示:

    Windows串口通信中还会用到设备控制、超时控制、通信错误、通信状态、通信事件等操作,以下演示了对设备控制DCB和超时控制COMMTIMEOUTS的设置

    [cpp] view plain copy

    1. #include <iostream>  

    2. #include <cstdlib>  

    3. #include <Windows.h>  

    4.   

    5. bool OpenPort();  //打开串口  

    6. bool SetupDCB(int rate_arg); //设置DCB设备控制块  

    7. bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier,  

    8.     DWORD ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant);  //超时设置  

    9. HANDLE hComm;  

    10. bool OpenPort()  

    11. {  

    12.     //HANDLE hComm;  

    13.     hComm = CreateFile(L"COM1",  //指定串口  

    14.         GENERIC_READ | GENERIC_WRITE,  //允许读写  

    15.         0,  //以独占方式打开  

    16.         0,  //无安全属性  

    17.         OPEN_EXISTING,  //通讯设备已存在  

    18.         0,  //同步I/O  

    19.         0);   //不指定模式  

    20.     if (hComm == INVALID_HANDLE_VALUE)  

    21.     {  

    22.         CloseHandle(hComm);  

    23.         return FALSE;  

    24.     }  

    25.     else  

    26.         return TRUE;  

    27. }  

    28.   

    29. bool SetupDCB(int rate_arg)  

    30. {  

    31.     DCB dcb;  

    32.     memset(&dcb, 0,sizeof(dcb));  

    33.     if (!GetCommState(hComm, &dcb))  //获取当前DCB配置  

    34.         return FALSE;  

    35.     /* ---------- 串口设置 ------- */  

    36.     dcb.DCBlength = sizeof(dcb);  //DCB块大小  

    37.     dcb.BaudRate = rate_arg;  //波特率  

    38.     dcb.Parity = NOPARITY;    //奇偶校验0-4:分别表示不校验、奇校验,偶校验、标号、空格  

    39.     dcb.fParity = 0;   //不允许奇偶校验  

    40.     dcb.StopBits = ONESTOPBIT;   //停止位  

    41.     dcb.ByteSize = 8;   //数据位,以字节表示4-8  

    42.     dcb.fOutxCtsFlow = 0;   //CTS输出流控制  

    43.     dcb.fOutxDsrFlow = 0;   //DSR输出流控制  

    44.     dcb.fDtrControl = DTR_CONTROL_DISABLE;  //DTR流控制类型  

    45.     dcb.fDsrSensitivity = 0;   //对DSR信号线不敏感  

    46.     dcb.fRtsControl = RTS_CONTROL_DISABLE;  //RTS流控制  

    47.     dcb.fOutX = 0;   //XON/XOFF输出流控制  

    48.     dcb.fInX = 0;   //XON/XOFF输入流控制  

    49.     /* ---------- 容错机制 ------- */  

    50.     dcb.fErrorChar = 0;   //允许错误替换  

    51.     dcb.fBinary = 1;   //二进制模式,不检测EOF  

    52.     dcb.fNull = 0;   //允许剥离,去掉NULL字符  

    53.     dcb.fAbortOnError = 0;   //有错误时终止读写操作  

    54.     dcb.wReserved = 0;   //  

    55.     dcb.XonLim = 2;   //XON发送字符之前缓冲区中允许接收的最小字节数  

    56.     dcb.XoffLim = 4;   //XON发送字符之前缓冲区中允许的最小可用字节数  

    57.     dcb.XonChar = 0x13;   //发送和接受XON字符  

    58.     dcb.XoffChar = 0x19;   //发送和接受XOFF字符  

    59.     dcb.EvtChar = 0;   //接收到的事件字符  

    60.     if (!SetCommState(hComm, &dcb))  

    61.         return FALSE;  

    62.     else  

    63.         return TRUE;  

    64. }  

    65.   

    66. bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier,  

    67.     DWORD ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant)  

    68. {  

    69.     COMMTIMEOUTS time;  

    70.     time.ReadIntervalTimeout = ReadInterval;   //读时间超时  

    71.     time.ReadTotalTimeoutConstant = ReadTotalConstant;  //读时间常量  

    72.     time.ReadTotalTimeoutMultiplier = ReadTotalMultiplier;  //读时间系数  

    73.     time.WriteTotalTimeoutConstant = WriteTotalConstant;  //写时间常量  

    74.     time.WriteTotalTimeoutMultiplier = WriteTotalMultiplier;  //写时间系数  

    75.     if (!SetCommTimeouts(hComm, &time))  

    76.         return FALSE;  

    77.     else  

    78.         return TRUE;  

    79. }  

    80. int main()  

    81. {  

    82.     if (OpenPort())  

    83.         std::cout << "Open port success" << std::endl;  

    84.     if (SetupDCB(9600))  

    85.         std::cout << "Set DCB success" << std::endl;  

    86.     if (SetupTimeout(0, 0, 0, 0, 0))  

    87.         std::cout << "Set timeout success" << std::endl;  

    88.     SetCommMask(hComm, EV_RXCHAR);  //当有字符在inbuf中时产生这个事件  

    89.     PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);  

    90.   

    91.     return EXIT_SUCCESS;  

    92. }  


    COM1口的测试结果如下,

     

    串口的读写操作:

    本例实现串口的读写,采用虚拟串口虚拟一对串口COM2和COM3,COM2用于接收,COM3用于发送。完整代码如下:

    [cpp] view plain copy

    1. #include <iostream>  

    2. #include <cstdlib>  

    3. #include <windows.h>  

    4.   

    5. HANDLE hComm;  

    6. OVERLAPPED OverLapped;  

    7. COMSTAT Comstat;  

    8. DWORD dwCommEvents;  

    9.   

    10. bool OpenPort();  //打开串口  

    11. bool SetupDCB(int rate_arg);  //设置DCB  

    12. bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier, DWORD  

    13.     ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant);   //设置超时  

    14. void ReciveChar();   //接收字符  

    15. bool WriteChar(char* szWriteBuffer, DWORD dwSend);  //发送字符  

    16.   

    17. bool OpenPort()  

    18. {  

    19.     hComm = CreateFile(L"COM2",  

    20.         GENERIC_READ | GENERIC_WRITE,  

    21.         0,  

    22.         0,  

    23.         OPEN_EXISTING,  

    24.         FILE_FLAG_OVERLAPPED,  

    25.         0);  

    26.     if (hComm == INVALID_HANDLE_VALUE)  

    27.         return FALSE;  

    28.     else  

    29.         return true;  

    30. }  

    31.   

    32. bool SetupDCB(int rate_arg)  

    33. {  

    34.     DCB dcb;  

    35.     memset(&dcb, 0, sizeof(dcb));  

    36.     if (!GetCommState(hComm, &dcb))//获取当前DCB配置  

    37.     {  

    38.         return FALSE;  

    39.     }  

    40.     dcb.DCBlength = sizeof(dcb);  

    41.     /* ---------- Serial Port Config ------- */  

    42.     dcb.BaudRate = rate_arg;  

    43.     dcb.Parity = NOPARITY;  

    44.     dcb.fParity = 0;  

    45.     dcb.StopBits = ONESTOPBIT;  

    46.     dcb.ByteSize = 8;  

    47.     dcb.fOutxCtsFlow = 0;  

    48.     dcb.fOutxDsrFlow = 0;  

    49.     dcb.fDtrControl = DTR_CONTROL_DISABLE;  

    50.     dcb.fDsrSensitivity = 0;  

    51.     dcb.fRtsControl = RTS_CONTROL_DISABLE;  

    52.     dcb.fOutX = 0;  

    53.     dcb.fInX = 0;  

    54.     dcb.fErrorChar = 0;  

    55.     dcb.fBinary = 1;  

    56.     dcb.fNull = 0;  

    57.     dcb.fAbortOnError = 0;  

    58.     dcb.wReserved = 0;  

    59.     dcb.XonLim = 2;  

    60.     dcb.XoffLim = 4;  

    61.     dcb.XonChar = 0x13;  

    62.     dcb.XoffChar = 0x19;  

    63.     dcb.EvtChar = 0;  

    64.     if (!SetCommState(hComm, &dcb))  

    65.     {  

    66.         return false;  

    67.     }  

    68.     else  

    69.         return true;  

    70. }  

    71.   

    72. bool SetupTimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier, DWORD  

    73.     ReadTotalConstant, DWORD WriteTotalMultiplier, DWORD WriteTotalConstant)  

    74. {  

    75.     COMMTIMEOUTS timeouts;  

    76.     timeouts.ReadIntervalTimeout = ReadInterval;  

    77.     timeouts.ReadTotalTimeoutConstant = ReadTotalConstant;  

    78.     timeouts.ReadTotalTimeoutMultiplier = ReadTotalMultiplier;  

    79.     timeouts.WriteTotalTimeoutConstant = WriteTotalConstant;  

    80.     timeouts.WriteTotalTimeoutMultiplier = WriteTotalMultiplier;  

    81.     if (!SetCommTimeouts(hComm, &timeouts))  

    82.     {  

    83.         return false;  

    84.     }  

    85.     else  

    86.         return true;  

    87. }  

    88.   

    89. void ReciveChar()  

    90. {  

    91.     bool bRead = TRUE;  

    92.     bool bResult = TRUE;  

    93.     DWORD dwError = 0;  

    94.     DWORD BytesRead = 0;  

    95.     char RXBuff;  

    96.     for (;;)  

    97.     {  

    98.         bResult = ClearCommError(hComm, &dwError, &Comstat);  

    99.         if (Comstat.cbInQue == 0)  

    100.             continue;  

    101.         if (bRead)  

    102.         {  

    103.             bResult = ReadFile(hComm,  //通信设备(此处为串口)句柄,由CreateFile()返回值得到  

    104.                 &RXBuff,  //指向接收缓冲区  

    105.                 1,  //指明要从串口中读取的字节数  

    106.                 &BytesRead,   //  

    107.                 &OverLapped);  //OVERLAPPED结构  

    108.             std::cout << RXBuff << std::endl;  

    109.             if (!bResult)  

    110.             {  

    111.                 switch (dwError == GetLastError())  

    112.                 {  

    113.                 case ERROR_IO_PENDING:  

    114.                     bRead = FALSE;  

    115.                     break;  

    116.                 default:  

    117.                     break;  

    118.                 }  

    119.             }  

    120.         }  

    121.         else  

    122.         {  

    123.             bRead = TRUE;  

    124.         }  

    125.     }  

    126.     if (!bRead)  

    127.     {  

    128.         bRead = TRUE;  

    129.         bResult = GetOverlappedResult(hComm,  

    130.             &OverLapped,  

    131.             &BytesRead,  

    132.             TRUE);  

    133.     }  

    134. }  

    135.   

    136. bool WriteChar(char* szWriteBuffer, DWORD dwSend)  

    137. {  

    138.     bool bWrite = TRUE;  

    139.     bool bResult = TRUE;  

    140.     DWORD BytesSent = 0;  

    141.     HANDLE hWriteEvent=NULL;  

    142.     ResetEvent(hWriteEvent);  

    143.     if (bWrite)  

    144.     {  

    145.         OverLapped.Offset = 0;  

    146.         OverLapped.OffsetHigh = 0;  

    147.         bResult = WriteFile(hComm,  //通信设备句柄,CreateFile()返回值得到  

    148.             szWriteBuffer,  //指向写入数据缓冲区  

    149.             dwSend,  //设置要写的字节数  

    150.             &BytesSent,  //  

    151.             &OverLapped);  //指向异步I/O数据  

    152.         if (!bResult)  

    153.         {  

    154.             DWORD dwError = GetLastError();  

    155.             switch (dwError)  

    156.             {  

    157.             case ERROR_IO_PENDING:  

    158.                 BytesSent = 0;  

    159.                 bWrite = FALSE;  

    160.                 break;  

    161.             default:  

    162.                 break;  

    163.             }  

    164.         }  

    165.     }  

    166.     if (!bWrite)  

    167.     {  

    168.         bWrite = TRUE;  

    169.         bResult = GetOverlappedResult(hComm,  

    170.             &OverLapped,  

    171.             &BytesSent,  

    172.             TRUE);  

    173.         if (!bResult)  

    174.         {  

    175.             std::cout << "GetOverlappedResults() in WriteFile()" << std::endl;  

    176.         }  

    177.     }  

    178.     if (BytesSent != dwSend)  

    179.     {  

    180.         std::cout << "WARNING: WriteFile() error.. Bytes Sent:" << BytesSent << "; Message Length: " << strlen((char*)szWriteBuffer) << std::endl;  

    181.     }  

    182.     return TRUE;  

    183. }  

    184. int main()  

    185. {  

    186.     if (OpenPort())  

    187.         std::cout << "Open port success" << std::endl;  

    188.     if (SetupDCB(9600))  

    189.         std::cout << "Set DCB success" << std::endl;  

    190.     if (SetupTimeout(0, 0, 0, 0, 0))  

    191.         std::cout << "Set timeout success" << std::endl;  

    192.     PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);  

    193.     WriteChar("Please send data:", 20);  

    194.     std::cout << "Received data:";  

    195.     ReciveChar();  

    196.     return EXIT_SUCCESS;  

    197. }  

    首先编译运行如下结果:

     

    此时打开串口调试助手,设置串口号为COM3,波特率9600,数据位8,停止位1,以ASCII码形式发送,然后在发送栏写入要发送的字符如“Hello world!”,点击发送,COM2口就可以成功接收发送来的数据,并且COM3口成功接收到了COM2发来的数据请求。图如所示,

     

     

     全新视频:www.makeru.com.cn/?t=12           嵌入式学习交流群:561213221

  • 相关阅读:
    hive 之only supports newline ' ' right now. Error encountered near token ''报错
    四、第三方图标库
    三、工具模块封装(二):封装mock模块
    三、工具模块封装(一):封装axios模块
    二、前端项目案例
    一、搭建前端开发环境(Vue+element)
    注册中心(Consul)
    系统服务监控(Spring Boot Admin)
    JWT
    Spring Security(四)
  • 原文地址:https://www.cnblogs.com/huan-huan/p/8508528.html
Copyright © 2011-2022 走看看