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