GD32F4(4):GD32F450串口的使用

GD32F4使用标准库来配置串口


本文介绍了用GD32的标准库来使用GD32F450的串口,配置中断接收,对于将串口映射为printf请参考我的另一篇文章

其实我感觉串口初始化比较简单,注意细节就不会有问题。主要有人问我,我一想正好可以水一篇文章,赚点CSDN原力,于是整理了这个

1. 系统环境

  • 系统:win10
  • ide:keil5
  • 测试芯片:GD32F450
  • 用户手册版本:GD32F4xx_yonghushouce_Rev2.6.pdf
  • 数据手册版本:GD32F450xx_Datasheet_Rev2.2.pdf

2. 初始化串口(USART0为例)

2.1 开启引脚和外设时钟

//开启时钟
rcu_periph_clock_enable(RCU_GPIOA);//使能引脚时钟
rcu_periph_clock_enable(RCU_USART0);//使能外设时钟

2.2 将引脚配置为复用功能

//配置复用功能
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); //配置PA9为复用类别7
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

在数据手册中指出,对于GPIO,当作为外设接口的时候将要启用AFIO功能(在用户手册叫备用功能),也就是复用,引脚最多支持16种复用模式,每个引脚支持的复用种类,和种类所对应的功能是固定的,如下图(我的是在《GD32F450xx_Datasheet_Rev2.2.pdf》的第2.6.4章节):
在这里插入图片描述

通过红框内可知,当将引脚PA9.PA10复用为AF_7,则引脚功能为串口0收发接口。对于将串口0复用到其他引脚,要去数据手册上查找对应的AF组别。

2.3 配置引脚的模式

在数据手册中,我们知道标准gpio的结构图,如下:

在这里插入图片描述

//配置pa9引脚的模式
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_9);//配置pa9为复用上拉模式
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_9);//配置pa9为推挽输出,速度为50M
//配置pa10引脚的模式
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_10);//配置pa10为复用上拉模式
//gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);//这条语句只对输出引脚有效,输入的不需要添加这句话

2.4 配置串口参数

//串口配置
usart_deinit(USART0);	//复位串口
usart_baudrate_set(USART0,115200U);	//设置串口波特率		

这里只设置了波特率,起始奇偶校验,数据位数,停止位设置都有相应的函数,在gd32f4xx_usart.c中,如:

void usart_parity_config(uint32_t usart_periph, uint32_t paritycfg)//设置奇偶校验
void usart_word_length_set(uint32_t usart_periph, uint32_t wlen)//配置数据位数
void usart_stop_bit_set(uint32_t usart_periph, uint32_t stblen)//设置停止位
void usart_data_first_config(uint32_t usart_periph, uint32_t msbf)//设置数据发送和接收的时候数据高位在前还是低位在前

对于串口,波特率是必须设置的,其他可以不设置,就会配置成:不奇偶校验、8位数据位、一个停止位、数据低位在前的默认模式。

2.5 使能串口

usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能串口接收
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能串口发送
usart_enable(USART0);//使能串口

2.6 举一个完整的例子

#include "gd32f4xx.h"
#include "gd32f450z_eval.h"
#include "systick.h"

void uart0_init()
{
    //开启时钟
    rcu_periph_clock_enable(RCU_GPIOA);//使能引脚时钟
    rcu_periph_clock_enable(RCU_USART0);//使能外设时钟

    //配置复用功能
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); //配置PA9为复用类别7
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

    //配置引脚的模式
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_9);//配置pa9为复用上拉模式
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_9);//配置pa9为推挽输出,速度为50M

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_10);
    //gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);//这就话对输入引脚来说

    //串口配置
    usart_deinit(USART0);	//复位串口
    usart_baudrate_set(USART0,115200U);	//设置串口波特率		
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能串口接收
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能串口发送
    usart_enable(USART0);//使能串口
}

int main(void)
{
    uint16_t rx_data = 0;
	//初始化串口
	uart0_init();

    while(1){
        //数据接收
        while (usart_flag_get(USART0, USART_FLAG_RBNE) == RESET);
		rx_data = usart_data_receive(USART0); //获取字符 
        //发送数据    
        usart_data_transmit(USART0, (uint8_t)rx_data);
        while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    }
}

现在把usb转串口接到mcu引脚上,上位机发送什么,mcu就会返回什么,一个简单的串口0回显就完成了。

3. 串口中断的使用

上面虽然可以使用串口,但是对于我们来讲,使用串口中断接收才是我们最常用的方式。

3.1 开启中断

开启中断一般包括部分:

  • 系统刚启动,首先要配置系统的中断优先级分组,抢占优先级和响应优先级位数。

  • 配置外设中断的响应优先级和抢占优先级。

  • 对于外设,要配置使能中断的类型,比如:使能串口接收中断和发送中断。

  • 编写中断函数。

针对这4点,下面分别实现。

  1. gd32f4xx_misc.c里面有GD标准库提供的函数nvic_priority_group_set是设置中断优先级分组的函数,参数对应如下:
NVIC_PRIGROUP_PRE0_SUB4     :0 bits for pre-emption priority 4 bits for subpriority
NVIC_PRIGROUP_PRE1_SUB3     :1 bits for pre-emption priority 3 bits for subpriority
NVIC_PRIGROUP_PRE2_SUB2     :2 bits for pre-emption priority 2 bits for subpriority
NVIC_PRIGROUP_PRE3_SUB1     :3 bits for pre-emption priority 1 bits for subpriority
NVIC_PRIGROUP_PRE4_SUB0     :4 bits for pre-emption priority 0 bits for subpriority
nvic_priority_group_set(NVIC_PRIGROUP_PRE0_SUB4)

对于中断分组还有另外一个函数NVIC_SetPriorityGrouping,在core_cm4.h中,这两个函数效果是一样的。

  1. 同样设置中断的优先级也提供了GD标准库和ARM核心库两种函数,:
nvic_irq_enable(USART0_IRQn, 0, 0);//GD标准库
NVIC_SetPriority(SysTick_IRQn, 0x00U);//基于CMSIS标准的ARM库函数
  1. 对于开启中断,我们要在初始化串口后,添加:
//使能串口接收中断
usart_interrupt_enable(USART0, USART_INT_RBNE);
//使能串口发送中断
//usart_interrupt_enable(USART0, USART_INT_TBE);

  1. 编写串口中断函数

开启中断后,就要编写中断函数,一般我们都将中断函数放在gd32f4xx_it.c中,和STM32一样,GD的中断函数名字也是固定的。

void USART0_IRQHandler(void)
{
    if((RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) && 
       (RESET != usart_flag_get(USART0, USART_FLAG_RBNE))){
        /* Read one byte from the receive data register */
    }
       
    if((RESET != usart_flag_get(USART0, USART_FLAG_TBE)) && 
       (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_TBE))){
        /* Write one byte to the transmit data register */
    }
}

3.2 举一个完整的例子

针对上面的叙述,进行总结,如下:

#include "gd32f4xx.h"
#include "gd32f450z_eval.h"
#include "systick.h"

void uart0_init()
{
    //开启时钟
    rcu_periph_clock_enable(RCU_GPIOA);//使能引脚时钟
    rcu_periph_clock_enable(RCU_USART0);//使能外设时钟

    //配置复用功能
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); //配置PA9为复用类别7
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

    //配置引脚的模式
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_9);//配置pa9为复用上拉模式
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_9);//配置pa9为推挽输出,速度为50M

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_10);
    //gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);

    //串口配置
    usart_deinit(USART0);	//复位串口
    usart_baudrate_set(USART0,115200U);	//设置串口波特率		
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能串口接收
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能串口发送
    usart_enable(USART0);//使能串口
}

int main(void)
{
    uint16_t rx_data = 0;
    nvic_priority_group_set(NVIC_PRIGROUP_PRE0_SUB4);//配置优先级分组
	//初始化串口
	uart0_init();
	nvic_irq_enable(USART0_IRQn, 0, 0);//设置串口中断的优先级
	//开启串口接收中断
    usart_interrupt_enable(USART0, USART_INT_RBNE);
    //开启串口发送中断
    //usart_interrupt_enable(USART0, USART_INT_TBE);//暂时不开启串口发送中断
    while(1){
		;
    }
}

gd32f4xx_it.c编写串口中断函数

void USART0_IRQHandler(void)
{
    uint8_t rx_data = 0;
    //当接收中断发生
    if((RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) && 
       (RESET != usart_flag_get(USART0, USART_FLAG_RBNE))){
        /* Read one byte from the receive data register */
        rx_data = (uint8_t)usart_data_receive(USART0);//获取接收到的数据
 		usart_data_transmit(USART0, rx_data);//将接收到的字符输出,做回显显示
    }
    
     //当发送中断发生
    if((RESET != usart_flag_get(USART0, USART_FLAG_TBE)) && 
       (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_TBE))){
        /* Write one byte to the transmit data register */
    }
}

通过这个程序就能实现串口的中断接受了。

注意:相对于stm32的标准库需要手动清除中断标志位,GD在发生中断后不需要手动调用clear函数清零,那是因为它可以自动清零,在用户手册里面写了它自动清零的条件,如下:
在这里插入图片描述

即可以调用函数清零:

usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);//清除接收中断发生标志位

或,当读取接收寄存器的时候,接收中断发生标志位自动清除

usart_data_receive(USART0);//获取接收到的数据
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈搭石

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值