【个人经验分享】环形缓冲区(Ring Buffer)全面解析

1. 什么是环形缓冲区

  • • 环形缓冲区(Ring Buffer),也称为循环缓冲区或环形队列,是一种固定大小的数据结构,它使用一个连续的内存区域并以循环方式操作读写指针当指针到达缓冲区末尾时会自动回绕到开头形成一个"环形"结构

1.1 工作原理

  • • 工作流程

  • • 读指针和写指针

    • • 在内存中实际开始位置;

    • • 在内存中实际结束位置,也可以用缓冲区长度代替;

    • • 存储在缓冲区中的有效数据的开始位置(读指针);

    • • 存储在缓冲区中的有效数据的结尾位置(写指针)。

1.2 环形缓冲区的关键特点

  • 固定大小:创建时指定容量,不会动态扩展。

  • FIFO(先进先出):数据的读取顺序与写入顺序一致。

  • 高效的内存利用:重复利用同一块内存空间。

  • 原子操作支持:适合在中断和主程序间共享数据。

  • 2. 环形缓冲区 与其他数据结构对比

    2.1 优劣对比

    特性 环形缓冲区 动态数组(如malloc) 链表
    内存使用 :white_check_mark: 固定,无碎片 :cross_mark: 动态分配,可能碎片化 :white_check_mark: 动态,但有指针开销
    性能 :white_check_mark: O(1)读写 :cross_mark: 插入删除可能O(n) :white_check_mark: O(1)插入删除
    线程安全 :white_check_mark: 易于实现(通过关中断) :cross_mark: 需要复杂锁机制 :cross_mark: 需要复杂锁机制
    缓存友好 :white_check_mark: 连续内存 :white_check_mark: 连续内存 :cross_mark: 非连续内存
    实时性 :white_check_mark: 确定性的时间复杂度 :cross_mark: 动态分配时间不确定 :white_check_mark: 确定性的操作时间
    内存开销 :white_check_mark: 极低(仅3个指针) :white_check_mark: 仅数据本身 :cross_mark: 每个节点有额外指针

2.2 环形缓冲区使用场景

  • 环形缓冲区最适合:

    • • 嵌入式系统中的中断服务程序(ISR)与主程序通信

    • • 实时数据流处理(如传感器数据、网络数据包)

    • • 音频/视频数据缓冲

    • • 生产者-消费者模式的实现

  • 不适合:

    • • 需要随机访问元素的场景

    • • 需要动态调整大小的场景

    • • 元素大小不一致的情况

3. 环形缓冲区的代码实现

3.1 数据结构设计

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. 1. 使用elem_size:支持任意类型的数据元素。

  2. 2. 维护count变量:快速判断空/满状态,无需复杂的指针计算。

  3. 3. self_allocated标志:区分静态和动态分配的内存。

3.2 关键函数实现

3.2.1 内存操作辅助函数

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实现类型无关的数据拷贝,支持任意数据类型。

3.2.2 压入环形缓冲区(缓冲区满不覆盖写入)

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;
}

3.2.3 覆盖写入模式

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;
}

3.2.4 弹出环形缓冲区的数据

/**
 * @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");
}

4.2 CAN接收数据处理

// 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;
    }
}

4.3 CAN 发送数据处理

// 发送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();
}

4.5 主函数

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;
                }
            }
        }
    }
}

好啦,那么本期的分享就到此结束啦~谢谢大家阅读

:grin: