| 
 
| 采用GD32F103C8T6开发板实现了串口1和串口3的DMA空闲中断通信,在串口1上还添加了SP485,实现了485方向控制, 
 串口1的针脚为PA9和PA10
 
 串口3的针脚为PB10和PB11,
 
 由于在串口1添加了485模块,所以必须控制数据收发的方向控制,只有485模块的DE和RE为低电平时才能接收,高电平时才能发送,方向控制的针脚为PA8,实现代码如下:
 
 /*
 USART0
 PA9:TX  发送
 PA10:RX 接收
 DMA_CH4为接收
 DMA_CH3为发送
 */
 
 #include <string.h>
 #include "gd32f10x.h"
 #include "systick.h"
 #include "usart0_rs485.h"
 
 uint8_t usart0_rx_buf[256];
 uint8_t usart0_tx_buf[256];
 volatile static uint8_t usart0_tx_busy = 0; //发送状态
 volatile uint8_t usart0_rx_flag = 0; //接收状态
 volatile uint16_t usart0_rx_len = 0; //接收长度
 
 //若串口0添加了485,则需要配置485方向控制使能
 #define rs485_rx_en GPIO_BC(GPIOA)=GPIO_PIN_8;
 #define rs485_tx_en GPIO_BOP(GPIOA)=GPIO_PIN_8;
 
 void USART0_nvic_config(void)
 {
 /* 设置优先级组 */
 nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
 
 //USART0 DMA0发送中断
 nvic_irq_enable(DMA0_Channel3_IRQn, 1, 0);
 
 //USART0 DMA0接收中断
 nvic_irq_enable(DMA0_Channel4_IRQn, 1, 0);
 
 //USART0 串口中断
 nvic_irq_enable(USART0_IRQn, 0, 0);
 }
 
 void USART0_rcu_config()
 {
 rcu_periph_clock_enable(RCU_DMA0);
 
 /* enable GPIO clock */
 rcu_periph_clock_enable(RCU_GPIOA);
 
 /* enable USART clock */
 rcu_periph_clock_enable(RCU_USART0);
 
 rcu_periph_clock_enable(RCU_AF);
 }
 
 void USART0_dma_recv_config()
 {
 dma_parameter_struct dma_init_struct;
 
 /* deinitialize DMA channel4 (USART0 rx) */
 dma_deinit(DMA0, DMA_CH4);
 dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
 dma_init_struct.memory_addr = (uint32_t)usart0_rx_buf;
 dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
 dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
 dma_init_struct.number = sizeof(usart0_rx_buf);
 dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART0);;
 dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
 dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
 dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
 dma_init(DMA0, DMA_CH4, &dma_init_struct);
 
 //dma_interrupt_enable(d->dma_periph, d->dma_rx_ch, DMA_INT_FTF);
 
 /* configure DMA mode */
 dma_circulation_disable(DMA0, DMA_CH4);
 /* enable DMA channel4 */
 dma_channel_enable(DMA0, DMA_CH4);
 
 }
 
 void USART0_dma_send_config()
 {
 uint32_t dma = DMA0;
 dma_channel_enum ch = DMA_CH3;
 dma_parameter_struct ds;
 uint32_t cpLen = sizeof(usart0_tx_buf);
 
 
 /* 复位DMA参数结构体变量 */
 dma_struct_para_init(&ds);
 dma_deinit(dma, ch);
 ds.direction = DMA_MEMORY_TO_PERIPHERAL;
 ds.memory_addr = (uint32_t)usart0_tx_buf;
 ds.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
 ds.memory_width = DMA_MEMORY_WIDTH_8BIT;
 ds.number = cpLen;
 ds.periph_addr = (uint32_t)&USART_DATA(USART0);
 ds.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
 ds.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
 ds.priority = DMA_PRIORITY_ULTRA_HIGH;
 dma_init(dma, ch, &ds);
 
 dma_circulation_disable(dma, ch);
 dma_memory_to_memory_disable(dma, ch);
 dma_interrupt_enable(dma, ch, DMA_INT_FTF);
 //dma_channel_enable(dma, ch);
 usart_dma_transmit_config(dma, USART_TRANSMIT_DMA_ENABLE);
 }
 
 void USART0_dma_send(uint8_t *p, uint32_t number)
 {
 uint32_t dma = DMA0;
 dma_channel_enum ch = DMA_CH3;
 uint32_t cpLen = number;
 if(cpLen > sizeof(usart0_tx_buf)){
 cpLen = sizeof(usart0_tx_buf);
 }
 memcpy(usart0_tx_buf, p, cpLen);
 
 //准备发送
 rs485_tx_en;
 
 //关闭DMA发送
 dma_channel_disable(dma, ch);
 
 //在发送地址改变的情况下需要重新配置发送地址
 //dma_memory_address_config(dma, ch, (uint32_t)usart0_tx_buf);
 
 //重新配置发送数据的长度
 dma_transfer_number_config(dma, ch, number);
 
 //启动DMA发送
 dma_channel_enable(dma, ch);
 }
 
 void USART0_dma_recv_reconfig(void)
 {
 //uint32_t dma = DMA0;
 //dma_channel_enum ch = DMA_CH4;
 usart0_rx_flag = 0;
 usart0_rx_len = 0;
 memset(usart0_rx_buf,0,sizeof(usart0_rx_buf));
 }
 
 void USART0_Config(void)
 {
 uint32_t usart_periph = USART0;
 
 //配置中断
 USART0_nvic_config();
 
 //配置时钟
 USART0_rcu_config();
 
 //使用PA8控制485的方向
 gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP,ENABLE);
 gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
 rs485_rx_en;
 
 /* connect port to USARTx_Tx PA9 */
 gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
 
 /* connect port to USARTx_Rx PA10*/
 gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
 
 /* USART configure */
 usart_deinit(usart_periph);
 usart_baudrate_set(usart_periph, 115200U);
 usart_word_length_set(usart_periph, USART_WL_8BIT);
 usart_stop_bit_set(usart_periph, USART_STB_1BIT);
 usart_parity_config(usart_periph, USART_PM_NONE);
 usart_receive_config(usart_periph, USART_RECEIVE_ENABLE);
 usart_transmit_config(usart_periph, USART_TRANSMIT_ENABLE);
 usart_hardware_flow_rts_config(usart_periph, USART_RTS_DISABLE);        /* 无硬件流控制 */
 usart_hardware_flow_cts_config(usart_periph, USART_CTS_DISABLE);        /* 无硬件流控制 */
 usart_dma_receive_config(usart_periph, USART_RECEIVE_DMA_ENABLE);
 usart_dma_transmit_config(usart_periph, USART_TRANSMIT_DMA_ENABLE);
 usart_enable(usart_periph);
 
 //配置DMA
 USART0_dma_recv_config();
 
 //配置串口空闲中断和错误中断
 usart_interrupt_enable(usart_periph, USART_INT_IDLE);
 usart_interrupt_enable(usart_periph, USART_INT_ERR);
 usart_interrupt_enable(usart_periph, USART_INT_PERR);
 //配置传输完成中断
 usart_interrupt_enable(usart_periph, USART_INT_TC);
 
 USART0_dma_send_config();
 }
 
 void USART0_IRQHandler(void)
 {
 uint32_t usart_periph = USART0;
 uint32_t dma = DMA0;
 uint32_t err_flag = 0;
 uint32_t flag = 0;
 dma_channel_enum ch = DMA_CH4;
 
 uint32_t stat = USART_STAT(USART0);
 /* 统一错误处理(寄存器级) 性能影响:寄存器级操作比库函数更高效,但需确保位映射正确*/
 if(stat & (USART_FLAG_ORERR | USART_FLAG_FERR | USART_FLAG_NERR | USART_FLAG_PERR)) {
 uint16_t data = USART_DATA(USART0);  // 关键清除操作
 err_flag |= (stat & USART_FLAG_ORERR) ? 0x01 : 0;
 err_flag |= (stat & USART_FLAG_NERR)  ? 0x02 : 0;
 err_flag |= (stat & USART_FLAG_FERR)  ? 0x04 : 0;
 err_flag |= (stat & USART_FLAG_PERR)  ? 0x10 : 0;
 }
 
 if(RESET != usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_IDLE)) {
 /* clear IDLE flag */
 usart_interrupt_flag_clear(usart_periph, USART_INT_FLAG_IDLE);
 usart_data_receive(usart_periph);
 
 /* number of data received */
 usart0_rx_len = sizeof(usart0_rx_buf) - (dma_transfer_number_get(dma, ch));
 usart0_rx_flag = 1;
 
 //关闭DMA接收
 dma_channel_disable(dma, ch);
 //重新配置接收数据的长度
 dma_transfer_number_config(dma, ch, sizeof(usart0_rx_buf));
 //重启DMA接收
 dma_channel_enable(dma, ch);
 }
 
 /*传输完成中断
 触发时机:满足以下条件同时成立时触发:
 发送数据寄存器(TDR)为空
 移位寄存器完成最后一bit数据的物理发送
 */
 flag = USART_INT_FLAG_TC;
 if(usart_interrupt_flag_get(usart_periph, flag)){
 usart_interrupt_flag_clear(usart_periph, flag);
 usart0_tx_busy = 0;
 //传输完成后485启动接收使能,低电压
 rs485_rx_en;
 }
 
 /* 错误恢复处理 */
 if(err_flag){
 usart_disable(usart_periph);
 usart_enable(usart_periph); // 复位USART
 }
 }
 
 //DMA0 ch4接收中断
 void DMA0_Channel4_IRQHandler()
 {
 uint32_t usart_periph = USART0;
 uint32_t dma = DMA0;
 dma_channel_enum ch = DMA_CH4;
 if(dma_interrupt_flag_get(dma, ch, DMA_INT_FLAG_FTF)) {
 /* clear IDLE flag */
 usart_data_receive(usart_periph);
 
 usart0_rx_len = sizeof(usart0_rx_buf) - (dma_transfer_number_get(usart_periph, ch));
 usart0_rx_flag = 1;
 //清除接收完成中断
 dma_interrupt_flag_clear(dma, ch, DMA_INT_FLAG_FTF);
 }
 if(dma_interrupt_flag_get(dma, ch, DMA_INT_FLAG_ERR)) {
 dma_channel_disable(dma, ch);
 dma_interrupt_flag_clear(dma, ch, DMA_INT_FLAG_ERR);
 dma_channel_enable(dma, ch);
 }
 }
 
 //USART0 DMA0 ch3发送中断
 void DMA0_Channel3_IRQHandler(void)
 {
 uint32_t dma = DMA0;
 dma_channel_enum ch = DMA_CH3;
 //触发时机:当DMA传输计数器递减至0时自动触发,代表可以添加数据到缓冲区了
 if(dma_interrupt_flag_get(dma, ch, DMA_INT_FLAG_FTF)){
 dma_interrupt_flag_clear(dma, ch, DMA_INT_FLAG_FTF);
 }
 if(dma_interrupt_flag_get(dma, ch, DMA_INT_FLAG_ERR)) {
 dma_channel_disable(dma, ch);
 dma_interrupt_flag_clear(dma, ch, DMA_INT_FLAG_ERR);
 dma_channel_enable(dma, ch);
 }
 }
 void wait_usart0_send_finish(void)
 {
 while(usart0_tx_busy){};
 }
 
 void usart0_set_tx_busy(uint8_t busy)
 {
 usart0_tx_busy = busy;
 }
 uint8_t usart0_get_tx_busy(void)
 {
 return usart0_tx_busy;
 }
 
 
 
 源代码地址为:gd32f103c8t6-practice: 练习gd32f103c8t6开发板
 
 购买的gd32f103c8t6开发板的链接为:
 
 全新GD32F103C8T6开发板 含例程 含教学视频 GD32学习板核心板-淘宝网
 
 
   
 ————————————————
 
 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
 
 原文链接:https://blog.csdn.net/chencichang/article/details/148028369
 
 
 | 
 |