“使用GD32F450串口:深入探索GD32F4系列第四部分”

GD32F4使用标准库来配置串口

文章目录

  • GD32F4使用标准库来配置串口
  • 1. 系统环境
  • 2. 初始化串口(USART0为例)
  • 2.1 开启引脚和外设时钟
  • 2.2 将引脚配置为复用功能
  • 2.3 配置引脚的模式
  • 2.4 配置串口参数
  • 2.5 使能串口
  • 2.6 举一个完整的例子
  • 3. 串口中断的使用
  • 3.1 开启中断
  • 3.2 举一个完整的例子

  • 本文介绍了用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);//获取接收到的数据
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » “使用GD32F450串口:深入探索GD32F4系列第四部分”

    发表评论