STM32HAL 快速入門(二十):UART 中斷改進 —— 環形緩沖區解決數據丟失

前言

大家好,這里是 Hello_Embed。上一篇我們用中斷方式實現了 UART 收發,但發現一個關鍵問題:若 CPU 在處理其他任務時未及時重新使能接收中斷,新數據會覆蓋舊數據,導致丟失。本篇的核心改進方案是 ——“中斷接收 + 環形緩沖區”:中斷中實時將接收的數據存入緩沖區,主程序從緩沖區按需讀取,徹底解決 “接收不及時” 的痛點。下一篇我們將進一步學習更高效的 DMA 方式,現在先聚焦這個經典的中斷優化方案。

本篇筆記所提及的環形緩沖區相關知識可在同系列筆記14-15中找到

一、改進核心思路

要解決數據丟失,關鍵是讓 “接收” 和 “處理” 解耦 —— 接收端用中斷快速存數據,處理端(主程序)慢慢讀數據,無需同步等待。具體思路有兩點:

  1. 提前使能接收中斷:程序啟動時就開啟 UART 接收中斷,確保任何時候有數據都能被捕獲;
  2. 中斷中存環形緩沖區:每次接收中斷觸發時,立即將數據存入環形緩沖區,避免數據在寄存器中被覆蓋,主程序從緩沖區讀取數據時不影響接收。
二、代碼實現:從緩沖區定義到中斷處理

我們基于上一篇的工程修改,核心是在usart.c中集成環形緩沖區,實現 “中斷存數據、主程序讀數據” 的流程。

1. 準備工作:包含頭文件與定義核心變量

首先在usart.c的開頭包含環形緩沖區頭文件(需確保路徑正確),并定義接收相關的變量:

#include <circle_buffer.h>  // 包含環形緩沖區頭文件/* USER CODE BEGIN 1 */
// 1. 發送完成標志(沿用上篇)
static volatile int g_tx_cplt = 0;
// 2. 接收暫存變量:每次中斷接收1字節,先存在這里
static uint8_t g_RecvChar;
// 3. 環形緩沖區存儲數組:容量100字節,可存100個接收數據
static uint8_t g_RecvBuf[100];
// 4. 環形緩沖區結構體:管理讀寫指針和長度
static circle_buf g_uart1_rx_bufs;
/* USER CODE END 1 */
2. 步驟 1:初始化環形緩沖區 + 啟動接收中斷

定義StartUART1Recv函數,作用是初始化環形緩沖區提前使能接收中斷—— 程序啟動時調用一次,后續無需手動開啟中斷。

/* USER CODE BEGIN 1 */
// 啟動UART1接收:初始化緩沖區+使能接收中斷
void StartUART1Recv(void)
{// 初始化環形緩沖區:綁定結構體、容量100、存儲數組g_RecvBufcircle_buf_init(&g_uart1_rx_bufs, 100, g_RecvBuf);// 使能接收中斷:接收1字節到g_RecvChar,觸發中斷后進入回調函數HAL_UART_Receive_IT(&huart1, &g_RecvChar, 1);
}
/* USER CODE END 1 */
  • circle_buf_init參數說明:&g_uart1_rx_bufs(緩沖區結構體)、100(容量)、g_RecvBuf(存儲數組);
  • HAL_UART_Receive_IT:使能 RXNE 中斷(RDR 寄存器非空時觸發),接收的 1 字節暫存到g_RecvChar
3. 步驟 2:接收中斷回調 —— 數據存入緩沖區

重寫HAL_UART_RxCpltCallback(接收完成回調函數),核心邏輯是:將暫存的字節存入環形緩沖區,并重新使能接收中斷(確保下一個數據能被捕獲)。

/* USER CODE BEGIN 1 */
// 接收完成回調函數:中斷觸發后執行
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart1)  // 確認是USART1的中斷{// 1. 將接收的字節(g_RecvChar)寫入環形緩沖區circle_buf_write(&g_uart1_rx_bufs, g_RecvChar);// 2. 重新使能接收中斷:準備接收下一個字節(關鍵!避免中斷斷連)HAL_UART_Receive_IT(&huart1, &g_RecvChar, 1);}
}
/* USER CODE END 1 */
  • 為什么要 “重新使能中斷”?HAL_UART_Receive_IT是 “一次性” 的 —— 接收 1 字節后會自動關閉中斷,必須重新調用才能繼續接收下一字節。
4. 步驟 3:封裝緩沖區讀取函數

定義UART1GetChar函數,供主程序調用,從環形緩沖區讀取 1 字節數據(成功返回 0,失敗返回 - 1,對應緩沖區空)。

/* USER CODE BEGIN 1 */
// 從環形緩沖區讀取1字節數據
int UART1GetChar(uint8_t *pVal)
{// 調用環形緩沖區讀函數,將數據存入pVal指向的地址return circle_buf_read(&g_uart1_rx_bufs, pVal);
}
/* USER CODE END 1 */
  • pVal:主程序傳入的 “數據存儲地址”,讀取成功后,緩沖區的數據會存在這里;
  • 返回值:0 表示讀取成功(有數據),-1 表示緩沖區空(無數據)。
5. 沿用發送相關函數

若需要保留中斷發送功能,可沿用上篇的發送完成回調和等待函數(確保發送流程正常):

/* USER CODE BEGIN 1 */
// 發送完成回調函數(沿用)
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if (huart == &huart1)g_tx_cplt = 1;
}// 等待發送完成(沿用,主程序調用)
void Wait_Tx_Complete(void)
{while (g_tx_cplt == 0);  // 等待發送完成標志置位g_tx_cplt = 0;           // 復位標志
}
/* USER CODE END 1 */
三、主程序調用:實現 “接收 - 處理 - 返回” 完整流程

main.c中,先啟動接收中斷,再通過 “發送提示→讀取緩沖區→數據加 1 返回” 的邏輯,驗證改進方案是否有效。

1. 聲明外部函數

main.c/* USER CODE BEGIN PV */區域,聲明usart.c中定義的函數:

/* USER CODE BEGIN PV */
// 聲明外部函數:啟動接收中斷、等待發送完成、讀取緩沖區數據
extern void StartUART1Recv(void);
extern void Wait_Tx_Complete(void);
extern int UART1GetChar(uint8_t *pVal);
/* USER CODE END PV */
2. 主程序核心邏輯
/* USER CODE BEGIN 2 */
// 1. 啟動UART1接收:初始化緩沖區+使能中斷(程序啟動時執行一次)
StartUART1Recv();// 2. 定義發送的提示信息和接收變量
char *str1 = "Please enter a char : \r\n";
uint8_t c;  // 存儲從緩沖區讀取的字節
/* USER CODE END 2 *//* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{/* USER CODE BEGIN 3 */// 步驟1:發送提示信息(中斷方式)HAL_UART_Transmit_IT(&huart1, (uint8_t *)str1, strlen(str1));Wait_Tx_Complete();  // 等待發送完成// 步驟2:從環形緩沖區讀取1字節(循環等待,直到有數據)while (0 != UART1GetChar(&c));  // 返回0表示讀取成功,退出循環// 步驟3:數據加1后返回(查詢方式,簡單場景可用)c += 1;HAL_UART_Transmit(&huart1, &c, 1, 1000);    // 發送加1后的字符HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, 1000);  // 換行
}
/* USER CODE END 3 */
四、實驗驗證:數據丟失問題解決

燒錄程序后,用串口工具一次性發送 “12345”(模擬快速連續發送),結果如下:
請添加圖片描述

可以看到,單片機正確接收了所有字符,并返回 “23456”—— 證明環形緩沖區成功暫存了所有數據,即使主程序在處理發送,也不會丟失接收的數據。

五、核心流程梳理(為什么能解決丟失?)

整個改進方案的閉環流程如下,關鍵是 “接收” 和 “處理” 的解耦:

  1. 啟動階段StartUART1Recv初始化緩沖區→使能接收中斷;
  2. 接收階段:電腦發數據→RXNE 中斷觸發→HAL_UART_RxCpltCallback將數據存入緩沖區→重新使能中斷(準備下一次接收);
  3. 處理階段:主程序通過UART1GetChar從緩沖區讀數據→加 1 后返回→即使主程序耗時,緩沖區也會暫存新數據,不會被覆蓋。
結尾

“中斷 + 環形緩沖區” 是 UART 通信中解決數據丟失的經典方案,它兼顧了中斷的高效性和緩沖區的可靠性,適合中低速、數據量不大的場景。下一篇筆記,我們將學習更高級的 “DMA 方式”—— 讓 DMA 硬件替 CPU 完成 “數據搬運”,徹底解放 CPU,適合高速、大數據量的通信場景。
Hello_Embed 繼續帶你探索 UART 通信的高效實現方式,敬請期待~

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

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

相關文章

使用Docker搭建MaxKB智能體平臺

1、系統要求 詳見&#xff1a; https://maxkb.cn/docs/v2/quick_start https://maxkb.cn/docs/v2/installation/offline_installtion https://maxkb.cn/docs/v2/installation/online_installtion 2、安裝Docker 合集&#xff1a;Docker安裝與使用 3、安裝MaxKB 詳見&#xf…

寵物電商痛點破解:智能客服的關鍵作用

在寵物電商蓬勃發展的當下&#xff0c;行業面臨著諸多痛點。從客戶咨詢的高頻率到訂單處理的復雜性&#xff0c;每一個環節都可能成為制約發展的瓶頸。而智能客服的出現&#xff0c;為這些痛點提供了有效的解決方案&#xff0c;成為寵物電商行業不可或缺的助力。一、寵物電商的…

基于GraphRAG+Ollama驗證知識圖譜和檢索增強融合

之前介紹了知識圖譜與檢索增強的融合探索GraphRAG。 https://blog.csdn.net/liliang199/article/details/151189579 這里嘗試在CPU環境&#xff0c;基于GraphRAGOllama&#xff0c;驗證GraphRAG構建知識圖譜和檢索增強查詢過程。 1 環境安裝 1.1 GraphRAG安裝 在本地cpu環境…

36頁可編輯PPT | 某制造集團燈塔工廠解決方案

制造業企業訂單種類多&#xff0c;傳統產線換型慢&#xff0c;庫存高&#xff0c;財務壓力大。工人年齡大&#xff0c;招工難&#xff0c;工資漲&#xff0c;效率低。海外對手用低價和柔性產線搶單&#xff0c;國內同行用數字化縮短交期。企業想擴產&#xff0c;又怕投資重、回…

Redis 非緩存核心場景及實例說明

Redis 非緩存核心場景及實例說明 一、分布式鎖 分布式鎖用于解決分布式系統中多節點競爭同一資源的問題&#xff0c;確保操作原子性。Redis 實現分布式鎖的核心思路是利用鍵的唯一性和原子命令&#xff0c;通常基于 Redisson 框架簡化實現&#xff08;底層依賴 Redis 命令&…

【技術教程】如何將ONLYOFFICE文檔集成到使用Spring Boot框架編寫的Java Web應用程序中

在現代協作辦公環境中&#xff0c;將功能強大的文檔編輯器無縫集成到自有業務系統中&#xff0c;已成為提升工作效率和用戶體驗的關鍵需求。ONLYOFFICE 文檔服務器提供了一套成熟的在線文檔編輯解決方案&#xff0c;而 Java Spring Boot 則是構建高效、模塊化 Web 應用的熱門框…

openharmony之AV_CodeC音視頻編解碼模塊詳解(二)

1. 音頻解碼器函數調用流程 1.1 音頻解碼器架構概覽 decoder:解碼器 encoder:編碼器 前面文章介紹了關于openHarmony的AV_CodeC模塊,這篇文章將詳細講解編解碼時函數的調用流程 音頻解碼器采用插件化架構,核心實現位于: services/engine/codec/audio/decoder/audio_ffmpeg…

PDF24 Creator:免費的多功能PDF工具

在處理PDF文件時&#xff0c;一個功能強大且免費的PDF工具是許多用戶的首選。PDF24 Creator作為一款免費的PDF工具&#xff0c;提供了豐富的功能&#xff0c;幫助用戶創建、編輯和轉換PDF文件&#xff0c;滿足從初學者到專業用戶的各種需求。它不僅支持PDF與Word、Excel等15種以…

VBA 中使用 ADODB 操作 SQLite 插入中文亂碼問題

問題 使用 VBA 的 ADODB 對象的 command 對象、parameter 對象&#xff0c;插入的中文數據為亂碼 驅動下載、安裝、引用 驅動網址(下載路徑) 使用的 ODBC 驅動&#xff08;需要梯子才能下載&#xff0c;感謝大佬開源&#xff09; http://www.ch-werner.de/sqliteodbc/ 版本…

執行select * from a where rownum<1;,數據庫子進程崩潰,業務中斷。

文章目錄環境癥狀觸發條件解決方案環境 系統平臺&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;4.5.2 癥狀 執行select * from a where rownum<1;&#xff0c;數據庫子進程崩潰&#xff0c;業務中斷。 觸發條件 select 和 where條件帶有rownum…

python庫 Py2app 的詳細使用(將 Python 腳本變為 MacOS 獨立軟件包)

更多內容請見: python3案例和總結-專欄介紹和目錄 文章目錄 一、Py2app 概述 1.1 Py2app 介紹 1.2 安裝 1.3 替代工具推薦 二、基礎使用 2.1 最簡單的 setup.py 文件 2.2 完整示例 2.3 配置選項詳解 2.4 完整項目案例 2.5 打包為單文件應用(可選) 三、高級配置 3.1 處理特定…

NTP配置為客戶端廣播監聽模式

前言 項目需求&#xff1a; 使能ntp為客戶端模式&#xff0c;能監服務端廣播模式發出的ntp報文&#xff0c;計算出服務端的時間與客戶端的時間偏差并上報。 開發狀況&#xff1a; 交叉編譯ntp源碼&#xff0c;將修改后的ntpd進程部署到設備上作為客戶端完成項目需求 如何操作&a…

Claude-Flow 使用指南

Claude-Flow 不僅僅是一個工具&#xff0c;更是一個強大的AI驅動開發編排平臺。本問初步帶您深入了解 Claude-Flow v2.0.0 Alpha 的強大功能&#xff0c;助您在AI開發領域如虎添翼。1. 簡介&#xff1a;什么是 Claude-Flow&#xff1f; Claude-Flow v2 Alpha 是一個企業級的AI編…

系統梳理 Test-Time Compute 的主要實現路徑

編者按&#xff1a; AI 真的在“思考”嗎&#xff1f;當模型面對數學推理、代碼生成或復雜決策時&#xff0c;它是如何一步步推演出答案的&#xff1f;如果你曾困惑于大模型在關鍵任務中表現不穩定、缺乏可解釋性&#xff0c;甚至生成結果難以驗證&#xff0c;那么你并不孤單。…

vue 經常寫的echarts圖表模塊結構抽取

vue 經常寫的echarts圖表模塊結構抽取將項目中經常寫的結構抽取一下, 方便以后用 表頭包含標題和右側操作部分下面為圖表 <div class"chartBox"><div class"chartheadbox"><div class"chartheadleft">這是圖表標題</div>…

主流的開源協議(MIT,Apache,GPL v2/v3)

文章目錄1. MIT 協議 (MIT License)2. Apache 2.0 協議 (Apache License 2.0)3. GPL v2 協議 (GNU General Public License v2)“開源協議選擇指南”的流程圖 flowchart TDA[開始選擇開源協議] --> B{是否要求修改后必須開源?<br>(是否具有 傳染性?)};B -- 是&…

CameraService筆記

cameraservicecamera 結構圖1. 啟動CameraServer1.1 注冊media.camera服務1.2 構造CameraService1.3 CameraService::onFirstRef1.4 CameraService::enumerateProviders&#xff1a;前置準備知識1.4 CameraService::enumerateProviders&#xff1a;Provider和Device初始化1.4.1…

MacOS 15.6 編譯SDL3 Android平臺多架構so庫

成功編譯輸出: 編譯: Android平臺多架構編譯腳本: sdl3_android_build.sh #!/bin/bash# 設置變量 macos 其他系統需要更改路徑 SDL_SOURCE_DIR=$(pwd)/SDL BUILD_DIR=${SDL_SOURCE_DIR}/../sdl3_build_android NDK_PATH=$HOME/Library/Android/Sdk/Ndk/25.2.9519653 CMAKE…

Real-IAD D3: A Real-World 2D/Pseudo-3D/3D Dataset for Industrial Anomaly

Real-IAD D: A Real-World 2D/Pseudo-3D/3D Dataset for Industrial Anomaly Detection Paper Github 摘要 隨著工業異常檢測&#xff08;Industrial Anomaly Detection, IAD&#xff09;復雜程度的不斷提升&#xff0c;多模態檢測方法已成為機器視覺領域的研究焦點。然而&a…

IT需求提示未讀信息查詢:深度技術解析與性能優化指南【類似:釘釘已讀 功能】

IT需求提示未讀信息查詢&#xff1a;深度技術解析與性能優化指南【類似&#xff1a;釘釘已讀 功能】 DROP TABLE IF EXISTS rs_kpi_it_need_tip; CREATE TABLE IF NOT EXISTS rs_kpi_it_need_tip (id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵ID&#xff…