驱动开发,队列,环形缓冲区:以GD32 CAN 消息处理为例

对环形缓冲区进行进一步的优化和功能扩展,以应对更复杂的实际应用场景,特别是针对 CAN 总线消息处理的场景。

一、优化点

1:动态配置环形缓冲区大小在原始实现中,我们固定了缓冲区大小为 RINGBUFF_LEN = 64。这种方式虽然简单,但在实际应用中缺乏灵活性。例如,在资源受限的嵌入式系统中,我们可能需要根据内存情况和数据流量动态调整缓冲区大小。

我们通过修改初始化函数,引入动态缓冲区容量配置:

c 复制代码
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 参数,轻松设置缓冲区大小:

c 复制代码
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:增强错误处理机制在实际系统运行中,缓冲区溢出或数据丢失是常见的问题。我们对写入函数进行了改进,增加了对缓冲区状态的详细检查和处理:

c 复制代码
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;  // 在正常模式下,丢弃数据        
}    
}}

在缓冲区满的情况下,根据模式决定是否覆盖旧数据。

我们还提供了状态检查函数:

c 复制代码
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:提供缓冲区状态监控功能为了更好地理解缓冲区的使用情况,我们增加了缓冲区占用百分比计算功能:

c 复制代码
float ring_buffer_occupancy(can_ring_buffer_t *rb) {    
return (float)rb->length / rb->capacity * 100.0f;
}

在 main 函数中,我们可以通过以下方式输出缓冲区占用情况:

c 复制代码
printf("Buffer occupancy: %.2f%%\n", ring_buffer_occupancy(&can_ring_buffer));

这个功能对于系统调优和资源分配具有重要意义。

四、优化点

4:改进消息处理流程我们完善了消息读取和处理函数,使其能够批量处理缓冲区中的消息:

c 复制代码
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 函数中调用:

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

这种批量处理方式提高了系统效率。

五、完整代码实现

以下是优化后的完整代码实现:

c 复制代码
#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),防止数据竞争。例如:
c 复制代码
// 在写入函数中添加锁保护
pthread_mutex_lock(&rb->mutex);// 写入操作
pthread_mutex_unlock(&rb->mutex);
  1. 进一步优化消息处理:可以根据 CAN 消息的内容添加过滤和优先级处理。例如,对特定 ID 的消息进行优先处理。
  2. 错误日志和统计:可以添加日志记录功能,记录缓冲区溢出、数据丢失等事件,便于系统调试和优化。通过这些优化和扩展,我们的环形缓冲区实现变得更加健壮和实用,能够更好地适应实际嵌入式系统中的 CAN 消息处理需求。
相关推荐
吟安安安安2 分钟前
适合短期冲刺的学习工作流(针对算法)
学习·算法
科研前沿7 分钟前
什么是时空融合技术?
大数据·人工智能·数码相机·算法·重构·空间计算
weixin_4217252611 分钟前
C语言常用字符串函数:长度、比较、拼接和查找
c语言·字符串函数·查找·比较·长度
AI科技星12 分钟前
全域数学本源公理:0、1、∞ 三者核心关系 (典籍定稿版)
人工智能·算法·数学建模·数据挖掘·量子计算
AI科技星17 分钟前
全域数学·第卷:场计算机卷(场空间计算机)【乖乖数学】
java·开发语言·人工智能·算法·机器学习·数学建模·数据挖掘
Deepoch19 分钟前
数学模型驱动:Deepoc 低幻觉数学大模型助力发动机全周期智能优化
人工智能·算法·机器学习·deepoc·数学大模型·低幻觉
charlie11451419124 分钟前
嵌入式C++实践开发第21篇(单片机实践):按钮输入 —— 硬件原理、消抖与HAL API
开发语言·c++·单片机
嘻嘻哈哈樱桃28 分钟前
牛客经典101题解题集--贪心算法+模拟
java·python·算法·贪心算法
AKDreamer_HeXY28 分钟前
QOJ 12255 - 36 Puzzle 题解
数据结构·c++·数学·算法·icpc·qoj
余生皆假期-35 分钟前
YuanHub 源码分析【一】FlashDB 初始化与项目应用
笔记·单片机·嵌入式硬件