隊列,環形緩沖區實現與應用:適用于GD32串口編程或嵌入式底層驅動開發

環形緩沖區實現與應用:從基礎到實踐

在嵌入式系統和實時數據處理場景中,環形緩沖區(Circular Buffer)是一種非常常用的的數據結構,它能有效地管理數據的讀寫操作,尤其適用于數據流的臨時存儲與轉發。

今天,我們就來深入探討如何實現一個簡單高效的環形緩沖區,并將其應用到模擬的 UART 通信場景中。

這篇文章將帶您從零開始構建一個實用的環形緩沖區,并展示其在數據傳輸中的應用。環形緩沖區基本原理環形緩沖區是一種固定大小的數組結構,通過兩個指針(讀指針和寫指針)來追蹤數據的讀寫位置。當緩沖區的空間被占滿時,根據不同的模式可選擇覆蓋舊數據或者阻塞寫入操作。這種數據結構的優勢在于無需頻繁的內存分配和釋放操作,能高效地利用有限的內存資源。

項目結構搭建
為了實現環形緩沖區,我們構建了一個簡單的項目結構:

project/├── src/│  ├── main.c              // 主程序│   └── ring_buffer.c       // 環形緩沖區實現        ├── include/│ └── ring_buffer.h       // 環形緩沖區頭文件└── Makefile                // 項目的Makefile

這種清晰的項目結構有助于我們更好地組織和管理代碼。

環形緩沖區實現頭文件
定義在ring_buffer.h中,我們首先定義了環形緩沖區的結構體、錯誤碼、寫入模式以及相關的函數聲明:

#ifndef RING_BUFFER_H
#define RING_BUFFER_H#include <stdint.h>// 環形緩沖區結構體typedef struct 
{    
uint8_t *buffer;    // 數據存儲的緩沖區    
uint32_t in_index;  // 寫入指針    
uint32_t out_index; // 讀取指針    
uint32_t length;    // 當前緩沖區中的元素個數    
ring_buffer_mode_t mode; // 緩沖區的寫入模式} 
ring_buffer_t;// 錯誤碼定義#define RINGBUFF_OK     0    // 成功
#define RINGBUFF_ERR    1    // 錯誤
#define RINGBUFF_EMPTY  2    // 緩沖區為空
#define RINGBUFF_FULL   3    // 緩沖區滿// 寫入模式枚舉typedef enum {    
RINGBUFF_OVERWRITE,    // 緩沖區滿時覆蓋最舊數據    
RINGBUFF_NO_OVERWRITE  // 緩沖區滿時返回錯誤
} ring_buffer_mode_t;// 函數聲明void ring_buffer_init(ring_buffer_t *buffer, uint8_t *data, ring_buffer_mode_t mode);uint8_t ring_buffer_write(ring_buffer_t *buffer, uint8_t data);uint8_t ring_buffer_read(ring_buffer_t *buffer);int read_data_to_array(ring_buffer_t *buffer, uint8_t *data, uint32_t data_len);#endif // RING_BUFFER_H

源文件實現在ring_buffer.c
我們實現了環形緩沖區的各項功能:

#include "ring_buffer.h"// 初始化環形緩沖區
void ring_buffer_init(ring_buffer_t *buffer, uint8_t *data, ring_buffer_mode_t mode) 
{    
buffer->buffer = data;    
buffer->in_index = 0;    
buffer->out_index = 0;    
buffer->length = 0;    
buffer->mode = mode;
}// 寫入數據到環形緩沖區uint8_t ring_buffer_write(ring_buffer_t *buffer, uint8_t data) 
{    
uint32_t next_in_index = (buffer->in_index + 1) % RINGBUFF_LEN;  // 使用數組的固定大小    
if (buffer->length == RINGBUFF_LEN) {        
if (buffer->mode == RINGBUFF_NO_OVERWRITE) {            return RINGBUFF_FULL;  // 緩沖區已滿,且不允許覆蓋        
} 
else 
{            
// 覆蓋最舊的數據            
buffer->out_index = (buffer->out_index + 1) % RINGBUFF_LEN;            
buffer->length--;        
}    
}    buffer->buffer[buffer->in_index] = data;    
buffer->in_index = next_in_index;    
buffer->length++;    
return RINGBUFF_OK;
}// 從環形緩沖區讀取數據
uint8_t ring_buffer_read(ring_buffer_t *buffer) 
{    
if (buffer->length == 0) 
{        
return '\0';  // 緩沖區為空,返回 '\0'    
}    uint8_t data = buffer->buffer[buffer->out_index];    
buffer->out_index = (buffer->out_index + 1) % RINGBUFF_LEN;    
buffer->length--;    
return data;
}// 從緩沖區讀取數據到數組int read_data_to_array(ring_buffer_t *buffer, uint8_t *data, uint32_t data_len) 
{    
uint32_t index = 0;    while (buffer->length > 0 && index < data_len) 
{        
uint8_t byte = ring_buffer_read(buffer);        if (byte != '\0') 
{            
data[index++] = byte;        
}    
}    
return index;  // 返回實際讀取的字節數}

主程序與模擬應用

main.c中,我們模擬了一個簡單的 UART 通信場景,展示如何使用環形緩沖區實現數據的接收和讀取:

#include "ring_buffer.h"
#include <stdio.h>#define RINGBUFF_LEN 128  // 固定緩沖區長度uint8_t uart_ring_buffer[RINGBUFF_LEN];
ring_buffer_t uart_buffer;// 模擬 UART 中斷接收函數,模擬數據寫入緩沖區void uart_interrupt_receive(uint8_t data) 
{    
ring_buffer_write(&uart_buffer, data);
}int main() 
{    
// 初始化環形緩沖區,使用覆蓋模式    
ring_buffer_init(&uart_buffer, uart_ring_buffer, RINGBUFF_OVERWRITE);    // 模擬 UART 中斷接收數據    
uart_interrupt_receive('A');    uart_interrupt_receive('B');    uart_interrupt_receive('C');    uart_interrupt_receive('D');    uart_interrupt_receive('E');    uart_interrupt_receive('F');    // 讀取數據并打印    
uint8_t data[10];    
int bytes_read = read_data_to_array(&uart_buffer, data, sizeof(data));    // 打印讀取的數據    
printf("Read %d bytes: ", bytes_read);    for (int i = 0; i < bytes_read; i++) 
{        
printf("%c ", data[i]);    
}    return 0;
}

Makefile 構建
為了方便編譯和構建項目,我們提供了簡單的Makefile

makefile
CC = gccCFLAGS = -Wall -Wextra -std=c99
SRC = src/main.c src/ring_buffer.c
OBJ = $(SRC:.c=.o)
EXEC = ring_buffer_demo
all: $(EXEC)$(EXEC): $(OBJ)    
$(CC) $(OBJ) -o $(EXEC)%.o: %.c    
$(CC) $(CFLAGS) -c $< -o 
$@clean:    rm -f $(OBJ) $(EXEC)

關鍵點總結

  1. 環形緩沖區:我們定義了一個基于固定大小數組的環形緩沖區結構體,通過in_indexout_index來追蹤寫入和讀取的位置。
  2. 中斷模擬:在uart_interrupt_receive函數中,我們模擬了 UART 中斷接收數據的過程,并將接收到的數據寫入環形緩沖區。
  3. 數據讀取:在主函數中,我們使用read_data_to_array函數將環形緩沖區中的數據讀取到普通數組中,并通過printf打印輸出結果。
  4. 擴展性:如果需要支持多線程場景,可以加入互斥鎖來確保緩沖區訪問的安全性。
  5. 優化建議:在高頻率中斷場景下,可以進一步優化數據結構和訪問模式以提高性能。總結通過這個簡單的環形緩沖區實現,我們了解了其基本原理和應用場景。

這個項目不僅適用于學習目的,還能作為實際項目中的基礎模塊進行擴展和優化。希望這篇文章能幫助您更好地理解和使用環形緩沖區技術。

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

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

相關文章

WHAT - Expo Go 和 development build

文章目錄 1. 什么是 Expo Go?簡介作用限制2. 什么是 Development Build(開發構建)?簡介功能創建方式3. 它們有什么區別?總結建議怎么從 Expo Go 遷移到開發構建一、什么是“遷移”?二、遷移步驟總覽三、詳細操作步驟1. 安裝 expo-dev-client2. 配置 eas.json(Expo 應用服…

Keepalived 配置 VIP 的核心步驟

Keepalived 配置 VIP 的核心步驟主要涉及安裝軟件、主備節點配置及服務管理。以下是具體操作指南: 一、安裝 Keepalived ?Ubuntu/Debian 系統? sudo apt update sudo apt install keepalived ?CentOS/RHEL 系統? sudo yum install keepalived 注:需確保已配置 EPE…

HarmonyOS 5折疊屏自適應廣告位布局方案詳解

以下是HarmonyOS 5折疊屏廣告位自適應布局的完整技術方案&#xff0c;綜合響應式設計、動態交互與元服務融合策略&#xff1a; 一、核心布局技術? ?斷點響應式設計? 基于屏幕寬度動態調整布局結構&#xff0c;避免簡單拉伸&#xff1a; // 定義斷點閾值&#xff08;單位&am…

【數據分析十:Classification prediction】分類預測

一、分類的定義 已知&#xff1a;一組數據&#xff08;訓練集&#xff09; (X, Y) 例如&#xff1a; x&#xff1a;數據特征/屬性&#xff08;如收入&#xff09; y&#xff1a;類別標記&#xff08;是否有借款&#xff09; 任務: 學習一個模型&#xff0c;利用每一條記錄…

設計模式-接口隔離原則(Interface Segregation Principle, ISP)

接口隔離原則&#xff08;Interface Segregation Principle, ISP&#xff09; 核心思想&#xff1a;客戶端不應被迫依賴它們不使用的接口方法。 目標&#xff1a;通過拆分臃腫的接口為更小、更具體的接口&#xff0c;減少不必要的依賴&#xff0c;提高系統的靈活性和可維護性。…

超融合:系統工程還是軟件工程? 從H3C UIS9.0看超融合的技術本質

在數字化轉型的浪潮中&#xff0c;超融合基礎架構&#xff08;Hyper-Converged Infrastructure, HCI&#xff09;憑借其簡化部署、彈性擴展和高效運維的優勢&#xff0c;成為企業IT基礎設施升級的重要選擇。 然而&#xff0c;關于超融合究竟屬于系統工程還是軟件工程的討論一直…

青少年編程與數學 01-012 通用應用軟件簡介 01 Microsoft Office辦公軟件

青少年編程與數學 01-012 通用應用軟件簡介 01 Microsoft Office辦公軟件 **一、Microsoft Office辦公軟件概述****二、發展過程**&#xff08;一&#xff09;早期起源&#xff08;二&#xff09;技術演進 **三、主要用途或功能**&#xff08;一&#xff09;文字處理&#xff0…

vivado IP綜合選項

在 Vivado 中&#xff0c;生成 IP 文件時的 Synthesis Options 提供了兩種主要的綜合模式&#xff1a;Global 和 Out of Context per IP。這兩種模式的主要區別如下&#xff1a; 1. Global Synthesis&#xff08;全局綜合&#xff09; 定義&#xff1a;在這種模式下&#xff…

零信任一招解決智慧校園的遠程訪問、數據防泄露、安全運維難題

隨著數字化轉型持續深入&#xff0c;“智慧校園”已成為高校發展的必經之路。從統一門戶、一卡通到教務系統、選課系統&#xff0c;各類應用極大地便利了師生的工作與學習。 然而&#xff0c;便捷的背后也隱藏著一系列安全挑戰。為了滿足師生校外訪問的需求&#xff0c;許多應…

web布局08

flex-basis 是 Flexbox 布局模塊中 flex 屬性的另一個子屬性&#xff0c;在前面的課程中我們深度剖析了瀏覽器是如何計算 Flex 項目尺寸的&#xff0c;或者說 Flexbox 是如何工作的。對于眾多 Web 開發者而言&#xff0c;在 CSS 中都習慣于使用像 width 、height 、min-* 和 ma…

在 Docker 27.3.1 中安裝 PostgreSQL 16 的實踐

前言&#xff1a;為什么在 Docker 中部署 PostgreSQL&#xff1f; 在云原生時代&#xff0c;容器化部署已成為生產環境的首選方案。通過 Docker 部署 PostgreSQL 具有以下顯著優勢&#xff1a; 環境一致性&#xff1a;消除“在我機器上能運行”的問題快速部署&#xff1a;秒級…

日志混亂與數據不一致問題實戰排查:工具協同調試記錄(含克魔使用點)

日志調試、狀態驗證和數據一致性排查&#xff0c;是iOS開發中最費時間、最易出錯的工作之一。尤其是在模塊之間異步通信頻繁、本地緩存與遠程狀態需保持同步時&#xff0c;如果缺乏一套合適的流程與工具&#xff0c;開發人員極容易陷入“盲查狀態”。 在一次跨部門聯合開發的A…

Redis底層數據結構與內部實現

目錄 一、RedisDB結構 1、RedisDB在Redis實例中的位置 2、RedisDB結構與核心組件 二、RedisObject結構 1、核心數據結構 1.1 簡單動態字符串 (Simple Dynamic String - SDS) 1.2 字典 (Dict / Hash Table) 1.3 雙端鏈表 (Linked List) 1.4 跳躍表 (Skip List) 1.5 壓…

【項目實訓】【項目博客#07】HarmonySmartCodingSystem系統前端開發技術詳解(5.12-6.15)

【項目實訓】【項目博客#07】HarmonySmartCodingSystem系統前端開發技術詳解&#xff08;5.12-6.15&#xff09; 一、項目概述與目標 HarmonySmartCodingSystem是一個面向HarmonyOS開發者的智能編碼輔助平臺&#xff0c;旨在通過自然語言交互簡化開發流程&#xff0c;提供智能…

系統性能優化-2 CPU

系統性能優化-2 CPU 其實除了 CPU 的頻率&#xff0c;多核架構以及多 CPU 架構對系統運行的性能也是很大影響的&#xff0c;那么該如何充分利用 CPU 呢&#xff1f; CPU 架構 首先介紹一下當前主流的 CPU 架構&#xff0c;現在的系統基本都是多 CPU&#xff0c;一個 CPU 處理…

Docker Pull 相關配置指南

在Docker環境中&#xff0c;docker pull命令用于從Docker鏡像倉庫拉取鏡像。為了確保Docker鏡像能夠快速、穩定地拉取&#xff0c;配置 docker pull相關的設置是非常重要的。本文將詳細介紹如何配置Docker以優化 docker pull操作&#xff0c;涵蓋鏡像源配置、登錄私有倉庫、網絡…

Python的Matplotlib庫:從入門到精通的數據可視化實戰指南

&#x1f49d;&#x1f49d;&#x1f49d;歡迎蒞臨我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 持續學習&#xff0c;不斷…

CentOS查日志

在 CentOS 系統中&#xff0c;查看日志是系統維護和故障排查的重要技能。以下是常用的日志查看方法和工具&#xff1a; 1. 基本日志位置 CentOS 使用systemd管理服務&#xff0c;主要日志存儲在&#xff1a; /var/log/messages&#xff1a;系統主日志/var/log/secure&#x…

Linux運維新人自用筆記(用虛擬機Ubuntu部署lamp環境,搭建WordPress博客)

內容全為個人理解和自查資料梳理&#xff0c;歡迎各位大神指點&#xff01; 每天學習較為零散。 day20 一、./configure 腳本命令 ./configure 是 Unix/Linux 系統中用于配置軟件源代碼的腳本命令&#xff0c;通常用于為后續的 make 和 make install 準備編譯環境。 選項作…

JetBrains 2025 全家桶 包含 IDEA、WebStorm、DataGrip、Pycharm、CLion、GoLand、PhpStorm

JetBrains 2025 全家桶 11合1 包含&#xff1a;IDEA、WebStorm、DataSpell、DataGrip、Pycharm、RustRover、CLion、Rider、PhpStorm、RubyMine、GoLand。 原文地址&#xff1a;JetBrains 2025 全家桶 11合1 含 IDEA、PyCharm、DataGrip、WebStrom、GoLand、CLion、PhpStorm、D…