GD32F310 串口空闲中断+DMA+rs485转换

该文描述了如何使用GD32F310微控制器通过USART接口配合DMA和RS485转换芯片进行数据通信。初始化设置包括串口参数、DMA通道配置以及RS485模式切换。在接收时,利用DMA缓存数据,并在空闲中断中处理接收到的信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GD32F310 串口USART空闲中断+DMA+rs485转换

工作模式

1、串口USART发送数据到RS485芯片,经过芯片转换与外部设备进行通讯。
2、rs485芯片,收发模式控制引脚 PA11,低电平接收,高电平发送,初始化为接收模式,删除发送函数此引脚调用,即为正常串口USART调用。
3、使用USART0进行数据通讯,发送引脚TX为PA9,接收引脚RX为PA10,引脚由西片厂商指定,不可随意更改。
4、用于USART0接收的MDA数据通道,由芯片厂商指定不可随意配置,具体内用需要查看芯片手册。

头文件 usart_rs485.h

#ifndef __PRIVATE_PACKS_USART_RS485_H__
#define __PRIVATE_PACKS_USART_RS485_H__

//private_packs_usart_rs485.h

#include "stdint.h"

//接收缓存大小
#define RECV_BUF_LEN_RS485 256

typedef struct {
//	串口数据接收缓存
  uint8_t buf_recv[RECV_BUF_LEN_RS485];
//	串口接收数据数量
  int count_recv;
} private_packs_usart_rs485_struct_recv_rs485;

//串口485初始化函数
void private_packs_usart_rs485_init();
//串口485发送函数
void private_packs_usart_rs485_send_data(uint8_t *buf, int len);

#endif

源文件 usart_rs485.c

#include "gd32f3x0.h"
#include <stdio.h>
#include "gd32f310c_eval.h"
#include "private_packs_usart_rs485.h"
#include "string.h"

#define BAUDRATE_RS485 9600

//串口数据缓存变量
private_packs_usart_rs485_struct_recv_rs485 rs485_recv = {0};

//DMA数据接收缓存buf
static uint8_t dma_recv_buf[RECV_BUF_LEN_RS485];

/*!
    \brief      DMA_CH2配置函数
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void dma_config_rs_485(void)
{
  dma_parameter_struct dma_init_struct;

//	启动DMA时钟
  rcu_periph_clock_enable(RCU_DMA);

  /* 取消DMA_CH2初始化 */
  dma_deinit(DMA_CH2);
  dma_struct_para_init(&dma_init_struct);
	
//	填写初始化结构体内容
  /* 数据方向:外设到内存 */
  dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
  /* 设置内存接收基地址 */
  dma_init_struct.memory_addr = (uint32_t)dma_recv_buf;
  /* 内存地址递增 */
  dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  /* 8位内存数据 */
  dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
	/* 最大接收数 */
  dma_init_struct.number = RECV_BUF_LEN_RS485;
  /* 外设基地址,USART数据寄存器地址 */
  dma_init_struct.periph_addr = (uint32_t)&USART_RDATA(USART0);
  /* 外设地址不递增 */
  dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  /* 8位外设数据 */
  dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
  /* 最高DMA通道优先级 */
  dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  /* 按照结构体的配置初始化DMA */
  dma_init(DMA_CH2, &dma_init_struct);
  /* 关闭DMA循环模式 */
  dma_circulation_disable(DMA_CH2);
  /* DMA内存到内存模式不开启 */
  dma_memory_to_memory_disable(DMA_CH2);
  /* 使能DMA传输 */
  dma_channel_enable(DMA_CH2);
}

/*!
    \brief      USART 配置函数
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usart_config_rs_485(void)
{
  /* 使能GPIOA时钟 */
  rcu_periph_clock_enable(RCU_GPIOA);

  /* 使能USART0时钟 */
  rcu_periph_clock_enable(RCU_USART0);

//	复用gpio到uart
  /* 复用DPIOA9为 USART0 TX引脚 */
  gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);

  /* 复用DPIOA10为 USART0 RX引脚 */
  gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);

  /* configure USART tx as alternate function push-pull */
  gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);

  /* configure USART rx as alternate function push-pull */
  gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
/

//设置rs485芯片,收发模式控制引脚 PA11,低电平接收,高电平发送,初始化为接收模式
  gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11);
  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX,  GPIO_PIN_11);
  gpio_bit_reset(GPIOA,  GPIO_PIN_11);


  /* 配置 USART0 */
  usart_deinit(USART0);
  /* 设置波特率 */
  usart_baudrate_set(USART0, BAUDRATE_RS485);

  /* 使能接收 */
  usart_receive_config(USART0, USART_RECEIVE_ENABLE);

  /* 使能发送 */
  usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

  /* USART0 DMA接收模式开启 */
  usart_dma_receive_config(USART0, USART_DENR_ENABLE);
  /* USART中断设置,抢占优先级0,子优先级0 */
  nvic_irq_enable(USART0_IRQn, 0, 0);
  /* 使能USART0空闲中断 */
  usart_interrupt_enable(USART0, USART_INT_IDLE);
	/* 使能USART0 */
  usart_enable(USART0);
}
/*!
    \brief      初始化串口usart rs485 DMA
    \param[in]  none
    \param[out] none
    \retval     none
*/
void private_packs_usart_rs485_init()
{
  dma_config_rs_485();
  usart_config_rs_485();
}
/*!
    \brief      串口usart rs485 发送函数
    \param[in]  none
    \param[out] none
    \retval     none
*/
void private_packs_usart_rs485_send_data(uint8_t *buf, int len)
{
//	拉高GPIOA11引脚电平,开启rs485芯片发送模式
  gpio_bit_set(GPIOA,  GPIO_PIN_11);
// 串口发送数据
  for(int tx_count = 0; tx_count < len; tx_count++) {
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    usart_data_transmit(USART0, buf[tx_count]);
  }
//	发送完成,拉底GPIOA11引脚电平,开启rs485芯片接收模式
  gpio_bit_reset(GPIOA,  GPIO_PIN_11);
}

//USART0中断处理函数
void USART0_IRQHandler()
{
  if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE))
  {
//		空闲中断处理
		/* 清中断标志 */
    usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
		/* 重新开启串口接收 */
    usart_data_receive(USART0);
		/* 关闭DMA */
    dma_channel_disable(DMA_CH2);
		/* 计算DMA接收数据长度 */
    rs485_recv.count_recv = RECV_BUF_LEN_RS485 - dma_transfer_number_get(DMA_CH2);
    if(rs485_recv.count_recv != 0 && rs485_recv.count_recv < RECV_BUF_LEN_RS485)
    {
			/* 转存数据到待处理数据缓冲区 */
      memcpy(rs485_recv.buf_recv, dma_recv_buf, rs485_recv.count_recv); 
    }
    else
    {
      rs485_recv.count_recv = 0;
    }

    /* 重新设置DMA传输 */
    dma_memory_address_config(DMA_CH2, (uint32_t)dma_recv_buf);
    dma_transfer_number_config(DMA_CH2, RECV_BUF_LEN_RS485);
    dma_flag_clear(DMA_CH2, DMA_FLAG_FTF);
		/* 开启DMA传输 */
    dma_channel_enable(DMA_CH2);		
    return ;
  }
}

#if 0
/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
  /* initialize USART */
  private_packs_usart_rs485_init();

  /* wait IDLEF set and clear it */
  while(RESET == usart_flag_get(USART0, USART_FLAG_IDLE));
  usart_flag_clear(USART0, USART_FLAG_IDLE);
  usart_interrupt_enable(USART0, USART_INT_IDLE);

  while(1) {
    if(rs485_recv.count_recv > 0) {
//			接收到串口数据,发送回去
			private_packs_usart_rs485_send_data(rs485_recv.buf_recv, rs485_recv.count_recv);
			rs485_recv.count_recv = 0;
    }
  }
}
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值