文章目录
本章介绍如何使用
STM32F429
的串口来发送和接收数据。本章将实现如下功能:
STM32F429
通过串口和上位机的对话,
STM32F429
在收到上位机发过来的字符串后,原原本本的返回给上位机。
一、串行通信基本原理
1.串行通信接口背景知识
处理器与外部设备通信有两种方式:
- 并行通信
- 传输原理:数据各个位同时传输。
- 优点:速度快
- 缺点:占用引脚资源多
- 串行通信
- 传输原理:数据按位顺序传输。
- 优点:占用引脚资源少
- 缺点:速度相对较慢
串行通信按照数据传送方向,分为:
- 单工
数据传输只支持数据在一个方向上传输 - 半双工
允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信 - 全双工
允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
串行通信的三种传送方式如下:
串行通信按照通信方式来分
- 同步通信:带时钟同步信号传输
SPI
,IIC
通信接口
- 异步通信:不带时钟同步信号
UART
(通用异步收发器),单总线
常见的串行通信接口为
2.异步串口通信UART知识
异步通信UART
包含三点知识:
- 物理层(电气层:接口决定):通信接口(
RS232
,RS485
,RS422
,TTL
) - 数据格式(数据层:芯片决定)
- 通信协议(协议层:程序决定)
UART
异步通信方式引脚连接方法:
RXD
:数据输入引脚。数据接受。TXD
:数据发送引脚。数据发送。
接口类型如下:
STM32 UART
异步通信方式引脚:
查看芯片数据手册引脚功能表可得:
PA9
与PA10
可做串口1的发送和接受引脚;PB10
和PB11
可做串口3的发送和接受引脚。
3.STM32串口数据格式和通信过程
STM32
串口异步通信需要定义的参数:
- 起始位:1个逻辑0数据位开始
- 数据位(8位或者9位)
- 奇偶校验位(第9位)
- 停止位(1,1.5,2位)
- 波特率设置
STM32
串口通信过程如下:
4.STM32串口框图
由图中可以看出:
- 发送端与接收端共用一个波特率,即确定串行通信的速度
USART_BRR
为分数波特率发生器
5.波特率计算方法
波特率计算在串口框图如下部分:
OVER8
由控制寄存器USART_CR1
中的位15来控制。
波特率的计算公式如下:
OVER8=0
时波特率计算公式:
T x / R x 波 特 率 = f P C L K x 16 ∗ U S A R T D I V Tx/Rx波特率=\frac{f_{PCLKx}}{16*USARTDIV} Tx/Rx波特率=16∗USARTDIVfPCLKx
- 根据波特率和串口时钟频率,计算出
USARTDIV
的值。 DIV_Fraction=USART的小数部分 X16所得的整数
DIV_Mantissa=USART的整数部分
那么,假如串口时钟为90M,需要得到115200的波特率;则
二、STM32F429 串口简介
STM32F429
的串口资源相当丰富的,功能也相当强劲。ALIENTEK
阿波罗 STM32F429
开发板所使用的 STM32F429IGT6
最多可提供 8 路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持 LIN
、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC
规范、具有 DMA
等。
阿波罗 STM32F429
开发板板载了 1 个 USB
串口和 2 个 RS232
串口,我们本章介绍的是通过 USB
串口和电脑通信。
串口最基本的设置,就是波特率的设置。STM32F429
的串口使用起来还是蛮简单的,只要你开启了串口时钟,并设置相应 IO
口的模式,然后配置一下波特率,数据位长度,奇偶校验位等信息,就可以使用了。下面介绍几个与串口基本配置直接相关的寄存器。
-
串口时钟使能。串口作为
STM32F429
的一个外设,其时钟由外设时钟使能寄存器控制,这里我们使用的串口 1 是在APB2ENR
寄存器的第 4 位。APB2ENR
寄存器在之前已经介绍过了,这里不再介绍。只是说明一点,就是除了串口 1 和串口 6 的时钟使能在APB2ENR
寄存器,其他串口的时钟使能位都在APB1ENR
寄存器。 -
串口波特率设置。每个串口都有一个自己独立的波特率寄存器
USART_BRR
,通过设置该寄存器就可以达到配置不同波特率的目的。 -
串口控制。
STM32F429
的每个串口都有 3 个控制寄存器USART_CR1~3
,串口的很多配置都是通过这 3 个寄存器来设置的。这里我们只要用到USART_CR1
就可以实现我们的功能了,该寄存器的各位描述如图所示:
该寄存器的高16位没有用到,低16位用于串口的功能设置。OVER8
为过采样模式设置位,我们一般设置位 0,即 16 倍过采样已获得更好的容错性;UE
为串口使能位,通过该位置 1,以使能串口;M
为字长选择位,当该位为 0 的时候设置串口为 8 个字长外加 n 个停止位,停止位的个数(n
)是根据USART_CR2
的[13:12]
位设置来决定的,默认为 0;PCE
为校验使能位,设置为 0,则禁止校验,否则使能校验;PS
为校验位选择位,设置为 0 则为偶校验,否则为奇校验;TXEIE
为发送缓冲区空中断使能位,设置该位为 1,当USART_SR
中的TXE
位为 1 时,将产生串口中断;TCIE
为发送完成中断使能位,设置该位为 1,当USART_SR
中的TC
位为 1 时,将产生串口中断;RXNEIE
为接收缓冲区非空中断使能,设置该位为 1,当USART_SR
中的ORE
或者RXNE
位为 1 时,将产生串口中断;TE
为发送使能位,设置为 1,将开启串口的发送功能;RE
为接收使能位,用法同 TE。
-
数据发送与接收。
STM32F429
的发送与接收是通过数据寄存器USART_DR
来实现的,这是一个双寄存器,包含了TDR
和RDR
。当向DR
寄存器写数据的时候,实际是写入TDR
,串口就会自动发送数据;当收到数据,读DR
寄存器的时候,实际读取的是RDR
。TDR
和RDR
对外是不可见的,所以,我们操作的就只有DR
寄存器,该寄存器的各位描述如图所示:
可以看出,虽然是一个 32 位寄存器,但是只用了低 9 位(DR[8:0]
),其他都是保留。DR[8:0]
为串口数据,包含了发送或接收的数据。由于它是由两个寄存器(TDR
和RDR
)组成的,一个给发送用(TDR
),一个给接收用(RDR
),该寄存器兼具读和写的功能。TDR
寄存器提供了内部总线和输出移位寄存器之间的并行接口。RDR
寄存器提供了输入移位寄存器和内部总线之间的并行接口。当使能校验位(USART_CR1
中PCE
位被置位)进行发送时,写到MSB
的值(根据数据的长度不同,MSB
是第 7 位或者第 8 位)会被后来的校验位取代。当使能校验位进行接收时,读到的MSB
位是接收到的校验位。 -
串口状态。串口的状态可以通过状态寄存器
USART_SR
读取。USART_SR
的各位描述如图所示:
这里我们关注一下两个位,第 5、6 位RXNE
和TC
。RXNE
(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取USART_DR
,通过读USART_DR
可以将该位清零,也可以向该位写 0,直接清除。TC
(发送完成),当该位被置位的时候,表示USART_DR
内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:- 读
USART_SR
,写USART_DR
- 直接向该位写 0。
- 读
通过以上一些寄存器的操作外加
IO
口的配置,我们就可以达到串口最基本的配置了。
串口字节的发送流程如下:
- 编程
USARTx_CR1
的M
位来定义字长。 - 编程
USARTx_CR2
的STOP
位来定义停止位位数。 - 编程
USARTx_BRR
寄存器确定波特率。 - 使能
USARTx_CR1
的UE
位使能USARTX
。 - 如果进行多缓冲通信,配置
USARTx_CR3
的DMA
使能DMAT
。 - 使能
USARTx_CR1
的TE
位使能发送器。 - 向发送数据寄存器
TDR
写入要发送的数据(对于M3
,发送和接收共用DR
寄存器)。 - 向
TRD
寄存器写入最后一个数据后,等待状态寄存器USARTx_SR(ISR)
的TC
位置1,传输完成。
上面是基于寄存器进行描述的。接下来,使用HAL
库实现串口发送程序配置:
- 初始化串口相关参数使能串口:
HAL UART Init();
- 串口相关
IO
口配置,复用配置:在HAL_UART_MspInit
中调用HAL GPIO Init
函数。 - 发送数据并等待数据发送完成:
HAL_UART_Transmit()
函数;
串口接收流程如下:
- 编程
USARTx_CR1
的M
位来定义字长。 - 编程
USARTx_CR2
的STOP
位来定义停止位位数。 - 编程
USARTx_BRR
寄存器确定波特率。 - 使能
USARTx_CR1
的UE
位使能USARTX
。 - 如果进行多缓冲通信,配置
USARTx_CR3
的DMA
使能DMAT
。 - 使能
USARTx_CR1
的RE
位为1使能接收器。 - 如果要使能接收中断(接收到数据后产生中断),使能
USARTx_CR1
的RXNEIE
位为1。
当串口接收到数据时:
USARTx_SR(ISR)
的RXNE
位置1。表明移位寄存器内容已经传输到RDR(DR)
寄存器。已经接收到数据并且等待读取。- 如果开启了接收数据中断(
USARTx_CR1
寄存器的RXNEIE
位为1),则会产生中断。(程序上会执行中断服务函数) - 如果开启了其他中断(帧错误等),相应标志位会置1。
- 读取
USARTx_RDR(DR)
寄存器的值,该操作会自动将RXNE
位清零,等待下次接收后置位。
接收数据过程:
-
步骤1获取状态标志位通过标识符实现:
__HAL_UART_GET_FLAG //判断状态标志位 __HAL_UART_GET_IT_SOURCE //判断中断标志位
-
步骤2-3中断服务函数:
void USARTx_IRQHandler(void) ;//(x=1~3,6) void USARTx_IRQHandler(void) ;//(x=4,5,7,8)
-
步骤4读取接收数据
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
接下来,使用HAL
库实现串口接收中断程序配置:
-
初始化串口相关参数,使能串口:
HAL_UART_Init();
-
串口相关
IO
口配置,复用配置:在HAL_UART_MspInit
中调用HAL_GPIO_Init
函数。 -
串口接收中断优先级配置和使能:
HAL_NVIC_EnableIRQ(); HAL_NVIC_SetPriority();
-
使能串口接收中断:
HAL_UART_Receive_IT();
-
编写中断服务函数:
USARTx_IRQHandler
接下来使用 HAL
库实现串口配置和使用的方法。在 HAL
库中,串口相关的函数和定义主要在文件 stm32f4xx_hal_uart.c
和 stm32f4xx_hal_uart.h
中。接下来我们看看 HAL
库提供的串口相关操作函数。
-
串口参数初始化(波特率/停止位等),并使能串口。
串口作为STM32
的一个外设,HAL
库为其配置了串口初始化函数。串口初始化函数HAL_UART_Init
定义如下:HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);</