diff --git a/Inc/uart_ring_buffer.h b/Inc/uart_ring_buffer.h index 65d2c8a..effeb35 100644 --- a/Inc/uart_ring_buffer.h +++ b/Inc/uart_ring_buffer.h @@ -1,14 +1,119 @@ +/** + * @file uart_ring_buffer.h + * @brief 简单高效的环形接收缓冲区(字节队列)接口声明。 + * @details 提供字节写入/读取、可读长度查询、清空与丢弃统计等 API, + * 适用于中断接收(写)与主循环解析(读)的典型嵌入式串口场景。 + */ #ifndef UART_RING_BUFFER_H #define UART_RING_BUFFER_H #include #include -#define UART_RX_BUFFER_SIZE 128 +/** + * @def UART_RX_BUFFER_SIZE + * @brief 接收环形缓冲区容量(单位:字节)。 + * @note 采用“预留一格”区分空/满策略,最大可用容量为 UART_RX_BUFFER_SIZE-1。 + */ +#define UART_RX_BUFFER_SIZE 64 + +/** + * @defgroup RingBuffer 环形缓冲区 + * @brief 字节环形缓冲区(接收端) + * @{ + */ + +/** + * @section RingBuffer_Usage 使用说明 + * 典型用法:中断接收(写入环形缓冲)、主循环解析(读取环形缓冲)。 + * + * 1) 初始化 + * @code{.c} + * uart_ring_buffer_init(); + * @endcode + * + * 2) 使能串口接收非空中断(RBNE)并开启中断(以 USART0 为例) + * @code{.c} + * usart_interrupt_enable(USART0, USART_INT_RBNE); + * nvic_irq_enable(USART0_IRQn, 2, 0); // 根据工程需要设置优先级 + * @endcode + * + * 3) 在中断服务函数中写入环形缓冲(参考你当前工程的写法) + * @code{.c} + * void USART0_IRQHandler(void) { + * if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) { + * uint8_t data = usart_data_receive(USART0); + * (void)uart_ring_buffer_put(data); // 缓冲满时丢弃并计数 + * } + * } + * @endcode + * + * 4) 在主循环中读取处理 + * @code{.c} + * while (uart_ring_buffer_available() > 0) { + * int b = uart_ring_buffer_get(); + * if (b >= 0) { + * // 处理字节 b + * } + * } + * @endcode + * + * @note 缓冲区满时新字节会被丢弃,可用 uart_ring_buffer_drop_count() 查看累计丢弃数。 + * @note 采用“预留一格”区分空/满,最大可用容量为 UART_RX_BUFFER_SIZE-1。 + */ + +/** + * @brief 初始化环形缓冲区。 + * @details 复位读/写索引与丢弃计数,准备接收数据。 + * @note 若在中断环境使用,初始化前建议关闭相关接收中断以避免并发竞争。 + * @ingroup RingBuffer + */ void uart_ring_buffer_init(void); -uint16_t uart_rx_available(void); -int uart_rx_get(void); -void uart_rx_put(uint8_t data); -void uart_rx_clear(void); + +/** + * @brief 获取当前可读的字节数。 + * @details 返回范围为 [0, UART_RX_BUFFER_SIZE-1]。 + * @return 可读字节数(uint8_t)。 + * @note 预留一个空槽区分“空/满”,因此满时返回 UART_RX_BUFFER_SIZE-1。 + * @ingroup RingBuffer + */ +uint8_t uart_ring_buffer_available(void); + +/** + * @brief 从环形缓冲区读取一个字节。 + * @details 若缓冲区非空,返回队头字节并推进读指针;若为空,返回 -1。 + * @return 读取到的字节(0..255),或 -1 表示缓冲区为空。 + * @retval -1 缓冲区为空,无数据可读。 + * @ingroup RingBuffer + */ +int uart_ring_buffer_get(void); + +/** + * @brief 向环形缓冲区写入一个字节。 + * @param data 待写入的字节。 + * @return 是否写入成功。 + * @retval true 写入成功。 + * @retval false 写入失败(缓冲区已满,数据被丢弃并计数)。 + * @note 如需改为“覆盖写入”策略,可在满时先推进读指针再写入。 + * @ingroup RingBuffer + */ +bool uart_ring_buffer_put(uint8_t data); + +/** + * @brief 清空环形缓冲区。 + * @details 复位读/写索引与丢弃计数,相当于逻辑上丢弃所有已接收数据,不擦除数据区内容。 + * @ingroup RingBuffer + */ +void uart_ring_buffer_clear(void); + +/** + * @brief 获取因缓冲区满而被丢弃的字节累计数量。 + * @details 该计数在 init/clear 时清零。 + * @return 丢弃的累计字节数。 + * @ingroup RingBuffer + */ +uint32_t uart_ring_buffer_drop_count(void); + +/** @} */ #endif // UART_RING_BUFFER_H diff --git a/Src/uart_ring_buffer.c b/Src/uart_ring_buffer.c index 90f2f7f..73554f0 100644 --- a/Src/uart_ring_buffer.c +++ b/Src/uart_ring_buffer.c @@ -1,34 +1,104 @@ +/** + * @file uart_ring_buffer.c + * @brief 字节环形接收缓冲区的实现。 + * @details 适用于中断接收(写)与主循环解析(读)的典型串口场景; + * 采用“预留一格”区分空/满,最大可用容量为 UART_RX_BUFFER_SIZE-1。 + * @ingroup RingBuffer + */ #include "uart_ring_buffer.h" static volatile uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE]; -static volatile uint16_t uart_rx_write = 0; -static volatile uint16_t uart_rx_read = 0; +static volatile uint8_t write_index = 0; +static volatile uint8_t read_index = 0; +static volatile uint32_t dropped_bytes = 0; +/** + * @brief 重置环形缓冲区状态。 + * @details 将读指针、写指针与丢弃计数清零,不清空数据区内容。 + * @note 内部工具函数;对外请优先使用 uart_ring_buffer_init()/uart_ring_buffer_clear()。 + * @ingroup RingBuffer + */ +static void uart_ring_buffer_reset_state(void) { + write_index = 0; + read_index = 0; + dropped_bytes = 0; +} + +/** + * @brief 初始化环形缓冲区。 + * @details 调用内部重置逻辑,复位读写索引与丢弃计数,准备接收数据。 + * @note 若在中断环境使用,初始化前建议关闭相关接收中断以避免并发竞争。 + * @ingroup RingBuffer + */ void uart_ring_buffer_init(void) { - uart_rx_write = 0; - uart_rx_read = 0; + uart_ring_buffer_reset_state(); } -uint16_t uart_rx_available(void) { - return (uart_rx_write + UART_RX_BUFFER_SIZE - uart_rx_read) % UART_RX_BUFFER_SIZE; +/** + * @brief 获取当前可读的字节数。 + * @details 通过读/写指针的快照计算可读长度,范围为 [0, UART_RX_BUFFER_SIZE-1]。 + * @return uint8_t 可读字节数。 + * @note 预留一个空槽区分“空/满”,因此满时返回 UART_RX_BUFFER_SIZE-1。 + * @ingroup RingBuffer + */ +uint8_t uart_ring_buffer_available(void) { + /* 使用快照减少并发不一致窗口 */ + uint8_t w = write_index; + uint8_t r = read_index; + return (uint8_t)((w + UART_RX_BUFFER_SIZE - r) % UART_RX_BUFFER_SIZE); } -int uart_rx_get(void) { - if (uart_rx_read == uart_rx_write) return -1; // 空 - uint8_t data = uart_rx_buffer[uart_rx_read]; - uart_rx_read = (uart_rx_read + 1) % UART_RX_BUFFER_SIZE; +/** + * @brief 从环形缓冲区读取一个字节。 + * @details 若缓冲区非空,返回队头字节并推进读指针;若为空,返回 -1。 + * @return int 读取到的字节(0..255),或 -1 表示缓冲区为空。 + * @ingroup RingBuffer + */ +int uart_ring_buffer_get(void) { + if (read_index == write_index) return -1; // 空 + uint8_t data = uart_rx_buffer[read_index]; + read_index = (read_index + 1) % UART_RX_BUFFER_SIZE; return data; } -void uart_rx_put(uint8_t data) { - uint16_t next = (uart_rx_write + 1) % UART_RX_BUFFER_SIZE; - if (next != uart_rx_read) { // 缓冲区未满 - uart_rx_buffer[uart_rx_write] = data; - uart_rx_write = next; +/** + * @brief 向环形缓冲区写入一个字节。 + * @details 尝试写入一个新字节;若缓冲区已满则丢弃并计数。 + * @param data 待写入的字节。 + * @return bool 是否写入成功。 + * @retval true 写入成功。 + * @retval false 写入失败(缓冲区已满,数据被丢弃并计数)。 + * @note 如需“覆盖写入”策略,可在满时先推进读指针再写入。 + * @ingroup RingBuffer + */ +bool uart_ring_buffer_put(uint8_t data) { + uint8_t next = (write_index + 1) % UART_RX_BUFFER_SIZE; + if (next != read_index) { // 缓冲区未满 + uart_rx_buffer[write_index] = data; + write_index = next; + return true; + } else { + /* 缓冲区已满,丢弃新字节并计数 */ + dropped_bytes++; + return false; } } -void uart_rx_clear(void) { - uart_rx_write = 0; - uart_rx_read = 0; +/** + * @brief 清空环形缓冲区。 + * @details 复位读写索引与丢弃计数,相当于逻辑上丢弃所有已接收数据,不擦除数据区内容。 + * @ingroup RingBuffer + */ +void uart_ring_buffer_clear(void) { + uart_ring_buffer_reset_state(); +} + +/** + * @brief 获取因满而被丢弃的字节累计数量。 + * @details 写入时缓冲区满会丢弃新字节并累加计数;该计数在 init/clear 时清零。 + * @return uint32_t 丢弃的累计字节数。 + * @ingroup RingBuffer + */ +uint32_t uart_ring_buffer_drop_count(void) { + return dropped_bytes; }