文章目錄
- 一、RS232 簡介
- 1. 電氣特性
- 2. 傳輸速率
- 3. 傳輸距離
- 二、在 C++ 中實現 RS232 通信
- 1. Windows 平臺
- (1)打開串行端口
- (2)配置串行通信參數
- (3)發送數據
- (4)接收數據
- (5)主函數示例
- 2. Linux 平臺
- (1)打開串行端口
- (2)配置串行通信參數
- (3)發送數據
- (4)接收數據
- (5)主函數示例
- 三、注意事項
- 四、總結
在現代嵌入式系統和工業控制領域,RS232 串行通信仍然是一種不可或缺的技術。盡管 USB 和以太網等高速通信技術已經廣泛應用,但在一些需要低速、簡單通信的場景中,RS232 仍然是首選。本文將詳細介紹如何在 C++ 中實現與 RS232 的通信,包括 Windows 和 Linux 平臺的實現方法。
一、RS232 簡介
RS232 是一種串行通信協議,用于實現設備之間的近距離數據傳輸。它通過一對發送和接收引腳(TxD 和 RxD)進行數據通信,并支持控制信號(如 RTS 和 CTS)以實現流控制。RS232 的傳輸速率通常在幾百比特每秒(bps)到幾十千比特每秒(kbps)之間,適用于低速數據傳輸場景。
1. 電氣特性
RS232 使用負邏輯,邏輯“1”對應的電平范圍是 -3V 到 -15V,邏輯“0”對應的電平范圍是 +3V 到 +15V。這種設計使得信號在傳輸過程中具有一定的抗干擾能力。
2. 傳輸速率
RS232 的傳輸速率通常在幾百 bps 到幾十 kbps 之間。例如,常見的波特率有 9600 bps、19200 bps 和 115200 bps。波特率越高,數據傳輸速度越快,但傳輸距離和可靠性可能會受到影響。
3. 傳輸距離
RS232 的傳輸距離通常在 15 米以內。如果需要更長的傳輸距離,可以使用 RS485 等其他串行通信協議。
二、在 C++ 中實現 RS232 通信
在 C++ 中實現 RS232 通信,需要使用操作系統提供的串行通信 API。以下是基于 Windows 和 Linux 平臺的實現方法。
1. Windows 平臺
在 Windows 系統中,可以使用 Windows API 中的串行通信函數來實現與 RS232 的通信。以下是一個簡單的示例代碼,展示如何打開串行端口、設置通信參數、發送和接收數據。
(1)打開串行端口
#include <windows.h>
#include <iostream>// 打開串行端口
HANDLE OpenSerialPort(const char* portName)
{HANDLE hSerial;hSerial = CreateFile(portName, // 端口名稱,如 "COM1"GENERIC_READ | GENERIC_WRITE, // 讀寫權限0, // 不共享0, // 無安全屬性OPEN_EXISTING, // 打開已存在的設備0, // 非異步0 // 無模板);if (hSerial == INVALID_HANDLE_VALUE){std::cerr << "Error opening serial port" << std::endl;return INVALID_HANDLE_VALUE;}return hSerial;
}
(2)配置串行通信參數
// 配置串行通信參數
bool ConfigureSerialPort(HANDLE hSerial)
{DCB dcbSerialParams = { 0 };dcbSerialParams.DCBlength = sizeof(dcbSerialParams);if (!GetCommState(hSerial, &dcbSerialParams)){std::cerr << "Error getting state" << std::endl;return false;}dcbSerialParams.BaudRate = CBR_9600; // 波特率 9600dcbSerialParams.ByteSize = 8; // 數據位 8dcbSerialParams.StopBits = ONESTOPBIT; // 停止位 1dcbSerialParams.Parity = NOPARITY; // 無校驗位if (!SetCommState(hSerial, &dcbSerialParams)){std::cerr << "Error setting state" << std::endl;return false;}return true;
}
(3)發送數據
// 發送數據
bool WriteSerialPort(HANDLE hSerial, const char* data, DWORD size)
{DWORD bytesWritten;if (!WriteFile(hSerial, data, size, &bytesWritten, 0)){std::cerr << "Error writing to port" << std::endl;return false;}return true;
}
(4)接收數據
// 接收數據
bool ReadSerialPort(HANDLE hSerial, char* buffer, DWORD size)
{DWORD bytesRead;if (!ReadFile(hSerial, buffer, size, &bytesRead, 0)){std::cerr << "Error reading from port" << std::endl;return false;}return true;
}
(5)主函數示例
int main()
{const char* portName = "COM1";HANDLE hSerial = OpenSerialPort(portName);if (hSerial == INVALID_HANDLE_VALUE){return 1;}if (!ConfigureSerialPort(hSerial)){CloseHandle(hSerial);return 1;}const char* dataToSend = "Hello, Serial Port!";if (!WriteSerialPort(hSerial, dataToSend, strlen(dataToSend))){CloseHandle(hSerial);return 1;}char readBuffer[128];if (ReadSerialPort(hSerial, readBuffer, sizeof(readBuffer))){std::cout << "Received: " << readBuffer << std::endl;}CloseHandle(hSerial);return 0;
}
2. Linux 平臺
在 Linux 系統中,可以使用 POSIX 串行通信 API 來實現與 RS232 的通信。以下是一個簡單的示例代碼。
(1)打開串行端口
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <cstring>// 打開串行端口
int OpenSerialPort(const char* portName)
{int fd = open(portName, O_RDWR | O_NOCTTY | O_SYNC);if (fd < 0){std::cerr << "Error opening serial port" << std::endl;return -1;}return fd;
}
(2)配置串行通信參數
// 配置串行通信參數
bool ConfigureSerialPort(int fd)
{struct termios tty;if (tcgetattr(fd, &tty) != 0){std::cerr << "Error getting attributes" << std::endl;return false;}cfsetospeed(&tty, B9600); // 波特率 9600cfsetispeed(&tty, B9600);tty.c_cflag &= ~PARENB; // 無校驗位tty.c_cflag &= ~CSTOPB; // 1 停止位tty.c_cflag &= ~CSIZE; // 清除數據位掩碼tty.c_cflag |= CS8; // 8 數據位tty.c_cflag &= ~CRTSCTS; // 關閉硬件流控制tty.c_cflag |= CREAD | CLOCAL; // 啟用接收器,忽略調制解調器控制線tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 關閉軟件流控制tty.c_iflag &= ~(ICRNL | INLCR); // 禁用回車和換行的特殊處理tty.c_lflag &= ~ICANON;tty.c_lflag &= ~ECHO; // 關閉回顯tty.c_lflag &= ~ISIG; // 關閉信號字符tty.c_oflag &= ~OPOST; // 防止特殊解釋輸出數據tty.c_oflag &= ~ONLCR; // 防止將換行符轉換為回車換行符if (tcsetattr(fd, TCSANOW, &tty) != 0){std::cerr << "Error setting attributes" << std::endl;return false;}return true;
}
(3)發送數據
// 發送數據
bool WriteSerialPort(int fd, const char* data, size_t size)
{ssize_t bytesWritten = write(fd, data, size);if (bytesWritten < 0){std::cerr << "Error writing to port" << std::endl;return false;}return true;
}
(4)接收數據
// 接收數據
bool ReadSerialPort(int fd, char* buffer, size_t size)
{ssize_t bytesRead = read(fd, buffer, size);if (bytesRead < 0){std::cerr << "Error reading from port" << std::endl;return false;}return true;
}
(5)主函數示例
int main()
{const char* portName = "/dev/ttyS0";int fd = OpenSerialPort(portName);if (fd < 0){return 1;}if (!ConfigureSerialPort(fd)){close(fd);return 1;}const char* dataToSend = "Hello, Serial Port!";if (!WriteSerialPort(fd, dataToSend, strlen(dataToSend))){close(fd);return 1;}char readBuffer[128];if (ReadSerialPort(fd, readBuffer, sizeof(readBuffer))){std::cout << "Received: " << readBuffer << std::endl;}close(fd);return 0;
}
三、注意事項
- 波特率匹配:發送端和接收端的波特率必須一致,否則會導致數據傳輸錯誤。
- 串行端口名稱:在 Windows 上,串行端口名稱通常為 “COM1”、“COM2” 等;在 Linux 上,通常為 “/dev/ttyS0”、“/dev/ttyUSB0” 等。
- 錯誤處理:在實際應用中,需要對串行通信中的錯誤進行詳細處理,例如超時錯誤、硬件故障等。
- 多線程支持:在需要同時進行發送和接收操作時,可以使用多線程來實現。
四、總結
RS232 串行通信在工業控制和嵌入式系統中仍然具有重要地位。通過使用 Windows API 和 POSIX API,我們可以在 C++ 中實現與 RS232 的通信。本文提供了詳細的代碼示例,幫助開發者快速上手。在實際應用中,還需要根據具體需求進行適當的擴展和優化。