/** * @file usart0.cpp * @brief USART0 串口配置与 printf 重定向实现。 * @note 使用 TX 中断 + 环形缓冲替代逐字节忙等 TBE,降低 CPU 占用。 */ #include "main.h" #include "device/usart0.h" #include "sys/config.h" #define USARTx USART0 #define USART_TX_BUF_SIZE 256U namespace { uint8_t g_tx_buf[USART_TX_BUF_SIZE]; volatile uint16_t g_tx_head = 0U; volatile uint16_t g_tx_tail = 0U; inline uint16_t tx_buf_next(uint16_t idx) { return (idx + 1U) % USART_TX_BUF_SIZE; } inline bool tx_buf_full(void) { return tx_buf_next(g_tx_head) == g_tx_tail; } inline bool tx_buf_empty(void) { return g_tx_head == g_tx_tail; } } // namespace /** * @brief 重定向标准输出字符到 USART0。 * @param[in] ch 待输出的字符。 * @param[in] f 标准流指针;当前实现中未实际使用。 * @retval 返回已发送的字符值。 * @note 将字符写入环形发送缓冲,由 USART0 TXE 中断负责实际发送。 */ extern "C" int fputc(int ch, FILE *f) { (void)f; uint16_t next = tx_buf_next(g_tx_head); while(next == g_tx_tail) { /* 缓冲满,忙等一小段时间后重试; * 在 115200 波特率下通常不会发生 */ } g_tx_buf[g_tx_head] = static_cast(ch); g_tx_head = next; /* 启动 TXE 中断以触发实际硬件发送 */ usart_interrupt_enable(USARTx, USART_INT_TBE); return ch; } /** * @brief USART0 中断服务例程。 * @note 处理 TXE 发送缓冲区空中断,从环形缓冲取下一字节发送。 */ extern "C" void USART0_IRQHandler(void) { if(usart_interrupt_flag_get(USARTx, USART_INT_FLAG_TBE) != RESET) { if(!tx_buf_empty()) { usart_data_transmit(USARTx, g_tx_buf[g_tx_tail]); g_tx_tail = tx_buf_next(g_tx_tail); } /* 缓冲已空,关 TXE 中断,等下次 fputc 再开 */ if(tx_buf_empty()) { usart_interrupt_disable(USARTx, USART_INT_TBE); } } } /** * @brief 配置 USART0 相关 GPIO 引脚。 */ void usart0_gpio_config(void) { rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); } /** * @brief 配置并使能 USART0 外设。 * @note 当前使用 8N1 格式,115200 波特率,收发同时使能。 * 同步配置 NVIC 以便 TXE 中断驱动发送。 */ void usart0_config(void) { rcu_periph_clock_enable(RCU_USART0); usart_deinit(USARTx); usart_baudrate_set(USARTx, CONFIG_USART0_BAUDRATE); usart_word_length_set(USARTx, USART_WL_8BIT); usart_stop_bit_set(USARTx, USART_STB_1BIT); usart_parity_config(USARTx, USART_PM_NONE); usart_receive_config(USARTx, USART_RECEIVE_ENABLE); usart_transmit_config(USARTx, USART_TRANSMIT_ENABLE); usart_enable(USARTx); /* 使能 USART0 NVIC,用于 TXE 中断驱动发送 */ nvic_irq_enable(USART0_IRQn, 2U, 0U); }