第 2 篇:UART——串口的坑比你想象的多
1. 物理层:TTL、RS232、RS485 的区别
| TTL | 0=0V, 1=3.3V | <1m | 1对1 |
| RS232 | -12V/+12V | <15m | 1对1 |
| RS485 | 差分 ±2V | <1200m | 最多 256 个 |
2. GD32 UART + DMA + 空闲中断
void uart_dma_init(void) {
rcu_periph_clock_enable(RCU_USART0);
rcu_periph_clock_enable(RCU_DMA0);
// UART 配置 115200-8-N-1
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200);
usart_word_length_set(USART0, USART_WL_8BIT);
usart_stop_bit_set(USART0, USART_STB_1BIT);
usart_parity_config(USART0, USART_PM_NONE);
// DMA 接收(循环模式)
dma_parameter_struct dma_init_struct;
dma_deinit(DMA0, DMA_CH4);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.periph_addr = (uint32_t)&USART_RDATA(USART0);
dma_init_struct.memory_addr = (uint32_t)rx_dma_buf;
dma_init_struct.number = RX_BUF_SIZE;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init(DMA0, DMA_CH4, &dma_init_struct);
dma_circulation_enable(DMA0, DMA_CH4); // 循环接收
usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
usart_interrupt_enable(USART0, USART_INT_IDLE); // 空闲中断
usart_enable(USART0);
}
3. 环形缓冲区 + 空闲中断断帧
void USART0_IRQHandler(void) {
if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
usart_data_receive(USART0); // 清除 IDLE 标志
uint16_t len = RX_BUF_SIZE – dma_transfer_number_get(DMA0, DMA_CH4);
ringbuf_write(&rx_ring, rx_dma_buf, len);
// 通知解析任务
xSemaphoreGiveFromISR(xRXSemaphore, &woken);
}
}
空闲中断是 UART 断帧的最优雅方案——不需要帧头帧尾,不需要固定长度,一帧结束后自动触发。
下一篇:UART 协议设计——定义你自己的通讯协议
网硕互联帮助中心

评论前必须登录!
注册