RS232 串行通信:C++ 實現指南

image.png

文章目錄

    • 一、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;
}

三、注意事項

  1. 波特率匹配:發送端和接收端的波特率必須一致,否則會導致數據傳輸錯誤。
  2. 串行端口名稱:在 Windows 上,串行端口名稱通常為 “COM1”、“COM2” 等;在 Linux 上,通常為 “/dev/ttyS0”、“/dev/ttyUSB0” 等。
  3. 錯誤處理:在實際應用中,需要對串行通信中的錯誤進行詳細處理,例如超時錯誤、硬件故障等。
  4. 多線程支持:在需要同時進行發送和接收操作時,可以使用多線程來實現。

四、總結

RS232 串行通信在工業控制和嵌入式系統中仍然具有重要地位。通過使用 Windows API 和 POSIX API,我們可以在 C++ 中實現與 RS232 的通信。本文提供了詳細的代碼示例,幫助開發者快速上手。在實際應用中,還需要根據具體需求進行適當的擴展和優化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902292.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902292.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902292.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux指令合集

一、VI的使用 命令行模式&#xff1a;默認此模式&#xff0c;從輸入模式回到命令行模式&#xff1a;esc &#xff0c; esc按完&#xff0c;insert消失 輸入模式&#xff1a;按 i 進入 &#xff0c; 看到insert就能編輯代碼 退出vi 保存代碼 命令行模式下 按&#xf…

IDEA使用jclasslib Bytecode Viewer查看jvm字節碼

學習jvm的時候&#xff0c;想查看字節碼和局部變量表&#xff0c;可以使用idea安裝jclasslib Bytecode View插件查看。 &#xff08;1&#xff09;安裝工具&#xff1a; 安裝完成后需要重啟idea. &#xff08;2&#xff09;準備一段代碼&#xff0c;編譯運行 package com.te…

從多個Excel批量篩查數據后合并到一起

這篇文章將講解如何批量的從多個Excel文件中篩選出需要的數據&#xff0c;最后合并到一張新的Excel。 全程0代碼圖形化界面操作。 準備數據 這里準備了3個測試文件&#xff0c;每個文件的格式是一樣的 現在我們需要篩選出每個文件里面&#xff0c;基金簡稱包含“南方遠見”&a…

Debian GNU/Linux的新手入門介紹

Debian GNU/Linux&#xff1a;起源、基本介紹與發行版對比 一、起源與發展歷程 Debian GNU/Linux 是現存最古老的 Linux 發行版之一&#xff0c;由 Ian Murdock 于 1993 年 8 月 16 日創立。其名稱結合了他的女友&#xff08;后成為妻子&#xff09;Debra 和他自己的名字 Ian…

Sentinel源碼—7.參數限流和注解的實現一

大綱 1.參數限流的原理和源碼 2.SentinelResource注解的使用和實現 1.參數限流的原理和源碼 (1)參數限流規則ParamFlowRule的配置Demo (2)ParamFlowSlot根據參數限流規則驗證請求 (1)參數限流規則ParamFlowRule的配置Demo 一.參數限流的應用場景 二.參數限流規則的屬性 …

多數據源配置(MyBatis-Plus vs AbstractRoutingDataSource)

MyBatis-Plus vs AbstractRoutingDataSource MyBatis-Plus多數據源配 1.添加依賴 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.0</version> <…

聊透多線程編程-線程互斥與同步-13. C# Mutex類實現線程互斥

目錄 一、什么是臨界區&#xff1f; 二、Mutex類簡介 三、Mutex的基本用法 解釋&#xff1a; 四、Mutex的工作原理 五、使用示例1-保護共享資源 解釋&#xff1a; 六、使用示例2-跨進程同步 示例場景 1. 進程A - 主進程 2. 進程B - 第二個進程 輸出結果 ProcessA …

stm32week12

stm32學習 九.stm32與HAL庫 2.HAL庫框架 總架構&#xff1a; 文件介紹&#xff1a; ppp是某一外設&#xff0c;ex是拓展功能 HAL庫API函數和變量命名規則&#xff1a; HAL庫對寄存器位操作的相關宏定義&#xff1a; HAL庫的回調函數&#xff1a; 3.STM32啟動過程 MDK編譯過…

opencv HSV的具體描述

色調H&#xff1a; 使用角度度量&#xff0c;取值范圍為0\~360&#xff0c;從紅色開始按逆時針方向計算&#xff0c;紅色為0&#xff0c;綠色為120&#xff0c;藍色為240。它們的補色是&#xff1a;黃色為60&#xff0c;青色為180&#xff0c;紫色為300。通過改變H的值&#x…

Java Lambda表達式指南

一、Lambda表達式基礎 1. 什么是Lambda表達式&#xff1f; 匿名函數&#xff1a;沒有名稱的函數函數式編程&#xff1a;可作為參數傳遞的代碼塊簡潔語法&#xff1a;替代匿名內部類的更緊湊寫法 2. 基本語法 (parameters) -> expression 或 (parameters) -> { statem…

面向對象設計中的類的分類:實體類、控制類和邊界類

目錄 前言1. 實體類&#xff08;Entity Class&#xff09;1.1 定義和作用1.2 實體類的特點1.3 實體類的示例 2. 控制類&#xff08;Control Class&#xff09;2.1 定義和作用2.2 控制類的特點2.3 控制類的示例 3. 邊界類&#xff08;Boundary Class&#xff09;3.1 定義和作用3…

C# 封裝教程

原文&#xff1a;C# 封裝_w3cschool &#xff08;注&#xff1a;本文為教程文章&#xff0c;請勿標記為付費文章&#xff01;特此聲明&#xff09; 封裝 被定義為"把一個或多個項目封閉在一個物理的或者邏輯的包中"。在面向對象程序設計方法論中&#xff0c;封裝是…

量化交易 - RSRS(阻力支撐相對強度)- 正確用法 - 年均收益18%

經過研究&#xff0c;發現RSRS的正確用法其實是需要用到兩個數據&#xff0c;分別是 n: 一階擬合樣本數&#xff0c;m:求均值方差樣本數&#xff0c;其中n比較小 如18&#xff0c;m比較大 如1100 經過調優后&#xff0c;收益率顯著上升&#xff01; 如下圖&#xff1a; &…

Oracle expdp的 EXCLUDE 參數詳解

Oracle expdp的 EXCLUDE 參數詳解 EXCLUDE 是 Oracle Data Pump Export (expdp) 工具中的一個關鍵參數&#xff0c;用于指定在導出過程中要排除的對象或對象類型。 一、基本語法 expdp username/password DUMPFILEexport.dmp DIRECTORYdpump_dir EXCLUDEobject_type[:name_c…

如何使用3DMAX插件PFSpliner將3D對象轉化為藝術樣條線?

什么是粒子流源(Particle Flow)是3DMAX的一個功能極其強大的粒子系統。它采用事件驅動模型,使用一個名為“粒子視圖”的特殊對話框。在“粒子視圖”中,您可以將描述粒子屬性(如形狀、速度、方向和一段時間內的旋轉)的單個運算符組合成稱為事件的組。每個操作符都提供一組…

【python】 循環語句(while)

1、循環語句 語法&#xff1a; while 條件:......... #只有條件為真時&#xff0c;才會執行while中的內容。 1.1循環語句基本使用 示例1&#xff1a; print("開始") while 1>2:print("人生得意須盡歡") print("結束") #輸出結果&#…

OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多變量時序預測一鍵對比

OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多變量時序預測一鍵對比 目錄 OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多變量時序預測一鍵對比預測效果基本介紹程序設計參考資料 預測效果 基本介紹 基于OOA-CN…

20250421在榮品的PRO-RK3566開發板的Android13下頻繁重啟RKNPU fde40000.npu: Adding to iommu gr

20250421在榮品的PRO-RK3566開發板的Android13下頻繁重啟RKNPU fde40000.npu: Adding to iommu gr 2025/4/21 14:50 緣起&#xff1a;電池沒電了&#xff0c;導致榮品的PRO-RK3566的核心板頻繁重啟。 內核時間4s就重啟。100%復現。 PRO-RK3566 Android13啟動到這里 復位&#…

動態監控進程

1.介紹: top和ps命令很相似,它們都是用來顯示正在執行的進程,top和ps最大的不同之處,在于top在執行中可以更新正在執行的進程. 2.基本語法&#xff1a; top [選項] 選項說明 ??僵死進程&#xff1a;內存沒有釋放,但是進程已經停止工作了,需要及時清理 交互操作說明 應用案…

657SJBH西藏藏藥特產銷售管理系統

畢業論文&#xff08;設計&#xff09;文獻綜述 西藏藏藥特產銷售管理系統的設計與實現 近年來&#xff0c;隨著網絡技術特別是Internet技術的普及和發展&#xff0c;電子商務的開發和應用成為一個熱門領域&#xff0c;在線藏藥特產銷售系統就是這其中的一員。 藏藥產業在西藏…