stm32 hal uart_Stm32HAL库开发(4.2) UART串口通信轮询方式

摘要:本期推送介绍使用 如何HAL库操作Stm32的UART功能,本文内容对应《Mastering Stm32》8.2、8.3节内容,将介绍UART的初始化以及使用轮询模式发送接收数据,并以如下图的结构展开。

9ba3caa6571f684a48b96bf42dcd1be7.png

fabacdcbc8d58f14a1404e7e107abda4.png

1

HAL库中UART相关结构体的内容

本小节参考《description-of-stm32f0-hal-and-lowlayer-drivers-stmicroelectronics》、《STM32F051x 参考手册中文》。

64dc2f23588fbfe5292e79e196d67896.png

UART的结构体有两个,如图,UART_InitTypeDef是初始化结构体,包含UART开始运行时的配置;UART_HandleTypeDef是句柄结构体,包含UART所有运行时的信息。

c5ec9a455d86afc498bc050d3ab959b1.png

UART_InitTypeDef初始化结构体中包含,波特率、帧的字长、停止位长度、奇偶校验方式、工作模式、硬件流模式和过(超)采样率设置。

64688bab2039190464af800e7cc82782.png

其中过采样的目的类似于一种低通滤波,Stm32通过对一帧进行16次或者8次采样,并对采样结果进行“多数票决”来判断该帧为起始位或是数据位的0或1。详见《STM32F051x 参考手册中文》573页。

7c68739feead55d0f34fca9844f7035e.png

硬件流控制是通过硬件对UART传输进行更精细的控制的手段。UART传输中,Stm32通过nCTS端口读取对方的nRTS端口电平,获知对方是否准备好接受新的数据,这种操作可以避免数据寄存器中未被读出的旧数据被新数据刷新掉的情况发生。详见《STM32F051x 参考手册中文》604页。

0bd5d002062cb377680bd13db99f7eec.png

UART_HandleTypeDef是UART句柄结构体,包含了UART运行过程中HAL层的所有信息。 2

UART初始化三步

在介绍Stm32的HAL初始化UART之前,我们先看一下Arduino怎么初始化UART的。

67ae03bdd758d7a4ccb73df4e73970f5.png

Arduino使用非常简便的一句话,Serial.begin(波特率); 来初始化UART,这一句话包含了三个内容:
  • UART对象——其代表我们要使用的UART外设;

  • UART启动——其代表根据UART参数启动串口;

  • UART参数——其代表UART以何种配置运行;

d2a609cf989cb550e77f4f76fac259e3.png

Stm32的HAL初始化过程也可以进行类比:

4ae2a5485ef81655112ea298d0324079.png

我们还可以用填表格来理解这三步操作:

8770d391a6ef78f473004a234a080419.png

2.1 Step1-申明结构体变量-生成表格

dda740725a39397987b7e20fb0cccd34.png

申明一个UART_HandleTypeDef的结构体变量,图中的结构体是在main函数中声明,推荐在main.c的头部申明结构体,使其成为全局变量。

8ef485aa5fac43fc26eeb4e0e84e5df4.png

2.2 Step2-配置UART参数-填写表格 配置UART参数参数包括两步:

6a1046268001b5e5e48f020b1069b8e6.png

第一步是要给UART_HandleTypeDef结构体变量赋值

  • 将我们要使用的外设赋值给其instance字段。

  • 将波特率、帧长度等配合赋值给其UART_InitTypeDef初始化结构体变量的相应字段。

ca70f75a8c5467513da34e96ef1cd7b2.png

第二步是要配置与所使用的UART连接的GPIO口,因为任何外设想与外界交换数据都需要正确的和使用的GPIO进行绑定。

在还未介绍的Step3中,我们需要调用HAL_UART_Init()初始化UART,HAL_UART_Init()又会调用HAL_UART_MspInit()对于单片机的Msp( MCU Specific Package 单片机的具体方案 )进行配置,这里Msp就指具体配置哪个IO与UART进行连接。 在HAL_UART_MspInit()中配置GPIO又需要进行如下两步操作: 1. 定义GPIO_InitTypeDef初始化结构体变量作为所要初始化GPIO的配置的“暂存”。 93dfbf92713cf319805e0a5d4a0409c1.png 2. 然后判断此次调用HAL_UART_MspInit()函数的UART外设,根据不同的UART外设对于相应的GPIO和时钟进行如下操作:
  • 启动所用UART外设的时钟。

  • 启用所用GPIO的时钟。

  • 配置GPIO_InitTypeDef初始化结构体变量(变量值如上图)。

  • 使用初始化函数初始化GPIO。

    44384206307077d3e9130516f40dd8ed.png

2.3Step3-使用函数初始化UART-提交表格 e91b8d049d0a74ddfec5dc05d990e4b0.png

完成了UART的参数配置和IO配置之后,我们需要使用HAL_UART_Init()函数提交之前配置好的UART_HandleTypeDef结构体变量这个“表格”,使得Stm32按照我们的参数配置、IO配置启动。

3

使用轮询模式

fabacdcbc8d58f14a1404e7e107abda4.png

3.1 UART通信的三种模式 UART通信有三种模式,分别为轮询模式、中断模式、DMA模式,本小节介绍轮询模式通信。 如果读者学过8位单片机的底层开发,应该能理解轮询模式和中断模式的区别以及中断模式比轮询模式在单片机任务较多时更为高效的原因。 《Mastering Stm32》一书的248页也对两者的区别进行了阐述:

54c6dfa3e54a48bd35984928cc56cfe7.png

简单来说,轮询模式是内核在规定的阻塞时间内使用while循环读取传输的标志位,直到标志位被置位才将数据写入或读出DR寄存器。 而中断模式是传输完成的相关中断发生时,内核才放下手中的工作,将数据写入或读出DR寄存器。少了阻塞时间内的循环读取因此更高效。 而DMA模式则更为高效,DMA作为内核的二弟,当传输完成中断发生时,帮助大哥将数据写入或读出DR寄存器,不需要打断大哥-内核的工作。3.2轮询模式

45c2f1eab928b3b0b93fd2cde5c1a22e.png

在轮询模式发送数据调用函数HAL_UART_Transmit() ,接收数据调用函数HAL_UART_Receive(),两者的传入参数列表,以及返回值意义相同,如下图,摘自《description-of-stm32f0-hal-and-lowlayer-drivers-stmicroelectronics》P572页。

73b8d58cbe52c7f52edc9af89ffabd61.png

下面演示两个函数的几种调用案例:

/* 发送字符数组 */  char buff[2] = {'a','b'};  HAL_UART_Transmit(&huart3,(uint8_t *)buff,                      sizeof(buff),HAL_MAX_DELAY);
/* 发送字符串 */  HAL_UART_Transmit(&huart3, (uint8_t*)"Hello",                       strlen("Hello"),HAL_MAX_DELAY);
/* 接受字符数组 */  char readBuf[1];  HAL_UART_Receive(&huart2, (uint8_t*)readBuf, 1, HAL_MAX_DELAY);

至此本文已经完成了对于Stm32使用HAL初始化UART,以及在轮询模式通信方法的阐述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值