GD32F44使用标准库配置串口
文章目录
- GD32F44使用标准库配置串口
-
- 1. 系统环境
- 2. 初始化串口(USART0为例)
-
- 2.1 打开引脚和外设时钟
- 2.2 将引脚配置为复用功能
- 2.3 配置引脚模式
- 2.4 配置串口参数
- 2.5 使能串口
- 2.6 举一个完整的例子
- 3. 使用串口中断
-
- 3.1 开启中断
- 3.2 举一个完整的例子
。
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点,下面分别实现。
- 在
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
中,这两个函数效果是一样的。
- 同样设置中断的优先级也提供了GD标准库和ARM核心库两种函数,:
nvic_irq_enable(USART0_IRQn, 0, 0);//GD标准库
NVIC_SetPriority(SysTick_IRQn, 0x00U);//基于CMSIS标准的ARM库函数
- 对于开启中断,我们要在初始化串口后,添加:
//使能串口接收中断
usart_interrupt_enable(USART0, USART_INT_RBNE);
//使能串口发送中断
//usart_interrupt_enable(USART0, USART_INT_TBE);
- 编写串口中断函数
开启中断后,就要编写中断函数,一般我们都将中断函数放在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);//获取接收到的数据