驅動開發,隊列,環形緩沖區:以GD32 CAN 消息處理為例

對環形緩沖區進行進一步的優化和功能擴展,以應對更復雜的實際應用場景,特別是針對 CAN 總線消息處理的場景。

一、優化點

1:動態配置環形緩沖區大小在原始實現中,我們固定了緩沖區大小為 RINGBUFF_LEN = 64。這種方式雖然簡單,但在實際應用中缺乏靈活性。例如,在資源受限的嵌入式系統中,我們可能需要根據內存情況和數據流量動態調整緩沖區大小。

我們通過修改初始化函數,引入動態緩沖區容量配置:

void ring_buffer_init(can_ring_buffer_t *rb, can_receive_message_struct *buffer, uint32_t capacity, uint8_t mode) 
{    
rb->buffer = buffer;      
rb->in_index = 0;    
rb->out_index = 0;    
rb->length = 0;    
rb->capacity = capacity;  // 動態配置緩沖區大小    
rb->mode = mode;
}

在 main 函數中,我們可以通過調整傳入的 capacity 參數,輕松設置緩沖區大小:

can_receive_message_struct recv_buf[50]; can_ring_buffer_t can_ring_buffer;ring_buffer_init(&can_ring_buffer, recv_buf, 50, RING_BUFFER_MODE_NORMAL);

這種方式使緩沖區大小完全可控,能夠適應不同場景下的需求。
二、優化點

2:增強錯誤處理機制在實際系統運行中,緩沖區溢出或數據丟失是常見的問題。我們對寫入函數進行了改進,增加了對緩沖區狀態的詳細檢查和處理:

int ring_buffer_write(can_ring_buffer_t *rb, can_receive_message_struct *msg) 
{    
if (rb->length < rb->capacity) 
{        
rb->buffer[rb->in_index] = *msg;        
rb->in_index = (rb->in_index + 1) % rb->capacity;        
rb->length++;        
return 1;    
} 
else 
{        
if (rb->mode == RING_BUFFER_MODE_OVERWRITE) {            
rb->buffer[rb->in_index] = *msg;            
rb->in_index = (rb->in_index + 1) % rb->capacity;            
rb->out_index = (rb->out_index + 1) % rb->capacity;            
return 1;        
} 
else 
{            
return 0;  // 在正常模式下,丟棄數據        
}    
}}

在緩沖區滿的情況下,根據模式決定是否覆蓋舊數據。
我們還提供了狀態檢查函數:

int ring_buffer_is_empty(can_ring_buffer_t *rb) 
{    
return rb->length == 0;
}
int ring_buffer_is_full(can_ring_buffer_t *rb) 
{    
return rb->length == rb->capacity;
}

這些函數可以幫助開發者實時監控緩沖區狀態,及時發現潛在問題。

三、優化點
3:提供緩沖區狀態監控功能為了更好地理解緩沖區的使用情況,我們增加了緩沖區占用百分比計算功能:

float ring_buffer_occupancy(can_ring_buffer_t *rb) {    
return (float)rb->length / rb->capacity * 100.0f;
}

在 main 函數中,我們可以通過以下方式輸出緩沖區占用情況:

printf("Buffer occupancy: %.2f%%\n", ring_buffer_occupancy(&can_ring_buffer));

這個功能對于系統調優和資源分配具有重要意義。

四、優化點
4:改進消息處理流程我們完善了消息讀取和處理函數,使其能夠批量處理緩沖區中的消息:

int read_messages_from_buffer(can_ring_buffer_t *rb) 
{    
can_receive_message_struct msg;    
int read_count = 0;    
while (!ring_buffer_is_empty(rb)) 
{        
if (ring_buffer_read(rb, &msg)) 
{            
// 處理讀取到的 CAN 消息            
printf("Received CAN message:\n");            printf("SFID: 0x%X, EFID: 0x%X, FF: %d, FT: %d, DLEN: %d\n",                    msg.rx_sfid, msg.rx_efid, msg.rx_ff, msg.rx_ft, msg.rx_dlen);            
printf("Data: ");            
for (int i = 0; i < msg.rx_dlen; i++) 
{                
printf("%d ", msg.rx_data[i]);            
}            
printf("\n");            
read_count++;        
}    
}    
return read_count;
}

在 main 函數中調用:

int read_count = read_messages_from_buffer(&can_ring_buffer);
printf("Total messages read: %d\n", read_count);

這種批量處理方式提高了系統效率。

五、完整代碼實現
以下是優化后的完整代碼實現:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>  // 用于動態內存分配#define RING_BUFFER_MODE_OVERWRITE 1
#define RING_BUFFER_MODE_NORMAL 0// CAN接收消息結構體
typedef struct 
{    
uint32_t rx_sfid;   /*!< standard format frame identifier */    
uint32_t rx_efid;   /*!< extended format frame identifier */    
uint8_t rx_ff;      /*!< format of frame, standard or extended format */    
uint8_t rx_ft;      /*!< type of frame, data or remote */    
uint8_t rx_dlen;    /*!< data length */    
uint8_t rx_data[8]; /*!< receive data */    
uint8_t rx_fi;      /*!< filtering index */} 
can_receive_message_struct;// 環形緩沖區結構體
typedef struct 
{    
can_receive_message_struct *buffer;  // 指向緩沖區的指針    
uint32_t in_index;    
uint32_t out_index;    
uint32_t length;    
uint32_t capacity;    
uint8_t mode;
} can_ring_buffer_t;// 初始化環形緩沖區void ring_buffer_init(can_ring_buffer_t *rb, can_receive_message_struct *buffer, uint32_t capacity, uint8_t mode) 
{    
rb->buffer = buffer;      
rb->in_index = 0;    
rb->out_index = 0;    
rb->length = 0;    
rb->capacity = capacity;  // 動態配置緩沖區大小    
rb->mode = mode;
}// 寫入數據int ring_buffer_write(can_ring_buffer_t *rb, can_receive_message_struct *msg) 
{    
if (rb->length < rb->capacity) 
{        
rb->buffer[rb->in_index] = *msg;        
rb->in_index = (rb->in_index + 1) % rb->capacity;        
rb->length++;        
return 1;    
} 
else 
{        
if (rb->mode == RING_BUFFER_MODE_OVERWRITE) {            
rb->buffer[rb->in_index] = *msg;            
rb->in_index = (rb->in_index + 1) % rb->capacity;            
rb->out_index = (rb->out_index + 1) % rb->capacity;            
return 1;        
} 
else 
{            
return 0;  // 在正常模式下,丟棄數據        
}    
}
}// 讀取數據int ring_buffer_read(can_ring_buffer_t *rb, can_receive_message_struct *msg) 
{    
if (rb->length > 0) 
{        
*msg = rb->buffer[rb->out_index];        
rb->out_index = (rb->out_index + 1) % rb->capacity;        
rb->length--;        
return 1;    
} 
else 
{        
return 0;  // 如果沒有數據,返回0    
}
}// 檢查是否為空int ring_buffer_is_empty(can_ring_buffer_t *rb) 
{    
return rb->length == 0;
}// 檢查是否已滿int ring_buffer_is_full(can_ring_buffer_t *rb) {    
return rb->length == rb->capacity;}// 獲取緩沖區占用的百分比float ring_buffer_occupancy(can_ring_buffer_t *rb) {    
return (float)rb->length / rb->capacity * 100.0f;
}// 讀取并處理緩沖區中的消息int read_messages_from_buffer(can_ring_buffer_t *rb) 
{    
can_receive_message_struct msg;    
int read_count = 0;    while (!ring_buffer_is_empty(rb)) 
{        
if (ring_buffer_read(rb, &msg)) 
{            
// 處理讀取到的 CAN 消息            
printf("Received CAN message:\n");            
printf("SFID: 0x%X, EFID: 0x%X, FF: %d, FT: %d, DLEN: %d\n",                    msg.rx_sfid, msg.rx_efid, msg.rx_ff, msg.rx_ft, msg.rx_dlen);            
printf("Data: ");            for (int i = 0; i < msg.rx_dlen; i++) 
{                
printf("%d ", msg.rx_data[i]);            
}            
printf("\n");            
read_count++;        
}    
}    return read_count;}// 模擬接收CAN消息的中斷處理函數void CAN1_IRQHandler(can_ring_buffer_t *rb) {    
can_receive_message_struct temp;    // 模擬從硬件獲取 CAN 消息    
temp.rx_sfid = 0x123;    
temp.rx_efid = 0x1ABC;    
temp.rx_ff = 0;    
temp.rx_ft = 1;    
temp.rx_dlen = 8;    
for (int i = 0; i < 8; i++) 
{        
temp.rx_data[i] = i;    
}    
temp.rx_fi = 1;    
if (rb->length < rb->capacity) 
{        
ring_buffer_write(rb, &temp);    
} 
else 
{        
if (rb->mode == RING_BUFFER_MODE_OVERWRITE) {            
ring_buffer_write(rb, &temp);        
}    
}
}int main(void) 
{    
// 定義接收緩存數組,容量為50    
can_receive_message_struct recv_buf[50];     // 初始化環形緩沖區,設置容量為50,正常模式    
can_ring_buffer_t can_ring_buffer;    
ring_buffer_init(&can_ring_buffer, recv_buf, 50, RING_BUFFER_MODE_NORMAL);    // 模擬接收10條CAN消息    
for (int i = 0; i < 10; i++) 
{        
CAN1_IRQHandler(&can_ring_buffer);      
}    // 輸出緩沖區的占用情況    
printf("Buffer occupancy: %.2f%%\n", ring_buffer_occupancy(&can_ring_buffer));    // 讀取并處理緩沖區中的消息    
int read_count = read_messages_from_buffer(&can_ring_buffer);    
printf("Total messages read: %d\n", read_count);    return 0;}

六、未來擴展方向

  1. 支持多線程環境:在多線程系統中,我們可以在寫入和讀取操作時添加互斥鎖(mutex),防止數據競爭。例如:
// 在寫入函數中添加鎖保護
pthread_mutex_lock(&rb->mutex);// 寫入操作
pthread_mutex_unlock(&rb->mutex);
  1. 進一步優化消息處理:可以根據 CAN 消息的內容添加過濾和優先級處理。例如,對特定 ID 的消息進行優先處理。
  2. 錯誤日志和統計:可以添加日志記錄功能,記錄緩沖區溢出、數據丟失等事件,便于系統調試和優化。通過這些優化和擴展,我們的環形緩沖區實現變得更加健壯和實用,能夠更好地適應實際嵌入式系統中的 CAN 消息處理需求。

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

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

相關文章

SQL基礎知識,MySQL學習(長期更新)

1、基本操作&#xff0c;增刪查改 INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...); DELETE FROM 表名 WHERE 條件 SELECT * FROM 表名 WHERE 條件 UPDATE 表名 SET 字段1 值, 字段2 值, ... WHERE 條件; SELECT * INTO 新表 FROM 舊表 WHERE… INSERT INTO 語…

Git(一):初識Git

文章目錄 Git(一)&#xff1a;初識GitGit簡介核心功能分布式特性結構與操作優勢與適用場景 創建本地倉庫git init配置name與email--global 工作區、暫存區與版本庫git addgit commitcommit后.git的變化 Git(一)&#xff1a;初識Git Git簡介 Git 是一個分布式版本控制系統&…

第19天:初級數據庫學習筆記3

分組函數&#xff08;多行處理函數&#xff09; 即多個輸入對應一個輸出。前面講的數據處理函數是單行處理函數。&#xff08;在公司中常說單&#xff0c;多行處理函數&#xff09; 分組函數包括五個&#xff1a; max&#xff1a;最大值min&#xff1a;最小值avg&#xff1a…

Windows11下搭建Raspberry Pi Pico編譯環境

1. 系統與工具要求 PC平臺&#xff1a; Windows 11 專業版 Windows GCC: gcc-15.1.0-64.exe GNU Make: 4.3 Git: 2.49.0 cmake: 4.0.2 python:3.12.11 Arm GNU Toolchain Downloads – Arm Developer 2. 工具安裝與驗證 2.1 工具安裝 winget安裝依賴工具&#xff08;Windows …

【C語言極簡自學筆記】重講運算符

一、算術操作符 算術操作符描述把兩個操作數相加-第一個操作數減去第二個操作數*把兩個操作數相乘/分子除以分母%取模運算符&#xff0c;整除后的余數 注意&#xff1a;1.除號的兩端都是整數的時候執行的是整數的除法&#xff0c;兩端只要有一個浮點數&#xff0c;就執行浮點…

持續集成 CI/CD-Jenkins持續集成GitLab項目打包docker鏡像推送k8s集群并部署至rancher

Jenkins持續集成GitLab項目 GitLab提交分支后觸發Jenkis任務 之前是通過jar包在shell服務器上進行手動部署&#xff0c;麻煩且耗時。現通過Jenkins進行持續集成實現CI/CD。以test分支為例 提交即部署。 由于是根據自己實際使用過程 具體使用到了 gitlabjenkinsdockerharborra…

Apache Iceberg與Hive集成:非分區表篇

引言 在大數據處理領域&#xff0c;Apache Iceberg憑借其先進的表格式設計&#xff0c;為大規模數據分析帶來了新的可能。當Iceberg與Hive集成時&#xff0c;這種強強聯合為數據管理與分析流程提供了更高的靈活性和效率。本文將聚焦于Iceberg與Hive集成中的非分區表場景&#…

webpack 如何區分開發環境和生產環境

第一種方法: 方法出處&#xff1a;命令行接口&#xff08;CLI&#xff09; | webpack 中文文檔 1.利用webpack.config.js 返回的是個函數&#xff0c;利用函數的參數&#xff0c;來區分環境 具體步驟 1&#xff09; package.json文件&#xff1a;在npm scripts 命令后面追加 …

React組件通信——context(提供者/消費者)

Context 是 React 提供的一種組件間通信方式&#xff0c;主要用于解決跨層級組件 props 傳遞的問題。它允許數據在組件樹中"跨級"傳遞&#xff0c;無需顯式地通過每一層 props 向下傳遞。 一、Context 核心概念 1. 基本組成 React.createContext&#xff1a;創建 C…

“微信短劇小程序開發指南:從架構設計到上線“

1. 引言&#xff1a;短劇市場的機遇與挑戰 近年來&#xff0c;短視頻和微短劇市場呈現爆發式增長&#xff0c;用戶碎片化娛樂需求激增。短劇小程序憑借輕量化、社交傳播快、變現能力強等特點&#xff0c;成為內容創業的新風口。然而&#xff0c;開發一個穩定、流暢且具備商業價…

RPC與RESTful對比:兩種API設計風格的核心差異與實踐選擇

# RPC與RESTful對比&#xff1a;兩種API設計風格的核心差異與實踐選擇 ## 一、架構哲學與設計目標差異 1. **RPC&#xff08;Remote Procedure Call&#xff09;** - **核心思想**&#xff1a;將遠程服務調用偽裝成本地方法調用&#xff08;方法導向&#xff09; - 典型行為…

【pytest進階】pytest之鉤子函數

什么是 hook (鉤子)函數 經常會聽到鉤子函數(hook function)這個概念,最近在看目標檢測開源框架mmdetection,里面也出現大量Hook的編程方式,那到底什么是hook?hook的作用是什么? what is hook ?鉤子hook,顧名思義,可以理解是一個掛鉤,作用是有需要的時候掛一個東西…

深度學習計算——動手學深度學習5

環境&#xff1a;PyCharm python3.8 1. 層和塊 塊&#xff08;block&#xff09;可以描述 單個層、由多個層組成的組件或整個模型本身。 使用塊進行抽象的好處&#xff1a; 可將塊組合成更大的組件(這一過程通常是遞歸) 如 圖5.1.1所示。通過定義代碼來按需生成任意復雜度…

NodeJS的fs模塊的readFile和createReadStream區別以及常見方法

Node.js 本身沒有像 Java 那樣嚴格區分字符流和字節流&#xff0c;區別主要靠編碼&#xff08;encoding&#xff09;來控制數據是以 Buffer&#xff08;二進制字節&#xff09;形式還是字符串&#xff08;字符&#xff09;形式處理。 詳細解釋&#xff1a; 方面JavaNode.js字節…

基于二進制XOR運算的機器人運動軌跡與對稱圖像自動生成算法

原創&#xff1a;項道德&#xff08;daode3056,daode1212&#xff09; 新的算法出現&#xff0c;往往能給某些行業與產業帶來革命與突破。為探索機器人運動軌跡與對稱圖像自動生成算法&#xff0c;本人已經通過18種算法的測試&#xff0c;最終&#xff0c;以二進制的XOR運算為…

Spring AI 項目實戰(七):Spring Boot + Spring AI Tools + DeepSeek 智能工具平臺(附完整源碼)

系列文章 序號文章名稱1Spring AI 項目實戰(一):Spring AI 核心模塊入門2Spring AI 項目實戰(二):Spring Boot + AI + DeepSeek 深度實戰(附完整源碼)3Spring AI 項目實戰(三):Spring Boot + AI + DeepSeek 打造智能客服系統(附完整源碼)4Spring AI 項目實戰(四…

spring-webmvc @RequestHeader 典型用法

典型用法 基礎用法&#xff1a;獲取指定請求頭值 GetMapping("/info") public String getInfo(RequestHeader("User-Agent") String userAgent) {return "User-Agent: " userAgent; }如果請求中包含 User-Agent 請求頭&#xff0c;則其值將被…

Ubuntu:20.04中安裝docker

是的&#xff0c;您列出的命令是完整的安裝步驟&#xff0c;但為了確保100%可靠性和處理可能的問題&#xff0c;我建議進行以下優化和補充&#xff1a; 完整優化的安裝腳本&#xff08;包含錯誤處理和驗證&#xff09; #!/bin/bash# 1. 徹底清理舊版本和配置 sudo apt remove…

大數據實時風控引擎:Spark Streaming、Kafka、Flink與Doris的融合實踐

大數據實時風控引擎&#xff1a;Spark Streaming、Kafka、Flink與Doris的融合實踐 在數字金融、電商交易與在線服務的核心戰場&#xff0c;風險控制能力已成為業務的生命線。傳統批量風控模式在應對瞬息萬變的欺詐攻擊、信用風險時捉襟見肘。本文將深入探討如何利用**Spark St…

【創龍瑞芯微 RK3576 全國產 ARM 八核 2.2GHz 工業開發板-硬件說明書】

前 言 本文主要介紹TL3576-EVM評估板硬件接口資源以及設計注意事項等內容。 RK3576J/RK3576處理器的IO電平標準一般為1.8V、3.3V,上拉電源一般不超過3.3V或1.8V,當外接信號電平與IO電平不匹配時,中間需增加電平轉換芯片或信號隔離芯片。按鍵或接口需考慮ESD設計,ESD器件…