STM32串口通信USART1配置与使用指南

UART:universal asynchronous receiver and transmitter通用异步收发器
USART:universal synchronous asynchronous receiver and transmitter通用同步异步收发器
上图是利用寄存器配置的步骤,下面我用官方库函数配置USART1

1、要配置串口usart1,先查看数据手册以及开发板原理图的芯片管脚开发板原理图的芯片图
根据上图可以看出USART1的发送线USART_TX连在芯片的PA9管脚,接收线USART_RX连在芯片的PA10管脚
数据手册的时钟树
再根据上图可以看出USART的时钟和GPIOA的时钟都挂在APB2总线上,有了这两条信息我们就可以开始配置的第一步了。
一、首先我们开启PA9和PA10两个IO口的时钟
1、查询开启APB2线上外设时钟的库函数,下图为查询到的结果
APB2时钟线使能或失能的库函数
由上图可以看出,此函数的作用是开启或关闭APB2指定线上外设的时钟,那么这两个参数必然包括指定外设和让他使能或失能的标志,使能为ENABLE、失能为DISABLE,剩余的一个参数我们在下面找到外设时钟的标志
APB2的第一个参数
由上图我们看到我们要开启的GPIOA的时钟参数为:RCC_APB2Periph_GPIOA

调用函数并将对应的参数填入
usart.c
毛病有不了一点儿。
2、接下来初始化管脚PA9和PA10
同样查询库函数
初始化管脚
上图函数是用来初始化管脚的属性的,两个参数分别是GPIOX,和一个结构体,往下翻可以看到结构体里面要配置的属性,下图示
这个结构体中要配置管脚的属性有,GPIOX的管脚号、管脚输出速率、管脚的输入输出模式。管脚号
输出速度
管脚输入输出模式
看了上图我们思考一下管脚各自对应的属性,先看PA9(USART_TX串口1的发送管脚),(1)我们自然要选择GPIO_Pin_9这个参数了(2)输出速率我们选择最高速率(3)我们站在单片机的角度来看,发送管脚自然是输出模式了,再有我们需要输出高电平1(3.3V)、低电平0(0V),那么开漏输出模式自然无法满足,因为开漏是无法给出高电平的,具体可以搜索一下CMOS管的开漏,那么为什么要复用呢?看下图可知这个管脚USART还要用到所以要复用一下

到此初始化PA9管脚的三个参数分别为GPIO_Pin_9、GPIO_Speed_50MHz、GPIO_Mode_AF_PP。知道了这些参数后我们定义一个GPIO_InitTypeDef结构体来容纳这些参数
将参数填入,调用GPIO_Init函数初始化IO口得到下图

同样的思路,PA10作为串口输入管脚,GPIO_Pin参数选择GPIO_Pin_10,因为是输入模式不需要输出速度,输入模式没有硬性要求,选择浮空输入模式GPIO_Mode_IN_FLOATING
同样的步骤初始化PA10管脚,不再赘述

二、我们开启USART1的时钟并初始化它
(1)由前面的时钟树可以看出,USART1的时钟也挂在APB2总线上,那么开启时钟

(2)接着我们要初始化USART1,查询库函数得到下图

我们要初始化的串口是USART1那么第一个参数当然是USART1,第二个参数是它的一些属性,那么我们看看有哪些属性,下图
我们看第一个参数,波特率,波特率描述的是一秒钟发送的位数(bit),可以自己设定,但是最终要选择和串口软件一样的波特率,这里我就选择115200了
数据长度就是你要发送一次数据的位数了,这里我选择8位;停止位类似与两个人打电话最后说我挂了啊,然后结束通信,这里我选择1位;硬件流控制选择不使用;模式我们既要接收还要发送,所以选择USART_Mode_Rx | USART_Mode_Tx;不使用校验位USART_Parity_No;最后同样初始化一个结构体然后填入对应参数初始化。

到这里只需要查询到对应功能的函数即可,参数根据库函数手册选择你需要的就行。
上面就是初始化工作,接下来我们开启串口使能(打开串口的开关)。


要开启的串口是USART1,那么参数选择USART1、ENABLE.

到此基本的串口配置工作完成。接下来我们要进行收发数据操作,那么仅仅配置串口是不行满足这两个操作的。
我们先看一下串口收发数据的操作示意图
可以看出数据收发利用的是同一个数据寄存器(DR)如下图,单片机是从TX口向外发送数据,所以首先可以看出图左为外、图右为内

1)发送数据流程:
我们需要判断一下发送数据寄存器(TDR)是否为空,如果为空那么我们将数据赋给DR(相当于写入TDR),为什么要判断?这是因为TDR位数有限,满了再写会把数据挤掉导致数据出错。下一步TDR会判断发送移位寄存器是否有数据,如果有数据会等待数据被移走,然后自动将自己的数据写入发送移位寄存器,最后数据通过tx口发送。
2)读取数据流程
外界数据通过RX口进入移位寄存器,移位寄存器将数据进行移位,当寄存器满时移位寄存器自动将数据写入接收数据寄存器(DRD),我们只需要读DR里的内容即可。

明白了这两个流程我们就可以构建自己的读写数据函数了,先写发送数据函数
根据流程,我们需要先判断发送数据寄存器是否为空,怎么判断呢?状态寄存器看下图通过判断状态寄存器的TXE位得出发送寄存器是否为空,也就是TXE=1时可以写入DR

这里我直接判断寄存器的TXD位是否为0,是0代表还有之前的数据没有移入发送移位寄存器,在此阻塞。其实还可以使用库函数,库函数很方便且可读性较强

while((USART->SR&(0x1<<6))==0);//寄存器方式
while(USART_ GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//RESET宏定义为0
可以看到下图的两个信号,TXE和TC这里谈一下这两个信号的区别,翻到图248 USART框图看到DR寄存器写入发送数据寄存器,寄存器通过TX口发出数据,那么这两个信号的区别就在TXE是判断发送数据寄存器是否为空,也就是你现在能不能写入DR寄存器,另一个TC是判断发送移位寄存器是否为空(之前的数据发送完毕没有,硬件判断是否能将发送数据寄存器放到发送移位寄存器)
最后调用发送数据库函数USART_ SendData完成自定的发送数据函数
接下来测试一下发送数据函数

调用函数并打开串口软件连接,注意串口软件右侧的波特率、停止位等信息选择正确。复位后发送一个w,测试结果如下
接下来写接收函数,那么接收函数的条件是什么?就像传球一样,1、对方手里有球才能传给你2、你得知道对方什么时候会传给你。我们先只考虑第一个条件,现在你只需要盯着他手里的球一直等他就行。
那么如何判断第一个条件,翻看USART_SR状态寄存器可知,我们需要判断的位为RXNE,当它为1是我们可以读出数据

上代码

当然也可以换成库函数来写

		while((USART_GetFlagStatus(USART1,USART_FLAG_RXNE))==RESET);
		data=USART_ReceiveData(USART1);
		USART1_SendData(data);

验证一下
此处有一个问题,如果while(1)里面接收代码下有大量代码的话,会造成数据丢失,因为发送一位数据需要1/波特率秒,这个速度是很快的,但是你接收一位之后还要运行大量代码,这时候后续的数据已经过来了,过来的数据无法接收造成丢失。但是我们一个工程不可能只接受数据,这是不允许的,所以要用到中断来接收。中断在其他文章中再叙述。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32串口通信USART1配置与使用指南

发表评论