1. 什么是环形缓冲区
- • 环形缓冲区(Ring Buffer),也称为循环缓冲区或环形队列,是一种固定大小的数据结构,它使用一个连续的内存区域并以循环方式操作读写指针。当指针到达缓冲区末尾时,会自动回绕到开头,形成一个"环形"结构。
• 工作流程
• 读指针和写指针
• 在内存中实际开始位置;
• 在内存中实际结束位置,也可以用缓冲区长度代替;
• 存储在缓冲区中的有效数据的开始位置(读指针);
• 存储在缓冲区中的有效数据的结尾位置(写指针)。
• 固定大小:创建时指定容量,不会动态扩展。
• FIFO(先进先出):数据的读取顺序与写入顺序一致。
• 高效的内存利用:重复利用同一块内存空间。
• 原子操作支持:适合在中断和主程序间共享数据。
| 特性 | 环形缓冲区 | 动态数组(如malloc) | 链表 |
|---|---|---|---|
| 内存使用 | |||
| 性能 | |||
| 线程安全 | |||
| 缓存友好 | |||
| 实时性 | |||
| 内存开销 |
• 环形缓冲区最适合:
• 嵌入式系统中的中断服务程序(ISR)与主程序通信
• 实时数据流处理(如传感器数据、网络数据包)
• 音频/视频数据缓冲
• 生产者-消费者模式的实现
• 不适合:
• 需要随机访问元素的场景
• 需要动态调整大小的场景
• 元素大小不一致的情况
typedef struct {
uint8_t* buf; // 缓冲区存储指针
size_t capacity; // 缓冲区容量(元素个数)
size_t elem_size; // 每个元素的大小(字节)
size_t head; // 写指针(下一个写入位置)
size_t tail; // 读指针(下一个读取位置)
size_t count; // 当前元素数量
uint8_t self_allocated; // 内存分配标志
} RingBuffer_t;
1. 使用elem_size:支持任意类型的数据元素。
2. 维护count变量:快速判断空/满状态,无需复杂的指针计算。
3. self_allocated标志:区分静态和动态分配的内存。
static void write_at(RingBuffer_t* rb, size_t index, const void* item) {
memcpy(rb->buf + index * rb->elem_size, item, rb->elem_size);
}
static void read_at(const RingBuffer_t* rb, size_t index, void* out_item) {
memcpy(out_item, rb->buf + index * rb->elem_size, rb->elem_size);
}
memcpy实现类型无关的数据拷贝,支持任意数据类型。uint8_t RingBuffer_Push(RingBuffer_t* rb, const void* item) {
uint32_t pm = __get_PRIMASK(); // 保存中断状态
OS_DISABLE_IRQ(); // 关中断
if (rb->count == rb->capacity) {
OS_ENABLE_IRQ(); // 恢复中断
return 0; // 缓冲区满
}
write_at(rb, rb->head, item);
rb->head = (rb->head + 1) % rb->capacity; // 循环移动
rb->count++;
OS_ENABLE_IRQ(); // 恢复中断
return 1;
}
uint8_t RingBuffer_PushOverwrite(RingBuffer_t* rb, const void* item) {
if (rb->capacity == 0) return 0;
uint32_t pm = __get_PRIMASK();
OS_DISABLE_IRQ();
// 如果缓冲区满,丢弃最旧的数据
if (rb->count == rb->capacity) {
rb->tail = (rb->tail + 1) % rb->capacity;
rb->count--;
}
write_at(rb, rb->head, item);
rb->head = (rb->head + 1) % rb->capacity;
rb->count++;
OS_ENABLE_IRQ();
return 1;
}
/**
* @brief 从环形缓冲区弹出元素
*
* @param rb 环形缓冲区指针
* @param out_item 弹出的元素指针
* @return uint8_t 弹出成功返回1,失败返回0
*/
uint8_t RingBuffer_Pop(RingBuffer_t* rb, void* out_item) {
uint32_t pm = __get_PRIMASK();
OS_DISABLE_IRQ();
if (rb->count == 0) { OS_ENABLE_IRQ(); return 0; }
read_at(rb, rb->tail, out_item);
rb->tail = (rb->tail + 1) % rb->capacity;
rb->count--;
OS_ENABLE_IRQ();
return 1;
}
4. 使用示例:CAN通信系统
4.1 创建和初始化
1. 静态分配
#include "ring_buffer.h"
// 定义CAN消息结构
typedef struct {
uint32_t id;
uint8_t data[8];
uint8_t len;
uint32_t timestamp;
} CAN_Message;
// 定义缓冲区参数
#define CAN_RB_CAPACITY 32 // 最多存储32条CAN消息
// 创建环形缓冲区实例
RingBuffer_t can_rx_rb; // CAN接收缓冲区
RingBuffer_t can_tx_rb; // CAN发送缓冲区
// 静态分配存储空间
uint8_t can_rx_storage[CAN_RB_CAPACITY * sizeof(CAN_Message)];
uint8_t can_tx_storage[CAN_RB_CAPACITY * sizeof(CAN_Message)];
// 初始化函数
void CAN_RingBuffer_Init(void) {
// 初始化接收缓冲区
RingBuffer_Attach(&can_rx_rb,
can_rx_storage,
CAN_RB_CAPACITY,
sizeof(CAN_Message));
// 初始化发送缓冲区
RingBuffer_Attach(&can_tx_rb,
can_tx_storage,
CAN_RB_CAPACITY,
sizeof(CAN_Message));
printf("CAN环形缓冲区初始化完成,容量:%d条消息\r\n", CAN_RB_CAPACITY);
}
2. 动态分配
void CAN_RingBuffer_InitDynamic(void) {
// 动态分配接收缓冲区
if (!RingBuffer_InitDynamic(&can_rx_rb,
CAN_RB_CAPACITY,
sizeof(CAN_Message))) {
printf("接收缓冲区分配失败!\r\n");
return;
}
// 动态分配发送缓冲区
if (!RingBuffer_InitDynamic(&can_tx_rb,
CAN_RB_CAPACITY,
sizeof(CAN_Message))) {
printf("发送缓冲区分配失败!\r\n");
RingBuffer_Free(&can_rx_rb);
return;
}
printf("CAN环形缓冲区动态初始化完成\r\n");
}
// CAN接收中断回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
CAN_RxHeaderTypeDef rxHeader;
CAN_Message message;
// 清空消息结构
memset(&message, 0, sizeof(CAN_Message));
// 从CAN硬件读取消息
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, message.data) == HAL_OK) {
// 设置消息ID(标准帧或扩展帧)
if (rxHeader.IDE == CAN_ID_STD) {
message.id = rxHeader.StdId;
} else {
message.id = rxHeader.ExtId;
}
// 设置数据长度
message.len = rxHeader.DLC;
// 记录时间戳
message.timestamp = HAL_GetTick();
// 将消息推入接收缓冲区(使用覆盖模式,确保不丢失最新数据)
if (!RingBuffer_PushOverwrite(&can_rx_rb, &message)) {
// 理论上PushOverwrite永远不会失败(除非容量为0)
// 这里可以添加错误统计
static uint32_t error_count = 0;
error_count++;
}
// 可选:触发处理任务
// osSemaphoreRelease(can_rx_sem); // 如果使用RTOS
}
}
// 接收数据处理任务(在主循环或独立线程中调用)
void CAN_Receive_Process(void) {
CAN_Message rx_msg;
uint32_t processed_count = 0;
// 一次性处理所有待处理的消息
while (!RingBuffer_IsEmpty(&can_rx_rb)) {
if (RingBuffer_Pop(&can_rx_rb, &rx_msg)) {
// 处理接收到的CAN消息
Process_CAN_Message(&rx_msg);
processed_count++;
}
}
// 可选:打印处理统计
if (processed_count > 0) {
printf("处理了 %lu 条CAN消息\r\n", processed_count);
}
}
// 示例:处理CAN消息
void Process_CAN_Message(CAN_Message* msg) {
// 根据CAN ID进行不同的处理
switch (msg->id) {
case 0x100: // 电机状态
Parse_Motor_Status(msg->data, msg->len);
break;
case 0x200: // 传感器数据
Parse_Sensor_Data(msg->data, msg->len);
break;
case 0x300: // 系统状态
Parse_System_Status(msg->data, msg->len);
break;
default:
// 未知ID,可以选择记录或忽略
printf("未知CAN ID: 0x%03X\r\n", msg->id);
break;
}
}
// 发送CAN消息到缓冲区
uint8_t CAN_Send_Message(uint32_t id, uint8_t* data, uint8_t len) {
CAN_Message tx_msg;
// 参数检查
if (len > 8) {
printf("CAN数据长度超过8字节!\r\n");
return 0;
}
// 填充消息结构
tx_msg.id = id;
tx_msg.len = len;
memcpy(tx_msg.data, data, len);
tx_msg.timestamp = HAL_GetTick();
// 推入发送缓冲区
if (!RingBuffer_Push(&can_tx_rb, &tx_msg)) {
printf("CAN发送缓冲区已满,消息丢弃!\r\n");
return 0;
}
// 触发发送任务
Start_CAN_Transmit();
return 1;
}
// CAN发送任务
void CAN_Transmit_Process(void) {
CAN_Message tx_msg;
// 检查是否有待发送的消息
if (RingBuffer_IsEmpty(&can_tx_rb)) {
return; // 没有消息需要发送
}
// 检查CAN总线是否空闲
if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) == 0) {
return; // 发送邮箱已满,等待下一次调用
}
// 从缓冲区取出消息
if (RingBuffer_Pop(&can_tx_rb, &tx_msg)) {
CAN_TxHeaderTypeDef txHeader;
uint32_t mailbox;
// 配置发送头
if (tx_msg.id <= 0x7FF) {
txHeader.StdId = tx_msg.id;
txHeader.IDE = CAN_ID_STD;
} else {
txHeader.ExtId = tx_msg.id;
txHeader.IDE = CAN_ID_EXT;
}
txHeader.RTR = CAN_RTR_DATA;
txHeader.DLC = tx_msg.len;
txHeader.TransmitGlobalTime = DISABLE;
// 发送CAN消息
if (HAL_CAN_AddTxMessage(&hcan1, &txHeader, tx_msg.data, &mailbox) == HAL_OK) {
printf("CAN消息已发送: ID=0x%03X\r\n", tx_msg.id);
} else {
printf("CAN发送失败!将消息重新放回缓冲区\r\n");
// 发送失败,将消息重新放回缓冲区头部
RingBuffer_PushOverwrite(&can_tx_rb, &tx_msg);
}
}
}
// 启动CAN传输(在中断或主循环中调用)
void Start_CAN_Transmit(void) {
// 如果使用RTOS,可以释放信号量
// osSemaphoreRelease(can_tx_sem);
// 如果没有RTOS,直接调用处理函数
CAN_Transmit_Process();
}
int main(void) {
// 系统初始化
HAL_Init();
SystemClock_Config();
MX_CAN1_Init();
// 初始化CAN环形缓冲区
CAN_RingBuffer_Init();
// 启动CAN接收中断
HAL_CAN_Start(&hcan1);
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
printf("CAN环形缓冲区系统启动完成\r\n");
while (1) {
// 处理接收到的CAN消息
CAN_Receive_Process();
// 处理CAN发送
CAN_Transmit_Process();
// 定期监控状态
static uint32_t last_monitor_time = 0;
if (HAL_GetTick() - last_monitor_time > 1000) {
Monitor_RingBuffer_Status();
last_monitor_time = HAL_GetTick();
}
// 系统延时
HAL_Delay(10);
}
}
// 示例:发送周期性CAN消息
void Send_Periodic_CAN_Messages(void) {
static uint32_t last_send_time = 0;
if (HAL_GetTick() - last_send_time > 100) { // 每100ms发送一次
uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
// 发送心跳消息
CAN_Send_Message(0x100, data, 8);
last_send_time = HAL_GetTick();
}
}
5. 串口环形缓冲区示例(AT命令)
/**
* @file simple_uart_example.c
* @brief 简单的串口环形缓冲区示例
*
* 这个示例展示了如何使用环形缓冲区实现串口数据的接收和发送
* 适用于嵌入式系统,特别是STM32 HAL库
*/
#include <stdio.h>
#include <string.h>
#include "ring_buffer.h"
#include "main.h"
/* 宏定义 ----------------------------------------------------------*/
#define UART_RB_CAPACITY 256 // UART 环形缓冲区容量
#define UART_MAX_PACKET_SIZE 128 // 最大数据包大小
#define UART_TIMEOUT_MS 1000 // 串口超时时间(毫秒)
/* 全局变量 --------------------------------------------------------*/
// UART 接收环形缓冲区
static RingBuffer_t uart_rx_rb; // UART 接收环形缓冲区
static uint8_t uart_rx_storage[UART_RB_CAPACITY]; // UART 接收缓冲区存储数组
// UART 发送环形缓冲区
static RingBuffer_t uart_tx_rb; // UART 发送环形缓冲区
static uint8_t uart_tx_storage[UART_RB_CAPACITY]; // UART 发送缓冲区存储数组
// 接收字节缓存
static uint8_t rx_byte; // UART 接收字节缓存
// UART 句柄
extern UART_HandleTypeDef huart1; // 假设使用 USART1
/* 函数声明 --------------------------------------------------------*/
void UART_RingBuffer_Init(void);
void UART_Receive_Callback(UART_HandleTypeDef *huart);
void UART_Process_Received_Data(void);
void UART_Send_Byte(uint8_t byte);
void UART_Send_String(const char* str);
void UART_Send_Bytes(const uint8_t* data, uint16_t len);
void UART_Transmit_Process(void);
/**
* @brief UART 环形缓冲区初始化
*/
void UART_RingBuffer_Init(void) {
// 初始化接收环形缓冲区
RingBuffer_Attach(&uart_rx_rb,
uart_rx_storage,
UART_RB_CAPACITY,
sizeof(uint8_t));
// 初始化发送环形缓冲区
RingBuffer_Attach(&uart_tx_rb,
uart_tx_storage,
UART_RB_CAPACITY,
sizeof(uint8_t));
printf("UART环形缓冲区初始化完成\r\n");
printf("接收缓冲区容量: %d字节\r\n", UART_RB_CAPACITY);
printf("发送缓冲区容量: %d字节\r\n", UART_RB_CAPACITY);
// 启动UART接收中断
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
}
/**
* @brief UART 接收完成回调函数
* @param huart UART句柄指针
*
* 这个函数在HAL库的UART接收中断中调用
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 将接收到的字节推入环形缓冲区(覆盖模式,防止阻塞)
RingBuffer_PushOverwrite(&uart_rx_rb, &rx_byte);
// 重新启动接收中断
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
}
}
/**
* @brief 处理接收到的UART数据
*
* 这个函数应该在主循环中定期调用
*/
void UART_Process_Received_Data(void) {
uint8_t byte;
static uint8_t packet_buffer[UART_MAX_PACKET_SIZE];
static uint16_t packet_index = 0;
// 处理所有接收到的字节
while (!RingBuffer_IsEmpty(&uart_rx_rb)) {
if (RingBuffer_Pop(&uart_rx_rb, &byte)) {
// 示例1:直接回显到串口
// UART_Send_Byte(byte);
// 示例2:打印到终端
printf("%c", byte);
// 示例3:组装数据包(以回车符结束)
if (byte == '\r' || byte == '\n') {
// 收到完整的数据包
if (packet_index > 0) {
packet_buffer[packet_index] = '\0'; // 添加字符串结束符
printf("\r\n收到数据包: %s\r\n", packet_buffer);
packet_index = 0; // 重置索引
}
} else {
// 存储到数据包缓冲区
if (packet_index < UART_MAX_PACKET_SIZE - 1) {
packet_buffer[packet_index++] = byte;
} else {
// 缓冲区溢出,重置
printf("\r\n数据包过长,已丢弃\r\n");
packet_index = 0;
}
}
}
}
}
/**
* @brief 发送单个字节到UART(通过缓冲区)
* @param byte 要发送的字节
*/
void UART_Send_Byte(uint8_t byte) {
if (!RingBuffer_Push(&uart_tx_rb, &byte)) {
printf("UART发送缓冲区已满,字节丢弃: 0x%02X\r\n", byte);
} else {
// 触发发送处理
UART_Transmit_Process();
}
}
/**
* @brief 发送字符串到UART(通过缓冲区)
* @param str 要发送的字符串
*/
void UART_Send_String(const char* str) {
if (str == NULL) return;
size_t len = strlen(str);
for (size_t i = 0; i < len; i++) {
UART_Send_Byte(str[i]);
}
}
/**
* @brief 发送字节数组到UART(通过缓冲区)
* @param data 要发送的数据指针
* @param len 数据长度
*/
void UART_Send_Bytes(const uint8_t* data, uint16_t len) {
if (data == NULL || len == 0) return;
for (uint16_t i = 0; i < len; i++) {
UART_Send_Byte(data[i]);
}
}
/**
* @brief UART 发送处理函数
*
* 这个函数应该在主循环中定期调用
* 它会检查发送缓冲区并发送数据
*/
void UART_Transmit_Process(void) {
static uint8_t tx_buffer[64]; // 小批量发送缓冲区
static uint8_t tx_index = 0;
uint8_t byte;
// 如果UART忙,等待
if (huart1.gState != HAL_UART_STATE_READY) {
return;
}
// 尝试填充发送缓冲区
while (tx_index < sizeof(tx_buffer) && !RingBuffer_IsEmpty(&uart_tx_rb)) {
if (RingBuffer_Pop(&uart_tx_rb, &byte)) {
tx_buffer[tx_index++] = byte;
}
}
// 如果缓冲区有数据,发送
if (tx_index > 0) {
// 使用HAL库发送数据
HAL_StatusTypeDef status = HAL_UART_Transmit(&huart1, tx_buffer, tx_index, UART_TIMEOUT_MS);
if (status == HAL_OK) {
// 发送成功,重置索引
tx_index = 0;
} else if (status == HAL_TIMEOUT) {
// 发送超时,可能需要重新初始化UART
printf("UART发送超时\r\n");
tx_index = 0;
} else {
// 其他错误
printf("UART发送错误: %d\r\n", status);
tx_index = 0;
}
}
}
/**
* @brief 获取UART接收缓冲区状态
*/
void UART_Get_Status(void) {
size_t rx_size = RingBuffer_Size(&uart_rx_rb);
size_t tx_size = RingBuffer_Size(&uart_tx_rb);
size_t rx_capacity = RingBuffer_Capacity(&uart_rx_rb);
size_t tx_capacity = RingBuffer_Capacity(&uart_tx_rb);
printf("\r\n=== UART缓冲区状态 ===\r\n");
printf("接收缓冲区: %lu/%lu (%.1f%%)\r\n",
rx_size, rx_capacity,
(float)rx_size / rx_capacity * 100);
printf("发送缓冲区: %lu/%lu (%.1f%%)\r\n",
tx_size, tx_capacity,
(float)tx_size / tx_capacity * 100);
printf("接收缓冲区状态: %s\r\n",
RingBuffer_IsFull(&uart_rx_rb) ? "已满" :
RingBuffer_IsEmpty(&uart_rx_rb) ? "空" : "有数据");
printf("发送缓冲区状态: %s\r\n",
RingBuffer_IsFull(&uart_tx_rb) ? "已满" :
RingBuffer_IsEmpty(&uart_tx_rb) ? "空" : "有数据");
}
/**
* @brief 清空UART缓冲区
*/
void UART_Clear_Buffers(void) {
RingBuffer_Reset(&uart_rx_rb);
RingBuffer_Reset(&uart_tx_rb);
printf("UART缓冲区已清空\r\n");
}
/**
* @brief 简单的命令处理示例
* @param command 接收到的命令字符串
*/
void UART_Process_Command(const char* command) {
if (command == NULL) return;
printf("\r\n执行命令: %s\r\n", command);
// 示例命令处理
if (strcmp(command, "help") == 0 || strcmp(command, "?") == 0) {
UART_Send_String("\r\n=== 可用命令 ===\r\n");
UART_Send_String("status - 显示UART状态\r\n");
UART_Send_String("clear - 清空缓冲区\r\n");
UART_Send_String("echo on - 开启回显\r\n");
UART_Send_String("echo off - 关闭回显\r\n");
UART_Send_String("test - 发送测试数据\r\n");
UART_Send_String("help/? - 显示帮助\r\n");
}
else if (strcmp(command, "status") == 0) {
UART_Get_Status();
}
else if (strcmp(command, "clear") == 0) {
UART_Clear_Buffers();
}
else if (strcmp(command, "test") == 0) {
UART_Send_String("\r\n这是一条测试消息\r\n");
UART_Send_String("Hello, UART Ring Buffer!\r\n");
}
else if (strcmp(command, "echo on") == 0) {
// 这里可以实现回显开关逻辑
UART_Send_String("回显已开启\r\n");
}
else if (strcmp(command, "echo off") == 0) {
UART_Send_String("回显已关闭\r\n");
}
else {
UART_Send_String("未知命令,输入 'help' 查看可用命令\r\n");
}
}
/**
* @brief 主函数
*/
int main(void) {
// HAL库初始化
HAL_Init();
SystemClock_Config();
// 串口初始化
MX_USART1_UART_Init();
// 初始化UART环形缓冲区
UART_RingBuffer_Init();
printf("\r\n=== UART环形缓冲区示例程序 ===\r\n");
printf("系统启动完成\r\n");
printf("输入 'help' 查看可用命令\r\n");
printf("等待接收数据...\r\n");
// 变量声明
static char command_buffer[64];
static uint8_t command_index = 0;
static uint32_t last_status_time = 0;
uint8_t byte;
while (1) {
// 处理接收到的UART数据
while (!RingBuffer_IsEmpty(&uart_rx_rb)) {
if (RingBuffer_Pop(&uart_rx_rb, &byte)) {
// 打印接收到的字符(回显)
printf("%c", byte);
// 处理命令输入(以回车结束)
if (byte == '\r' || byte == '\n') {
if (command_index > 0) {
command_buffer[command_index] = '\0';
UART_Process_Command(command_buffer);
command_index = 0;
}
} else if (byte == 0x08 || byte == 0x7F) { // 退格键
if (command_index > 0) {
command_index--;
UART_Send_String("\b \b"); // 擦除上一个字符
}
} else {
// 普通字符,添加到命令缓冲区
if (command_index < sizeof(command_buffer) - 1) {
command_buffer[command_index++] = byte;
} else {
UART_Send_String("\r\n命令过长\r\n");
command_index = 0;
}
}
}
}
// 处理UART发送
UART_Transmit_Process();
// 定期显示状态(每5秒)
if (HAL_GetTick() - last_status_time > 5000) {
// UART_Get_Status(); // 可以取消注释启用状态显示
last_status_time = HAL_GetTick();
}
// 系统延时
HAL_Delay(10);
}
}
/**
* @brief UART错误回调函数
* @param huart UART句柄指针
*/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
printf("\r\nUART通信错误!\r\n");
// 重新初始化UART
HAL_UART_DeInit(&huart1);
MX_USART1_UART_Init();
// 重新启动接收中断
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
printf("UART已重新初始化\r\n");
}
}
/* 辅助函数 --------------------------------------------------------*/
/**
* @brief 简单的AT命令处理示例
* @param data 接收到的数据
* @param len 数据长度
*
* 这个函数模拟处理AT命令,可以集成到原有的AT_Input函数中
*/
void AT_Command_Handler(const uint8_t* data, uint16_t len) {
if (len < 2) return; // AT命令至少需要"AT"两个字符
// 检查是否是AT命令
if (data[0] == 'A' && data[1] == 'T') {
printf("\r\n收到AT命令: ");
for (uint16_t i = 0; i < len; i++) {
printf("%c", data[i]);
}
printf("\r\n");
// 模拟AT命令响应
if (len == 2) {
UART_Send_String("\r\nOK\r\n");
}
else if (memcmp(data, "AT+TEST", 7) == 0) {
UART_Send_String("\r\n+TEST: Ring Buffer Example\r\nOK\r\n");
}
else if (memcmp(data, "AT+VERSION", 10) == 0) {
UART_Send_String("\r\n+VERSION: 1.0.0\r\nOK\r\n");
}
else {
UART_Send_String("\r\nERROR\r\n");
}
}
}
/**
* @brief 数据包解析示例
*
* 这个函数展示了如何从环形缓冲区中提取完整的数据包
*/
void UART_Packet_Parser(void) {
static uint8_t packet[128];
static uint16_t packet_len = 0;
uint8_t byte;
while (!RingBuffer_IsEmpty(&uart_rx_rb)) {
if (RingBuffer_Pop(&uart_rx_rb, &byte)) {
// 简单的数据包协议: 以0x7E开始, 0x7E结束
if (byte == 0x7E) {
if (packet_len > 0) {
// 收到结束符,处理完整的数据包
printf("\r\n收到数据包,长度: %d\r\n", packet_len);
// 这里可以添加数据包处理逻辑
// 例如: Process_Packet(packet, packet_len);
packet_len = 0; // 重置
}
// 开始新的数据包
packet[packet_len++] = byte;
}
else if (packet_len > 0) {
// 存储数据包内容
if (packet_len < sizeof(packet)) {
packet[packet_len++] = byte;
} else {
// 数据包过长,重置
printf("\r\n数据包过长,已丢弃\r\n");
packet_len = 0;
}
}
}
}
}
好啦,那么本期的分享就到此结束啦~谢谢大家阅读
![]()