一、使用平台
MCU | GD32F450ZKT6 |
处理器 | Cortex-M4 |
SRAM | 256k |
Flash | 3072k |
SDK | GD32F4xx_Firmware_Library_V2.1.2 |
二、USART简介
是一种设备间数据交互的方式,一般我们会将通信协议分为物理层和协议层,物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。USART是同步异步收发器,与UART区别在于多了一个异步。
所有USART都支持DMA功能,以实现高速率的数据通信。
1、物理层
规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输,这就是硬件部分。
1.1 电平标准
有两种电平标准,TTL和RS-232,最少需要3根线RX、TX和GND。
TTL :全双工 ,逻辑0对应0V,逻辑1对应3.3V或者5V,一般从单片机引脚直接引出,电平3.3或5V是与IO电平兼容;
RS232:全双工,逻辑0对应+3V至+15V,逻辑1对应-15V至-3V ,TTL经过电平转换芯片后可以输出RS232。
通讯标准 | 电平标准 |
TTL | 逻辑1:2.4V - 5V 逻辑0:0 - 0.5V |
RS-232 | 逻辑1:-15V - -3V 逻辑0:+3V - +15V |
TTL电平标准和RS-232电平标准
1.2 RS-232信号线
接线口以针式引出信号线称为公头,以孔式引出信号线称为母头。
以下是9针RS-232接口协议
2、协议层
串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成见 图串口数据包的基本组成。一帧数据包包含了1个起始位、8个数据位、1个奇偶校验位(可有可无)、1个停止位。
2.2波特率
波特率分频系数是一个16位的数字,包含12位整数部分和4位小数部分。波特率发生器使用这两部分组合所得的数值来确定波特率。常见的波特率有4800、9600、115200。
2.3 有效数据
在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效
数据的长度常被约定为 5、6、7或 8位长度。
2.4数据校验
奇校验:数据位中的1的个数,如果数据位中1的个数位偶数,此位为1,如果数据位中1的个数位奇数,此位为0。
偶校验:数据位中的1的个数,如果数据位中1的个数位偶数,此位为0,如果数据位中1的个数位奇数,此位为1。
三、USART初始化
(1)开启引脚和外设时钟
(2)将引脚配置为复用功能
(3)配置引脚的模式
(4)配置串口参数
(5)使能串口
以下是USART初始化
// 1、开启引脚和外设时钟
rcu_periph_clock_enable(RCU_GPIOA);//使能引脚时钟
rcu_periph_clock_enable(RCU_USART0);//使能外设时钟
// 2、将引脚配置为复用功能
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); //配置PA9为复用类别7
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);
// 3、配置引脚的模式
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);
// 4、配置串口参数
usart_deinit(USART0); //复位串口
usart_baudrate_set(USART0,115200U); //设置串口波特率
usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能串口接收
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能串口发送
// 5、使能串口
usart_enable(USART0);
四、串口中断的使用
4.1 开启中断一般包括部分:
(1)系统刚启动,首先要配置系统的中断优先级分组,抢占优先级和响应优先级位数。
在gd32f4xx_misc.c中有个设置中断优先级分组的函数,如下 nvic_priority_group_set(NVIC_PRIGROUP_PRE0_SUB4);
/* 优先级分组 - 定义主优先级和次优先级 */
#define NVIC_PRIGROUP_PRE0_SUB4 ((uint32_t)0x700) /*!< 0 个主优先级 和 4 个次优先级 */
#define NVIC_PRIGROUP_PRE1_SUB3 ((uint32_t)0x600) /*!< 1 个主优先级 和 3 个次优先级 */
#define NVIC_PRIGROUP_PRE2_SUB2 ((uint32_t)0x500) /*!< 2 个主优先级 和 2 个次优先级 */
#define NVIC_PRIGROUP_PRE3_SUB1 ((uint32_t)0x400) /*!< 3 个主优先级 和 1 个次优先级 */
#define NVIC_PRIGROUP_PRE4_SUB0 ((uint32_t)0x300) /*!< 4 个主优先级 和 0 个次优先级 */
2)配置外设中断的响应优先级和抢占优先级。
在gd32f4xx_misc.c中有个设置中断响应优先级和抢占优先级的函数,如下所示。
nvic_irq_enable(USART0_IRQn, 0, 0); /* 配置串口中断优先级 */
(3)对于外设,要配置使能中断的类型,比如:使能串口接收中断和发送中断。
在gd32f4xx_usart.c中有个使能串口接收中断和发送中断的函数,如下所示。
usart_interrupt_enable(USART0, USART_INT_RBNE); /* 开启串口接收中断 */
(4)编写中断函数。
开启中断后,就要编写中断函数,一般我们都将中断函数放在gd32f4xx_it.c中,和STM32一样,GD的中断函数名字也是固定的。
void USART0_IRQHandler(void)
{
uint8_t rx_data = 0;
if((RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)))
{
/* 从接收数据寄存器中读取一个字节的数据 */
rx_data = (uint8_t)usart_data_receive(USART0);
/* 将读取到的数据进行回显操作 */
usart_data_transmit(USART0,rx_data);
}
}
注意:在串口中断中,同等优先级的systick 和 IRQHandler具有相互竞争的表现,同时会导致串口数据的丢失,数据不完整。以下是同等优先级出现的结果。