STM32 HAL库

前言

这篇文章个人对WUT-电子科技协会的hal库学习视频的学习笔记,里面理论部分来自于文档“我的19岁-电子设计大赛”。
最开始通过一些示例来熟练上手HAL库

两个实例

CubeMX点亮LED

先以管理员身份运行CubeMX
在这里插入图片描述
点击New Project
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击GPIO_Output
在这里插入图片描述
然后点击Project Manager
在这里插入图片描述
配置好后,点击Code Generator
在这里插入图片描述
配置好后,点击Adcanced Settings
在这里插入图片描述
然后点击GENERATE CODE
然后关闭CubeMX
在这里插入图片描述
按照此路径打开文件(按照自己保存的路径打开)
在这里插入图片描述
在main.c里面的while(1)写入代码,实现led闪烁。

按键实现led关灭

  • 按下按键:Input
  • 点亮LED灯:Output
  • 0.5s:延时的过程
  • 熄灭:Output

CubeMX配置

虽然输出引脚比输入引脚多了更多的配置,但是目前需要你修改的就是GPIO Pull-up/Pull-down。(见后面的GPIO中的配置引脚)
在这里插入图片描述
点击System view
在这里插入图片描述
再点击GPIO
在这里插入图片描述
把led那个引脚配置成一开始就是高电平,上拉模式
在这里插入图片描述
按键那个引脚配置成上拉模式

最后生成代码

keil中的配置

1.输入模式下
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); //读取PA0引脚状态

2.输出模式下
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//将引脚状态改为低电平
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//将引脚状态改成高电平

按键实现 led关灭的主函数代码如下

最终主函数的代码如下

while (1)
  {
  	//为了代码的可读性,读取引脚一般不写0,写GPIO_PIN_RESET
	  if(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
	  {
		  while(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)//按键检测
			  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
	  }
	  HAL_Delay (500);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);	  
  }

GPIO

理论相关部分

GPIO 8种工作模式

1.GPIO_Mode_AIN 模拟输入
2.GPIO_Mode_IN_FLOATING 浮空输入
3.GPIO_Mode_IPD 下拉输入
4.GPIO_Mode_IPU 上拉输入
5.GPIO_Mode_Out_OD 开漏输出
6.GPIO_Mode_Out_PP 推挽输出
7.GPIO_Mode_AF_OD 复用开漏输出
8.GPIO_Mode_AF_PP 复用推挽输出

各个模式应用总结

  • 上拉输入、下拉输入可以用来检测外部信号;例如,按键等;
  • 浮空输入模式,由于输入阻抗较大,一般把这种模式用于标准通信协议的 I2C、USART 的接收端;
  • 普通推挽输出模式一般应用在输出电平为 0 和 3.3V 的场合。而普通开漏输出模式一般应用在电平不匹配的场合,如需要输出 5V 的高电平,就需要在外部一个上拉电阻,电源为 5V,把 GPIO 设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出 5V 电平。
  • 对于相应的复用模式(复用输出来源片上外设),则是根据 GPIO 的复用功能来选择,如 GPIO 的引脚用作串口的输出(USART/SPI/CAN),则使用复用推挽输出模式。如果用在 I2C、SMBUS 这些需要线与功能的复用场合,就使用复用开漏模式。
  • 在使用任何一种开漏模式时,都需要接上拉电阻。

Cube MX相关配置

选择引脚类型

GPIO_Input 输入引脚
GPIO_Output 输出引脚

配置引脚
  • 输入引脚

对于输入引脚,可以配置的就是GPIO Pull-up/Pull-down。这分别对应的就是Pull-up(输入上拉)与Pull-down(输入下拉)。

Pull-up:输入上拉就是把点位拉高,比如拉到Vcc,上拉就是将不确定的信号通过一个电阻嵌位在高电平。电阻同时起到限流的作用。弱强只是上拉电阻的阻值不同,没有什么严格区分。

Pull-up:输入下拉就是把电压拉低,拉到GND。与上拉原理相似。

简单的说,如果你希望你的引脚平时处于高电平用于检测低电平,你就使用Pull-up,如果你希望你的引脚平时处于低电平用于检测高电平,你就使用Pull-down。

  • 输出引脚

对于输出引脚,比输入多了更多的配置:
GPIO output level -> 初始化输出电平
GPIO mode -> 输出方式 -> 开漏或推挽输出
GPIO Pull-up/Pull-down -> 上拉或下拉输出
Maximum output speed 选中 GPIO 管脚的速率

选中GPIO管脚的速率:
I/O 口的输出模式下,有 3 种输出速度可选 (Low - 2MHz、Medium - 10MHz、High -50MHz),这个速度是指 I/O 口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在 I/O 口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的 EMI 性能。当然如果要输出较高频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。

举个例子:
1.USART 串口,若最大波特率只需 115.2k,那用 2M 的速度就够了,既省电也噪声小。
2.I2C 接口,若使用 400k 波特率,若想把余量留大些,可以选用 10M 的 GPIO 引脚速度。
3.SPI 接口,若使用 18M 或 9M 波特率,需要选用 50M 的 GPIO 的引脚速度。

keil中的代码

初始化及重置相关

在这里插入图片描述

IO口操作相关

在这里插入图片描述
同时HAL库帮我们定义好了GPIO_PIN_RESET与GPIO_PIN_SET,代表着0(低电平)、1(高电平)。

User Label

对于任意引脚,它都有这么一个选项。我想告诉你这个选项特别特别好用!这个选项简单的说就是它帮你在 main.h 中生成 define 语句。但是对于 HAL 库编程,main.h 会被用户的每个模块调用,也就是这些 define 语句的作用域几乎是全局。

举个例子让你感受一下,在一次开发中,我使用 PA0 来作为输出引脚。如果随着开发的继续 PA0 被迫要用于其他功能,那么你该怎么办?那你必须使用另外一个引脚(假设是 PB1)来替代它。如果你没有配置 User Label 选项,那你的代码中可能大量的充斥着
在这里插入图片描述
然后你又需要用 PB1 来代替 PA0,那你就需要将整个代码中有关 PA0 的 GPIOA 改成 GPIOB,将 GPIO_PIN_0 改成 GPIO_PIN_1。这会导致巨大的工作量,并且容易出错。

那么我们来看看使用了 User Label 会带来什么变化,使用 User Label 把他取名 R1。那你的代码中充斥着的不在是
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET),
而是HAL_GPIO_WritePin(R1_GPIO_Port, R1_Pin, GPIO_PIN_RESET)。
当遇到 PA0 被迫要用于其他功能,你只需要把 PB1 的 User Label 取名为 R1 后,代码不需要做丝毫改变。

在这位大佬的开发中,这个应用最典型的两个例子就是“矩阵键盘”和“ADS1256”的开发。用矩阵键盘来举例,需要用到 8 个引脚。
在这里插入图片描述
矩阵键盘中的代码全是由 R1-R4、C1-C4 组成,所以在各这个代码的复用性极其强,无论是换引脚还是换单片机型号,他只需要在 Cube MX 中配置一下,就可以马上投入使用。
在这里插入图片描述

实际操作(个人在CubeMX上的操作)

  • 使用User Label去命名PA1,使得按键的代码可以被复用
    在这里插入图片描述
  • 使用User Label去命名PA2,使得led的代码可以被复用
    在这里插入图片描述
  • 此时在keil工程的main.h里面,可以看到我们自己配置的User Label

在这里插入图片描述

  • 接着写main.c里面的代码
    在这里插入图片描述

在写函数里面的参数的时候,只要写入自己之前设定的名称Key1,就会自动检索出全称Key1_GPIO_Port与Key1_Pin,不需要一直去翻main.h。用起来确实非常方便。

接着需要更改引脚的时候,只需要在CubeMX里面配置好更改的引脚,将需要更改的引脚的User Label更改成Key1,然后直接从这边把代码拷贝过去就可以用了。

串口通信

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。

理论相关部分

UART与USART

  • UART: 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作 UART。它将要传输的资料在串行通信与并行通信之间加以转换。作为把并行输入信号转成串行输出信号的芯片,UART 通常被集成于其他通讯接口的连结上。
  • USART:(Universal Synchronous/Asynchronous Receiver/Transmitter) 通用同步/异步串行接收/发送器,USART 是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。

CubeMX相关配置

初始化引脚

Mode:
1.Asynchronous : 异步, 整个过程,不会阻碍发送者的工作。
2.Synchronous : 同步, 同步信息一旦发送,发送者必须等到应答,才能继续后续的行为。
3.Single Wire : 单总线, 半双工。

配置引脚
  • Baud Rate: 波特率, 波特率表示每秒钟传送的码元符号的个数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示。对于串口最重要的就是波特率, 常用的波特率为 115200 与 9600。
  • Wrod Length : 数据长
  • Parity : 奇偶校验 -> 无、奇校验、偶校验
  • Stop : 停止位

以上的配置与需要通信双方完全配对

编写keil中的代码

在这里插入图片描述
就大佬目前的学习来看,HAL并没有对同步通信的方式做拓展,所以上述都是关于UART的函数。

printf重定向

在Private includes中引入:
在这里插入图片描述
在 USER CODE BEGIN 0 添加:
在这里插入图片描述
然后你就可以在任意地方使用printf语句方便的输出你想要的内容了。

注意,这一步要在keil里面勾上Options for Target -> Target ->勾选Use MicroLIB

Log信息格式

格式1

参考目前主流嵌入式、安卓等输出方式
在这里插入图片描述

格式2

参考Java日志框架的输出方式:
在这里插入图片描述

条件编译

因为在进行单片机开发的过程中,会需要大量的 Log 信息,但是在开发结束时,你又不想它一直打印(这会拖慢单片机的速度)。所以大佬提出了他的办法:

在头文件中添加:
在这里插入图片描述
再把.c文件中将所有的printf包裹上 #if Log与 #endif:
在这里插入图片描述
在这里插入图片描述

可变参数宏

关于这个内容,是大佬在阅读国内某云物联网模块源码时发现并学习的
在这里插入图片描述
大佬觉得这个解决方案比之前提到的条件编译强100倍,甚至让大佬觉得以前的做法多么的愚蠢。这种方法不仅达到了代码的格式化,同时也完成了条件编译。

大佬的设计:
在这里插入图片描述
当需要打印串口信息的时候,define一个USER_MAIN_DEBUG,在不需要的时候将其注释

个性化输出

1.借助下面的网站设计自己的字符
http://patorjk.com/software/taag/
在这里插入图片描述
2.编写代码
先逐行复制输入
在这里插入图片描述
再用转义字符修补错误
在这里插入图片描述
3.串口助手看效果
在这里插入图片描述

串口中断

1.CubeMX中开启中断
在这里插入图片描述
2.在USER CODE BEGIN 2中打开串口中断
在这里插入图片描述
3.在USER CODE BEGIN 4中实现回调函数
在这里插入图片描述

实际操作(个人在CubeMX上的操作)

配置USART

  • 其中一种是直接在引脚上找USART1的串口
    在这里插入图片描述
    能用作USART通信的串口,在点击后是可以看到的。
  • 如果不想配置这个引脚了,可以点击Reset_State
    在这里插入图片描述
  • 接着点那两个三角尖,可以开始配置USART,或者也会自动弹出让你配置
    在这里插入图片描述
  • 然后可以直接进行配置,配置波特率,停止位,长度等等
    在这里插入图片描述
  • 接着是keil里面的代码
    在这里插入图片描述

这里面的&huart1是在usart里面找到的,跳转HAL_UART_Transmit这个函数的定义就可以知道为什么是&huart1了

在这里插入图片描述
在这里插入图片描述
第二个参数是需要传输的字符,第三个参数是传输的长度,第四个是传输时间,这个一般非常快,所以给个50就行。

  • 接着是在CubeMX配置时,直接去检索适合USART通信的 IO口
    在这里插入图片描述
    点击左边的Connectivity,然后点击需要的串口,比如 USART1,然后再点击上面Mode中选中Asynchronous。

  • 如果我将PA10已经用作GPIO_Output,但是我还需要用USART1,这个时候还是点击Connectivity,然后选中USART1,点击Mode中的Asynchronous,再点击下面的GPIO Settings,可以看到,CubeMX自动帮我们复用好了GPIO口
    在这里插入图片描述
    这就更方便了,不用我们手动去复用GPIO口,并且可以自动检索我们需要的GPIO口。

外部中断

理论相关部分

CubeMX相关配置

初始化引脚

如果你想使用 PA1 作为外部中断的接收引脚,那么你只需要点击 PA1,在点击它对应的 GPIO_EXTIx。
在这里插入图片描述

使能中断

在这里插入图片描述

配置引脚

这个地方不同于之前的GPIO mode
在这里插入图片描述
在这里插入图片描述

编写keil代码

在 main.c 中的 USER CODE BEGIN 4 编程范围内添加外部中断的回调函数:
在这里插入图片描述

测量pwm频率

当有上升沿的时候,就进入外部中断将 pwm_value 的值 +1。it is clear that “1s 钟上升沿的次数就是 pwm 的频率”。所以当我要用 pwm 的频率时,我就先将 pwm_value 置 0,再延时 1s,最后再使用 pwm_value。当然这并不是最终的代码,因为你读到这里还有很多的内容没有学习, 往后的定时器章节将介绍它的滤波算法。
在这里插入图片描述

实际操作(个人在CubeMX上的操作)

  • 这次用的时f4系列的作为实际操作,选好要作为中断的引脚,然后点击System view,然后点击NVIC,然后勾选中断。
    在这里插入图片描述
  • 接着配置GPIO,点击System view,选择GPIO,然后配置GPIO
    在这里插入图片描述
    然后生成项目
  • 中断这里的函数
    在这里插入图片描述
  • 主函数这里的函数
    在这里插入图片描述
    实现的功能就是,如果接收到中断,单片机发送exti,然后换行。

时钟树

理论相关部分

通常我们会让单片机的频率(决定单片机的处理速度)提到最大,然后再进行其他分频操作。

使能外部时钟源

在这里插入图片描述

将频率调至最大

不同单片机的最大运行频率是不同的,例如stm32f103为72M,而stm32f407为84M。
在这里插入图片描述

按需分频

在这里插入图片描述

定时器

理论相关部分

CubeMX相关配置

配置定时器时钟

如之前所说,将定时器时钟设置为最大,f1系列是72M,f4系列是84M
在这里插入图片描述

选择时钟源

选择内部时钟
在这里插入图片描述

配置定时器

在这里插入图片描述
在这里插入图片描述

开启中断-基本定时器

勾选Enabled框即可
在这里插入图片描述

开启中断-高级定时器

勾选TIM Xupdate interrupt 后的Enabled框即可
在这里插入图片描述

编写keil代码

在这里插入图片描述
在这里插入图片描述

平滑滤波

在这里我想在介绍定时器的另一种用法:平滑滤波。绝大部分人的滤波算法都是用的时候,多次采样再滤波。但是我希望让采样值在另一个“线程”一直滤波,而在我需要他的时候,直接取它的值即可。
在这里插入图片描述
在这里插入图片描述
当我们在任意时刻需要使用pwm的频率时,只需要使用pwm_value_final的值即可。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值