K1Guitar/project/src/usart.c

165 lines
3.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
#include "usart.h"
#define BUFF_SIZE 512
/* 纯比较宏:参数必须是普通局部变量(非 volatile
避免同一表达式多次访问 volatile 触发 Pa082 且逻辑不稳 */
#define IS_FULL(head, tail) ((((head) + 1) % BUFF_SIZE) == (tail))
#define IS_EMPTY(head, tail) ((head) == (tail))
/* ==================== 环形队列结构体 ==================== */
/* 一个串口实例的环形队列(收发各一) */
typedef struct
{
uint8_t rx_buff[BUFF_SIZE];
volatile uint16_t rx_head;
volatile uint16_t rx_tail;
uint8_t tx_buff[BUFF_SIZE];
volatile uint16_t tx_head;
volatile uint16_t tx_tail;
usart_type *usart; /* 关联的串口外设USART2 / UART4 */
} uart_ring_t;
/* USART2 和 UART4 各一个实例 */
static uart_ring_t uart2;
static uart_ring_t uart4;
/* 初始化:关联串口外设(由 wk_usart2_init / wk_uart4_init 调用) */
void uart_ring_usart2_init(void)
{
uart2.usart = USART2;
}
void uart_ring_uart4_init(void)
{
uart4.usart = UART4;
}
/* ==================== 通用入队/出队(带实例参数) ==================== */
/* 入队ISR 调用)。先快照 volatile 值再操作,避免 Pa082 */
static void ring_rx_push(uart_ring_t *rb, uint8_t c)
{
uint16_t h = rb->rx_head;
uint16_t t = rb->rx_tail;
if(IS_FULL(h, t)) return; /* 满则丢,防止覆盖未读数据 */
rb->rx_buff[h] = c;
rb->rx_head = (h + 1) % BUFF_SIZE;
}
/* 出队(业务线程调用) */
static uint8_t ring_rx_pop(uart_ring_t *rb, uint8_t *c)
{
uint16_t h = rb->rx_head;
uint16_t t = rb->rx_tail;
if(IS_EMPTY(h, t)) return 0;
*c = rb->rx_buff[t];
rb->rx_tail = (t + 1) % BUFF_SIZE;
return 1;
}
/* 写入 tx 队列(调用前应已关中断,防止 ISR 同时读) */
static void ring_tx_write(uart_ring_t *rb, uint8_t *data, uint16_t len)
{
uint16_t h = rb->tx_head;
uint16_t t = rb->tx_tail;
for(uint16_t i = 0; i < len; i++)
{
if(IS_FULL(h, t)) break; /* 用 tx 判满 */
rb->tx_buff[h] = data[i];
h = (h + 1) % BUFF_SIZE;
}
rb->tx_head = h; /* 最后一次性写回 volatile */
}
/* ==================== 发送接口(带串口参数) ==================== */
/* 通用发送:关中断 → 写队列 → 开 TDBE 中断触发发送 */
static void uart_ring_send(uart_ring_t *rb, uint8_t *data, uint16_t len)
{
rt_base_t level = rt_hw_interrupt_disable();
ring_tx_write(rb, data, len);
usart_interrupt_enable(rb->usart, USART_TDBE_INT, TRUE); /* 开发送中断 */
rt_hw_interrupt_enable(level);
}
/* USART2 发送对外midi_send.c 等在用) */
void USART2_SendData(uint8_t *data, uint16_t len)
{
uart_ring_send(&uart2, data, len);
}
/* UART4 发送(对外) */
void USART4_SendData(uint8_t *data, uint16_t len)
{
uart_ring_send(&uart4, data, len);
}
/* USART2 接收出队(对外) */
uint8_t USART2_RxPop(uint8_t *c)
{
return ring_rx_pop(&uart2, c);
}
/* UART4 接收出队(对外) */
uint8_t UART4_RxPop(uint8_t *c)
{
return ring_rx_pop(&uart4, c);
}
/* ==================== 串口中断 ==================== */
static void uart_ring_isr(uart_ring_t *rb)
{
/* 接收:收到字节 → 入 rx 队列 */
if(usart_flag_get(rb->usart, USART_RDBF_FLAG) == SET)
{
uint8_t data = usart_data_receive(rb->usart); /* 读数据(自动清 RDBF */
ring_rx_push(rb, data);
if(rb->usart == UART4)
{
rt_sem_release(UART4_sem);
}
}
/* 发送tx 队列有数据 → 发一个字节;发完 → 关 TDBE 中断 */
if(usart_flag_get(rb->usart, USART_TDBE_FLAG) == SET)
{
uint16_t h = rb->tx_head;
uint16_t t = rb->tx_tail;
if(!IS_EMPTY(h, t))
{
usart_data_transmit(rb->usart, rb->tx_buff[t]);
rb->tx_tail = (t + 1) % BUFF_SIZE;
}
else
{
usart_interrupt_enable(rb->usart, USART_TDBE_INT, FALSE); /* 发完关中断 */
}
}
/* 错误处理:清溢出标志,防止反复进中断卡死 */
if(usart_flag_get(rb->usart, USART_ROERR_FLAG) == SET)
usart_flag_clear(rb->usart, USART_ROERR_FLAG);
}
void USART2_IRQHandler(void)
{
rt_interrupt_enter();
uart_ring_isr(&uart2);
rt_interrupt_leave();
}
void UART4_IRQHandler(void)
{
rt_interrupt_enter();
uart_ring_isr(&uart4);
rt_interrupt_leave();
}