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

 

posted @ 2018-03-05 13:37  慧心的眼眸  阅读(4251)  评论(0编辑  收藏  举报