串口
一、串口通信原理
1.1串口基础知识
1.1.1串口介绍
串口是指外设和处理器之间通过数据信号线、地线和控制线等,按位进行传输数据的一种通讯方式。尽管传输速度比并行传输低。但串口可以在使用一根线发送数据的同时用另一根线接收数据。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验位,这些参数在两个通信端口之间必须一致。
1.1.2串口通信参数介绍
波特率: 衡量通信速度的参数,它表示每秒钟传送的bit的个数。
数据位: 衡量通信中实际数据位的参数,表示一个信息包里包含的数据位的个数。
停止位: 用于表示单个信息包的最后位,典型值为1、1.5和2位。由于数据是在传输线上传输的,每个设备都有自己的时钟,很有可能在通信过程中出现不同步,停止位不仅仅表示传输的结束,还能提供校正时钟同步的机会。停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率也越慢。
奇偶检验位: 表示一种简单的检查错误的方式。
1.1.3串口工作模式
串口可以工作在单工、半双工和全双工模式下。
单工:在通信的任意时刻,信息只能由A传到B。
半双工:在通信的任意时刻,信息即可由A传到B,又能由B传到A,但同时只能有一个方向上的传输存在。
全双工:在通信的任意时刻,通信线路上存在A到B和B到A的双向信号传输。
1.1.4串口通信协议
串口在进行通信的时候会按照数据包的形式进行发送,帧格式如图所示。
串口通信是一位一位地传输,每传输一个字符总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求。
每一个字符的前面都有一位起始位(低电平),后面由7位数据位组成,接着是一位校验位,最后是停止位。
停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。
1.2串口接口原理图
在开发板上默认使用的串口是串口1,有两根数据线,也就是USART1_TX和USART1_RX。串口引脚和下载引脚连接在同一个端子上,插上DAPLink就可以进行下载和串口调试。关于串口原理图如图所示。
1.3串口驱动流程
拿到开发板,把DAPLink连接到开发板的端子上,打开串口调试助手(在资料包/02开发工具/串口调试工具/sscom5.13.1),然后会检测到一个串口,如图所示。
编写代码,先要配置串口使能,配置波特率、停止位、校验位等参数。然后调用串口发送函数即可发送数据。如使用重定向还需要编写重定向函数,使用printf即可打印输出。
二、串口打印信息
2.1串口配置
一般我们使用串口,都需要有以下几个步骤。
l 开启时钟(包括串口时钟和GPIO时钟)
l 配置GPIO复用模式
l 配置GPIO的模式
l 配置GPIO的输出
l 配置串口(配置一些参数)
l 使能串口(串口使能和发送使能)
2.1.1开启时钟
使用串口0的话就是PA9和PA10引脚。
可在芯片手册中查到,如下:
那第一步就是先开启端口A的时钟,在库函数点灯那一章节给大家介绍了使能时钟的函数rcu_periph_clock_enable,只需要传入对应的参数即可。使能端口A的时钟就把RCU_GPIOA当做参数传入。第二步就是开启串口的时钟,把对应的串口0的时钟RCU_USART0传入即可。为了方便后续修改,把端口A的时钟和串口0的时钟用宏定义定义,如下:
#define BSP_USART_RCU RCU_USART0 #define BSP_USART_TX_RCU RCU_GPIOA #define BSP_USART_RX_RCU RCU_GPIOA
然后对应的使能时钟的代码就是:
rcu_periph_clock_enable(BSP_USART_RCU); // 开启串口时钟 rcu_periph_clock_enable(BSP_USART_TX_RCU); // 开启端口时钟 rcu_periph_clock_enable(BSP_USART_RX_RCU); // 开启端口时钟
2.1.2配置GPIO复用模式
GD32的引脚是可以有复用功能的,就是说单个引脚可有很多个功能,默认的功能一般都是作为GPIO使用。在gd32f4xx_gpio.h中可以查找到设置复用的函数void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin);
这个函数有三个参数,第一个参数就是要配置的引脚端口,第二个参数就是要复用的功能,第三个参数就是要配置的引脚。
固件库使用指南338页:
第一个参数和第三个参数我们知道分别为GPIOA,GPIO_PIN_9,GPIOA,GPIO_PIN_10。关于第二个参数可以到芯片数据手册的第46页进行查找,如图所示。
从图可以看到PA9对应的USART0_TX的功能复用为AF7,PA10对应的USART0_RX的功能复用为AF7,那第二个参数我们也知道了。接下来就可以开启PA9,PA10的复用功能了。代码编写如下。首先定义一下端口和复用功能的宏定义。
#define BSP_USART_TX_PORT GPIOA #define BSP_USART_TX_PIN GPIO_PIN_9 #define BSP_USART_RX_PORT GPIOA #define BSP_USART_RX_PIN GPIO_PIN_10 #define BSP_USART_AF GPIO_AF_7 // 串口是引脚复用功能7 /* 配置复用功能 */ gpio_af_set(BSP_USART_TX_PORT,BSP_USART_AF,BSP_USART_TX_PIN); gpio_af_set(BSP_USART_RX_PORT,BSP_USART_AF,BSP_USART_RX_PIN);
通过上面两句就可以把PA9,PA10设置为串口功能了。
2.1.3配置GPIO的模式
配置GPIO的模式还是使用gpio_mode_set这个函数,不同的是第二个参数要配置为复用功能而不是输出功能,第三个参数要配置为上拉。
转化为代码如下。
/* 配置TX为复用模式 上拉模式 */ gpio_mode_set(BSP_USART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_USART_TX_PIN); /* 配置RX为复用模式 上拉模式 */ gpio_mode_set(BSP_USART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, BSP_USART_RX_PIN);
根据官方给的代码例程,需要GPIO引脚需要上拉:
用户手册497页,引脚描述如下:
2.1.4配置GPIO的输出
配置GPIO的输出也还是用gpio_output_options_set这个函数,这个和之前库函数点灯配置的一样,修改一下引脚就可以直接套用。
/* 配置TX为推挽输出 50MHZ */ gpio_output_options_set(BSP_USART_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_TX_PIN); /* 配置RX为推挽输出 50MHZ */ gpio_output_options_set(BSP_USART_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_RX_PIN);
当我们配置为输出模式的时候,可以有两种输出模式选择,一种是推挽输出模式,一种是开漏输出模式。由于开漏需要外接上拉电阻才可以输出高电平,这里并不适合,所以需要设置为推挽输出。
2.1.5配置串口
和之前库函数点灯不同的是,使用串口还需要进行串口的配置。前面只是对GPIO的引脚做了配置,然后就可以操作GPIO进行输入输出,但是要使用串口,还需要设置串口的一些参数,后面使用其它的资源也是如此。
在前一章节的串口原理介绍中讲到串口有几个必要的参数,分别是波特率,校验位,数据位,停止位。在代码里也就是要设置这几个参数。
(1)复位
在使用一个外设之前,可以先复位一下,防止一些不必要的事情发生。在对应的外设库文件中一般都会有这个函数。在gd32f4xx_uart.h头文件中有。这个函数复位串口。有一个参数,就是要复位的串口:void usart_deinit(uint32_t usart_periph);
(2)波特率
这个函数设置波特率。有两个参数,分别为要设置的串口和要设置的波特率:void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval);
(3)校验功能
这个函数配置校验功能。有两个参数,第一个就是要配置的串口,第二个就是设置校验方式:void usart_parity_config(uint32_t usart_periph, uint32_t paritycfg);关于校验方式的选项如图所示。
从图可以看到,校验方式可以选择奇校验、偶检验和无校验。一般配置为无校验即可。
(4)数据为长度
这个函数设置数据位的长度。有两个参数,第一个参数就是要配置的串口,第二个参数就是要设置的数据位的长度:void usart_word_length_set(uint32_t usart_periph, uint32_t wlen);关于数据位长度的选项如图所示。
从图可以知道关于数据长度有两个选项,一般选择8位即可。
(5)停止位
这个函数设置停止位的位数。有两个参数,第一个参数就是要配置的串口,第二个参数就是要设置的停止位的位数,关于停止位的位数的选项如图所示。
停止位一般选择1位即可。
根据以上所学,编写串口配置代码如下:
/* 串口配置*/ usart_deinit(BSP_USART); // 复位串口 usart_baudrate_set(BSP_USART,dwbaud_rate); // 设置波特率 usart_parity_config(BSP_USART,USART_PM_NONE); // 没有校验位 usart_word_length_set(BSP_USART,USART_WL_8BIT); // 8位数据位 usart_stop_bit_set(BSP_USART,USART_STB_1BIT); // 1位停止位
这里要注意一下BSP_USART是一个宏定义
#define BSP_USART USART0
dwbaud_rate是函数里的一个形参,为了方便修改串口的波特率,函数实体为void usart_gpio_config(uint32_t dwbaud_rate),在使用的时候,可以直接传入对应的波特率,例如配置波特率为115200,转化为代码可写为
usart_gpio_config(115200); // 串口配置
如还需要配置其它的参数请查找对应的函数调用即可。
2.1.6使能串口
串口配置好之后并不能开始工作,还需要去使能,就是相当于有一个开关可以打开关闭。值得注意的是发送和接收也需要分别去使能,串口使能相当于一个总开关,发送和接收相当于分别控制的开关。要使用串口,首先要打开总开关。
这个函数使能串口,有一个参数,就是要使能的串口:void usart_enable(uint32_t usart_periph);
如果要发送数据的话还需要使能发送功能:void usart_transmit_config(uint32_t usart_periph, uint32_t txconfig);这个函数配置串口发送。有两个参数,第二个参数对应的选项如图所示。
从图中可以看到,如果使能串口发送就配置为USART_TRANSMIT_ENABLE。
要接收数据的话还需要使能接收功能。这个函数配置串口接收。void usart_receive_config(uint32_t usart_periph, uint32_t rxconfig);有一个参数,对应的选项如图所示。
从图中可以看到,如果使能串口接收就配置为USART_RECEIVE_ENABLE。
我们只使用串口发送功能,所以只需要配置串口使能和串口发送使能即可。转化为代码为
usart_transmit_config(BSP_USART,USART_TRANSMIT_ENABLE); // 使能串口发送 usart_enable(BSP_USART); // 使能串口
2.2串口发送数据
配置好串口之后,下一步的操作就是要发送数据。
void usart_data_transmit(uint32_t usart_periph, uint32_t data); 这个函数可以发送数据,有两个参数,第一个参数是要使用的串口,第二个参数是要发送的数据,不过需要注意的是这个函数一次只能发送一个字节。要保证串口稳定的传输,就需要在发送完一个字节之后再发送下一个字节。需要去检测数据发送完成。
FlagStatus usart_flag_get(uint32_t usart_periph, usart_flag_enum flag); 这个函数是获取状态寄存器的标志。有两个参数,第一个参数是要使用的串口,第二个参数是要获取的状态位,状态位选项为图所示(只截取一部分)。
可以获取发送缓冲区的标志位(缓冲区空标志TBE),看当前是否还有数据,如果有数据,将等待,如果没有数据就可以继续发送。
从图可以了解到当将要发送的数据写入USART_DATA时,此位被清0,当数据发送完成之后,此位置1。所以当检测到此位为1时就表明当前数据缓冲区为空,可以继续发送数据。
关于串口发送数据可以封装为一个函数如下
void usart_send_data(uint8_t ucch) { usart_data_transmit(BSP_USART, (uint8_t)ucch); while(RESET == usart_flag_get(BSP_USART, USART_FLAG_TBE)); // 等待发送数据缓冲区标志置位 }
这样一个字符一个字符的打印输出是不是很麻烦,没关系,我们可以再进行封装一层,一次发送一个字符串。
void usart_send_String(uint8_t *ucstr) { while(ucstr && *ucstr) // 地址为空或者值为空跳出 { usart_send_data(*ucstr++); } }
2.3串口重定向
上面封装的发送字符串的方式打印信息看似方便,但如果我们想要打印数字,小数,该怎么打印呢?大家是否习惯使用了printf这个函数,可以通过%d,%f打印整形和小数,这一小节就教大家怎么把串口重定向到printf函数。
2.3.1串口重定向介绍
C语言中的printf函数默认输出设备是显示器,如果要在串口显示,必须重新定义标准库函数里调用的与输出设备相关的函数。需要注意的是,在keil中使用printf一定要勾选“微库”选项。
2.3.2 printf重定向
首先c语言的printf函数中不断循环调用fputc函数,所以需要重写fputc函数,这个函数的功能就是打印输出一个字符,这不正和我们编写的usart_send_data函数功能一样。fputc函数可写为
int fputc(int ch, FILE *f) { usart_data_transmit(BSP_USART, (uint8_t)ch); while(RESET == usart_flag_get(BSP_USART, USART_FLAG_TBE)); // 等待发送数据缓冲区标志置位 return ch; }
编写好fputc函数之后就可以使用printf函数输出信息了。只要将fputc函数放入主函数,或者其他可以包括的.c文件中即可。
2.4举一反三
通过上面的一系列步骤,我们可以用串口0发送数据,那如果用串口1发送数据,该如何操作呢?
还记得我们前面配置的宏定义吗,宏定义的好处就是方便移植。把串口0改为串口1,函数主体都不用修改,只需要修改宏定义即可。
串口1的引脚接口为PA2和PA3,所以串口1的宏定义如图所示。
#define BSP_USART_RCU RCU_USART1 #define BSP_USART_TX_RCU RCU_GPIOA #define BSP_USART_TX_PORT GPIOA #define BSP_USART_TX_PIN GPIO_PIN_2 #define BSP_USART_RX_RCU RCU_GPIOA #define BSP_USART_RX_PORT GPIOA #define BSP_USART_RX_PIN GPIO_PIN_3 #define BSP_USART_AF GPIO_AF_7 // 串口是引脚复用功能7 #define BSP_USART USART1
代码中只需要将串口0的宏定义修改为串口1的宏定义就可以使用串口1发送信息了。
2.5实验现象
标签:USART,usart,08,BSP,参数,串口,GPIO From: https://www.cnblogs.com/steven913/p/16863901.html