GD32从0开始学GD32单片机—— USART串口通信详解
Posted 马浩同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GD32从0开始学GD32单片机—— USART串口通信详解相关的知识,希望对你有一定的参考价值。
目录
概述
USART串口将是我们接触的第一个通信协议,也是最常用的通信协议。在项目开发中,我们常常用串口来打印单片机的运行日志,在查找一些运行时异常时特别有用,如果能通过串口日志打印来找出运行时的异常,肯定就不需要再debug了,省去了很多时间。
下面是GD32串口的结构框图,咋一看非常复杂,但其实日常我们只使用了其中一小部分。
功能概述
GD32中的串口支持大概下面几种模式——全双工异步通信、智能卡模式、同步通信模式、硬件流操作、串行红外编解码功能、LIN模式、半双工通信模式
但并不是GD32中所有的串口都支持这些模式,USART0/1/2支持所有的功能,UART3/4仅支持全双工异步通信。
上面USART0/1/2和UART3/4并不是笔误,USART和UART的区别在于中间的“S”,这个“S”是英文Synchronous(同步)的缩写,因为UART3/4不支持同步传输模式,因此缩写中也就没有加“S”。
因为日常几乎只使用到全双工异步通信模式,所以下面只介绍这个模式。
全双工异步通信模式
参数说明
满血版的串口有5个引脚,但在全双工异步通信模式下只需要用到RX和TX引脚进行通信。
下面是全双工异步通讯时序图。
通讯开始后,发送一个起始位,起始位后紧跟每一个位的数据,最后一位,即bit7有可能为校检位,取决于用户的选择,但一般来说我们不需要使用校检位,最后会以一个停止位来结束一次通信。
停止位的时间长度并不一定是一个时间单位,不同的模式要设置不同的停止位长度。
停止位长度(位) | 功能描述 |
---|---|
1 | 默认值 |
0.5 | 智能卡模式接收 |
2 | 标准USART,单线及调制解调模式 |
1.5 | 智能卡模式发送和接收 |
使用全双工异步通信时,使用1位停止位即可。
串口发送
下图为串口发送的时序图。
串口发送的简要步骤:
- 在USART_CTL0寄存器中置位UEN位,使能USART;
- 通过USART_CTL0寄存器的WL设置字长;
- 在USART_CTL1寄存器中写STB[1:0]位来设置停止位的长度;
- 如果选择了多级缓存通信方式,应该在USART_CTL2寄存器中使能DMA(DENT位);
- 在USART_BAUD寄存器中设置波特率;
- 在USART_CTL0寄存器中设置TEN位,使能串口发送;
- 等待TBE置位;
- 向USART_DATA寄存器写数据;
- 若DMA未使能,每发送一个字节都需重复步骤7-8;
- 等待TC=1,发送完成。
说明:
TBE,全称Transfer Buffer Empty,“发送缓冲区空”标志位,当发送缓冲区为空该标志位置位,反之。
TC,全称Transfer Complete,“发送完成”标志位,当串口发送完成该标志位置位,很快后会硬件清零
串口接收
串口接收的简要步骤:
- 在USART_CTL0寄存器中置位UEN位,使能USART;
- 写USART_CTL0寄存器的WL去设置字长;
- 在USART_CTL1寄存器中写STB[1:0]位来设置停止位的长度;
- 如果选择了多级缓存通信方式,应该在USART_CTL2寄存器中使能DMA(DENR位);
- 在USART_BAUD寄存器中设置波特率;
- 在USART_CTL0中设置REN位,使能串口接收。
- 串口接收数据,向USART_DATA寄存器写数据
- RBNE置位
- 如果设置了USART_CTL0寄存器中相应的中断使能位RBNEIE,将会产生中断
- 对USART_DATA寄存器的读操作,清除RBNE位
说明:
RBNE,全称Read Buffer Not Empty,“接收缓冲区非空”标志位,当接收缓冲区非空时该标志位置位,反之。
例程
串口通信
usart.c文件
#include "usart.h"
void USART_Config(void)
/* 初始化GPIO外设 */
rcu_periph_clock_enable(RCU_GPIOA);
/* TX管脚,PA9,复用推挽输出,速度50MHz */
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
/* RX管脚,PA10,下拉输入,速度50MHz */
gpio_init(GPIOA, GPIO_MODE_IPD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
/* 初始化USART外设 */
rcu_periph_clock_enable(RCU_USART0); // 使能串口0时钟
usart_baudrate_set(USART0, 115200); // 波特率115200
usart_parity_config(USART0, USART_PM_NONE); // 无校检
usart_word_length_set(USART0, USART_WL_8BIT); // 8位数据位
usart_stop_bit_set(USART0, USART_STB_1BIT); // 1位停止位
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); // 使能串口发送
usart_receive_config(USART0, USART_RECEIVE_ENABLE); // 使能串口接收
usart_enable(USART0); // 使能串口
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
/* 发送一个字节数据到串口 */
usart_data_transmit(USART0, (uint8_t)ch);
/* 等待发送完毕 */
while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET);
return (ch);
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
/* 等待串口输入数据 */
while (usart_flag_get(USART0, USART_FLAG_RBNE) == RESET);
return (int)usart_data_receive(USART0);
上面的例程代码我们使用GD32的USART0外设,对于USART0我们需要初始化PA9和PA10这两个管脚,每个串口外设都有对应的管脚。
串口外设对应的发送接收管脚可以参考下表。
串口 | 发送管脚(TX) | 接收管脚(RX) |
---|---|---|
USART0 | PA9 | PA10 |
USART1 | PA2 | PA3 |
USART2 | PB10 | PB11 |
串口的发送和接收例程中分别封装在fputc和fgetc函数中,重定义这两个函数,使用这两个函数需包含头文件“stdio.h”,我们在向串口发送数据就可以直接用printf函数,向串口接收数据时就可以用scanf函数,十分符合我们平时的习惯。
但大家应该注意到,使用重定向只能固定某一个串口,所以使用重定向最好定义在自己常用的串口上。
串口发送的main.c文件
现象:每秒向串口发送一个“Hello”字符串。
int main(void)
systick_config();
USART_Config();
while(1)
printf("Hello\\n");
delay_ms(1000);
串口接收的main.c文件
现象:电脑端向GD32串口发送数据,GD32接收后返回所接收的内容。
int main(void)
systick_config();
USART_Config();
char buf[20] = 0;
while(1)
memset(buf, 0x00, sizeof(buf));
scanf("%s", buf);
printf("received: %s\\n", buf);
以上是关于GD32从0开始学GD32单片机—— USART串口通信详解的主要内容,如果未能解决你的问题,请参考以下文章