上下位機通訊規則

0:事由

最近開發,上位機Qt與下位機通訊的時候發現通訊規則有些不一樣,這里簡單記錄一下 。所有代碼基于元寶生成,屬于偽代碼不保證真實可用,啊但是邏輯是這么個邏輯。


1:底層通訊規則

????????以STM32向上位機通訊通訊基礎為例:

#include "main.h"
#include "usart.h"
#include "gpio.h"void SystemClock_Config(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();uint8_t data_to_send[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF}; // 8個字節數據uint16_t data_length = sizeof(data_to_send); // 數據長度=8while (1){// 發送多個字節HAL_UART_Transmit(&huart1, data_to_send, data_length, HAL_MAX_DELAY);// 延時1秒(可選)HAL_Delay(1000);}
}

還有一種發送的案例如下:

#include "main.h"
#include "usart.h"
#include "gpio.h"void SystemClock_Config(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();uint16_t sensor_data_u16 = 0x1234; // 16位數據uint32_t sensor_data_u32 = 0x12345678; // 32位數據uint8_t u16_data_bytes[2];uint8_t u32_data_bytes[4];// 拆分u16數據(大端模式)u16_data_bytes[0] = (sensor_data_u16 >> 8) & 0xFF; // 高字節u16_data_bytes[1] = sensor_data_u16 & 0xFF;        // 低字節// 拆分u32數據(大端模式)u32_data_bytes[0] = (sensor_data_u32 >> 24) & 0xFF; // 最高字節u32_data_bytes[1] = (sensor_data_u32 >> 16) & 0xFF;u32_data_bytes[2] = (sensor_data_u32 >> 8) & 0xFF;u32_data_bytes[3] = sensor_data_u32 & 0xFF;         // 最低字節while (1){// 發送u16數據(2字節)HAL_UART_Transmit(&huart1, u16_data_bytes, 2, HAL_MAX_DELAY);// 發送u32數據(4字節)HAL_UART_Transmit(&huart1, u32_data_bytes, 4, HAL_MAX_DELAY);// 延時1秒HAL_Delay(1000);}
}

這里簡單說一下他們通訊的原理:底層向上位機通訊的是以字節為單位發送的一個字節(8位)可以用兩個十六進制(Hex)字符表示。你想發送多少個字節就多少個字節乘以二發送多少個16進制的數。在底層有三個特別經典的數據類型:

uint8_t flag = 0x01;   //兩個16進制  8位數據 一個字節
uint16_t sensor_data_u16 = 0x1234; //四個16進制 16位數據  兩個字節
uint32_t sensor_data_u32 = 0x12345678; //八個16進制 32位數據    四個字節

然后如果想發送多個字節的話,以下面的代碼為例

#include "usart.h"void send_sensor_data() {uint8_t flag = 0x01;               // 1字節uint16_t sensor_data_u16 = 0x1234; // 2字節uint32_t sensor_data_u32 = 0x12345678; // 4字節uint8_t tx_buffer[7]; // 總字節數: 1 + 2 + 4 = 7uint8_t index = 0;// 拼接數據(注意字節序!)tx_buffer[index++] = flag;                          // 直接拷貝1字節// 拆分uint16_t為2字節(假設使用大端序)tx_buffer[index++] = (sensor_data_u16 >> 8) & 0xFF; // 高字節tx_buffer[index++] = sensor_data_u16 & 0xFF;        // 低字節// 拆分uint32_t為4字節(大端序)tx_buffer[index++] = (sensor_data_u32 >> 24) & 0xFF; // 最高字節tx_buffer[index++] = (sensor_data_u32 >> 16) & 0xFF;tx_buffer[index++] = (sensor_data_u32 >> 8) & 0xFF;tx_buffer[index++] = sensor_data_u32 & 0xFF;         // 最低字節// 通過UART發送HAL_UART_Transmit(&huart1, tx_buffer, sizeof(tx_buffer), HAL_MAX_DELAY);
}

2:上位機處理數據

上位機通過串口接收數據的時候可能會有各方面的問題,比如說需要設置串口的波特率、串口、比校驗碼、當然最主要還是需要借助串口調試助手工具來進行調試。

但無論如何只要你能接收到的數據你就會發現你的數據其實是很亂的因為你不知道從哪個地方開始然后就需要下沉向上層傳輸數據時在頭部引入兩個沒有任何意義的字節,即引入一個頭部。根據這個頭部來確定發送數據的長度。一般接受的邏輯是這樣一個結構

[Header1][Header2][Length][Flag][u16_Data][u32_Data][CRC][Footer]

  • ??Header1/Header2??:?0xAA 0x55(起始標志)
  • ??Length??: 數據部分長度(固定為?7?字節,1+2+4
  • ??Flag??: 用戶標志(uint8_t
  • ??u16_Data/u32_Data??: 傳感器數據
  • ??CRC??: 校驗碼(簡單求和校驗)
  • ??Footer??:?0xBB(結束標志)

當然這個接收也是以字節為單位進行接收的(偽代碼)。

    while (1) {// 1. 從串口讀取數據到緩存(偽代碼,需替換為實際串口讀取函數)uint8_t byte;if (serial_read_byte(&byte)) {  // 假設serial_read_byte()從串口讀取1字節serial_buf.buffer[serial_buf.index++] = byte;// 2. 檢查緩存中是否有完整幀(從頭部開始)while (serial_buf.index >= 2) {  // 至少需要Header1/Header2// 查找頭部起始位置(簡化版:假設頭部在緩存開頭)if (serial_buf.buffer[0] == HEADER1 && serial_buf.buffer[1] == HEADER2) {// 3. 檢查緩存是否足夠容納一幀uint8_t frame_length = 2 + 1 + EXPECTED_LEN + 1 + 1;  // 頭+長度+CRC+尾if (serial_buf.index >= frame_length) {// 4. 提取完整幀uint8_t frame[256] = {0};memcpy(frame, serial_buf.buffer, frame_length);// 5. 解析幀if (parse_frame(frame, &sensor_data) == 0) {// 6. 處理有效數據(示例:打印)printf("解析成功: flag=0x%02X, u16=0x%04X, u32=0x%08X\n",sensor_data.flag, sensor_data.u16_data, sensor_data.u32_data);}// 7. 移除已處理的數據(滑動窗口)serial_buf.index -= frame_length;memmove(serial_buf.buffer, &serial_buf.buffer[frame_length], serial_buf.index);} else {break;  // 數據不足,等待更多字節}} else {// 頭部不匹配,丟棄第一個字節(避免死循環)memmove(serial_buf.buffer, &serial_buf.buffer[1], --serial_buf.index);}}}

上面的代碼其實還是比較難懂的主要就是說干了以下幾個事情:

  1. 首先是根據下位機傳送出來的數據,并放到一個數組中。這這主要是根據頭部碼以及長度來確定的
  2. 其次是取出其中的數據具體就是提取從哪一字節到哪一個字節再取出來,然后進行分析解碼。
QByteArray pressureData = frame.mid(4, 4);
如果你有一個 frame 的16進制表示(比如 "01 02 03 04 05 06 07 08 09 0a 0b 0c"),那么:
第4個字節(索引4)是 05,
接下來的4個字節是 05 06 07 08。
所以 pressureData 就是 05 06 07 08(16進制)。

????????存在一個問題就是這個數據傳輸到底是第一個字節是高位還是后一個字節是高位的問題,也就是所謂的小端字節跟大端字節的一個問題

QByteArray frame = QByteArray::fromHex("0102030405060708090a0b0c"); // 示例數據
QByteArray pressureData = frame.mid(4, 4); // 提取第4~7字節(索引4開始)??小端解析??:0x08 0x07 0x06 0x05 → 0x08070605 → 84281096
??大端解析??:0x05 0x06 0x07 0x08 → 0x05060708 → 134810149// 打印提取的16進制數據
qDebug() << "Extracted data (hex):" << pressureData.toHex(); // 輸出 "05060708"// 轉換為十進制(假設是小端字節序)
quint32 pressureValue = static_cast<quint32>(pressureData[0]) |(static_cast<quint32>(pressureData[1]) << 8) |(static_cast<quint32>(pressureData[2]) << 16) |(static_cast<quint32>(pressureData[3]) << 24);
qDebug() << "Pressure value (decimal, little endian):" << pressureValue; // 輸出 84281096// 如果是大端字節序
quint32 pressureValueBigEndian = static_cast<quint32>(pressureData[3]) |(static_cast<quint32>(pressureData[2]) << 8) |(static_cast<quint32>(pressureData[1]) << 16) |(static_cast<quint32>(pressureData[0]) << 24);
qDebug() << "Pressure value (decimal, big endian):" << pressureValueBigEndian; // 輸出 134810149

當然一般來說他就是按照大端解析進行的,就是按照正常人的思維從左至右從大到小(當然了是按照正常人的思維進行的考慮到數據加密的話可能會有一點不一樣)。?

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

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

相關文章

創建平衡二叉樹C++

給你一個整數數組 nums &#xff0c;其中元素已經按 升序 排列&#xff0c;請你將其轉換為一棵 平衡 二叉搜索樹。 平衡二叉樹&#xff1a;每個節點的左右子樹高度差不超過1 class Solution { public:TreeNode* dfs(vector<int>& nums, int left, int right){if(l…

海光の初體驗

背景 八張K100的風扇已經將近一年沒轉過了…早在今年4月29日&#xff0c;Qwen3正式發布并全部開源8款「混合推理模型」。作為Qwen系列中的最新一代大型語言模型&#xff0c;Qwen3在推理、指令遵循、工具調用、多語言能力等方面進行了全面增強。海光DCU&#xff08;Deep Comput…

場外交易(OTC)財富管理系統開發及解決方案報告

——跨境金融科技賦能機構客戶新增長 一、OTC市場現狀與機構業務痛點 1. 政策機遇與市場擴容 “北向互換通”期限延長&#xff1a;2025年7月1日&#xff0c;中國外匯交易中心聯合香港交易所將利率互換合約期限延長至30年&#xff0c;首日交易規模達15.3億元&#xff0c;填補超…

pytorch底層原理學習--JIT與torchscript

文章目錄 0 目的1 TorchScript1.1 語言特性的限定性1.2 設計目的&#xff1a;模型表達的專注性 2pytorch JIT&#xff08;Just-in-time compilation)2.1pytorch JIT定義2.1pytorch JIT整個過程&#xff1a;1. 前端轉換層&#xff1a;生成靜態計算圖2. 中間表示層&#xff08;IR…

Ubuntu+Nginx+php+SQLite3+typecho手動搭建個人博客

零.Ubuntu環境 一.安裝nginx 使用以下指令進行nginx web服務器安裝&#xff1a; apt-get install nginx 如果提示找不到安裝包&#xff0c;也可以更新一下系統的apt環境包&#xff1a; sudo apt update 安裝完成后&#xff0c;可以使用以下指令查看nginx是否處于激活狀態&#…

網絡協議概念與應用層

1.概念 1.1 例子 點外賣 上述這個過程,就是自定義協議 自定義協議,具體的方式也是非常靈活的 2.幾種開發中更常見的格式 2.1xml 上古時期的組織數據的格式 通過標簽來組織數據 xml的優勢:讓數據的可讀性變得更好了 劣勢:標簽寫起來繁瑣,傳輸的時候也占用更多網絡帶寬 2.2…

pytorch學習—7.處理多維特征的輸入

2. 線性模型 3.梯度下降算法 4.反向傳播(用pytorch算梯度) 5.用pytorch實現線性回歸 6.logistic回歸 7.處理多維特征的輸入_嗶哩嗶哩_bilibili 7.1代碼復現: import numpy as np import torch import matplotlib.pyplot as plt# 1. 獲取數據集 xy_data = np.lo

AI助手“智普清言”《三元》(Python)詩解

文本邏輯解清晰&#xff0c;詩意對應技法輕。 筆記模板由python腳本于2025-07-01 06:54:55創建&#xff0c;本篇筆記適合喜歡python三元語句的coder翻閱。 學習的細節是歡悅的歷程 博客的核心價值&#xff1a;在于輸出思考與經驗&#xff0c;而不僅僅是知識的簡單復述。 Pytho…

本地RAG實戰:用Spring AI+Ollama+DeepSeek+ChromaDB增強文檔問答

本文手把手教你在本地部署RAG系統&#xff1a; 用 Spring AI 整合 Ollama&#xff08;運行DeepSeek中文模型&#xff09;ChromaDB 存儲本地文檔&#xff08;PDF/TXT&#xff09;向量Java程序實現&#xff1a;文檔解析 → 語義檢索 → 增強生成 最終效果&#xff1a;模型回答更準…

Python 數據分析:DataFrame,生成,用字典創建 DataFrame ,鍵值對數量不一樣怎么辦?

目錄 1 示例代碼2 歡迎糾錯3 論文寫作/Python 學習智能體------以下關于 Markdown 編輯器新的改變功能快捷鍵合理的創建標題&#xff0c;有助于目錄的生成如何改變文本的樣式插入鏈接與圖片如何插入一段漂亮的代碼片生成一個適合你的列表創建一個表格設定內容居中、居左、居右S…

Java 并發編程的 CAS(Compare and Swap)是什么?

CAS&#xff08;Compare and Swap&#xff0c;比較并交換&#xff09; 并非 Java 語言特有的概念&#xff0c;而是現代計算機硬件提供的一條核心原子指令。在 Java 并發編程中&#xff0c;它扮演著“幕后英雄”的角色&#xff0c;是構建高性能、無鎖并發工具&#xff08;如原子…

【UnityAssetBundle】AssetBundle打包

AssetBundle生成AB包資源文件方式&#xff1a; Unity編輯器開發&#xff0c;自定義打包工具&#xff1b;官方提供好的打包工具&#xff0c;Asset Bundle Browser 打包 選擇一個資源&#xff0c;new一個壓縮包名稱或選擇一個壓縮包名稱 點擊Window->AssetBundle Browser&…

Hush Puppies大中華區鞋類業務移交品牌方繼續經營

據悉&#xff0c;隨著百麗集團運營的暇步士&#xff08;Hush Puppies&#xff09;大中華區鞋類授權的到期&#xff0c;暇步士&#xff08;Hush Puppies&#xff09;鞋類業務已開始運營權移交。其中線上渠道授權于2025年6月30日正式到期&#xff0c;線下渠道將于2025年12月31日前…

解釋LLM怎么預測下一個詞語的

解釋LLM怎么預測下一個詞語的 通過上文詞的向量進行映射 在Transformer架構的大語言模型(如GPT系列、BERT等)中,詞語會先被轉化為詞向量。在預測下一個詞時,模型會基于之前所有詞的向量表示(并非僅僅上一個詞,但上一個詞的向量是重要信息來源之一)進行計算。 以GPT-2…

DAY 49 CBAM注意力

目錄 DAY 49 CBAM注意力1.通道注意力模塊復習2.空間注意力模塊3.CBAM的定義作業&#xff1a;嘗試對今天的模型檢查參數數目&#xff0c;并用tensorboard查看訓練過程 DAY 49 CBAM注意力 1.通道注意力模塊復習 2.空間注意力模塊 3.CBAM的定義 import torch import torch.nn …

【網絡】Linux 內核優化實戰 - net.ipv4.conf.all.rp_filter

目錄 net.ipv4.conf.all.rp_filter 參數詳解一、參數基本概念二、參數取值及含義三、反向路徑過濾的工作原理四、配置示例與注意事項五、與其他參數的關聯六、總結 net.ipv4.conf.all.rp_filter 參數詳解 一、參數基本概念 net.ipv4.conf.all.rp_filter 是 Linux 內核中用于控…

ElementUI el-select多選下拉框,回顯數據后無法重新選擇和修改

問題 ElementUI el-select多選下拉框&#xff0c;回顯數據后無法重新選擇和修改&#xff0c;點擊選擇和刪除都沒有反應&#xff0c;頁面也沒有報錯 方案一 網上搜出來的基本上都是這個解決辦法&#xff0c;但是我設置后沒有生效&#xff0c;還是無法選擇和修改 原因 下拉框數…

計算機視覺的新浪潮:擴散模型(Diffusion Models)技術剖析與應用前景

近年來&#xff0c;擴散模型&#xff08;Diffusion Models, DMs&#xff09;迅速崛起&#xff0c;成為計算機視覺領域最令人矚目的生成模型之一。從生成高質量圖像到風格遷移、圖像修復&#xff0c;再到文本驅動圖像生成&#xff08;如 DALLE 2、Stable Diffusion、Midjourney&…

「Java流程控制」跳轉語句

今天來聊聊Java里的兩個重要跳轉語句——break和continue。它們就像馬路上的交通信號燈,能夠控制程序執行的流向。 break和continue break和continue在循環中的作用,特別像快遞分揀中心的工作場景: break:就像發現一個破損包裹,直接停止當前分揀流程,把它扔進異常品處理…

R1-Searcher使用強化學習增強語言模型解決問題的搜索能力

R1-Searcher&#xff1a;Incentivizing the Search Capability in LLMs via Reinforcement Learning 2025.3 https://github.com/RUCAIBox/R1-Searcher 針對的問題&#xff1a; 現有大型推理模型在時間敏感或知識密集型問題上通常僅使用模型內部知識&#xff0c;導致回答不準…