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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM