【STM32】HAL库点灯
- 一、探究目标
- 二、探究原理
-
- [2.1 ST开发库](#2.1 ST开发库)
- [2.1.1 直接配置寄存器](#2.1.1 直接配置寄存器)
- [2.1.2 标准外设库](#2.1.2 标准外设库)
- [2.1.3 HAL库](#2.1.3 HAL库)
- [2.2 HAL开发](#2.2 HAL开发)
-
- [2.2.1 环境配置](#2.2.1 环境配置)
- [2.2.2 时钟配置](#2.2.2 时钟配置)
- [2.2.3 GPIO配置](#2.2.3 GPIO配置)
- [2.2.4 工程创建](#2.2.4 工程创建)
- [2.2.5 KEIL代码![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bf1c95d5c6724a6a9eb4a5a1d4fb65a8.png)](#2.2.5 KEIL代码)
- [2.2.6 注意:加入核心文件stm32f10x_md.s](#2.2.6 注意:加入核心文件stm32f10x_md.s)
- [2.3 GPIO函数](#2.3 GPIO函数)
- 三、代码实现
-
- [3.1 实验一](#3.1 实验一)
-
- [3.1.1 CubeMX配置](#3.1.1 CubeMX配置)
- [3.1.2 KEIL代码](#3.1.2 KEIL代码)
- [3.2 实验二](#3.2 实验二)
-
- [3.2.1 CubeMX配置](#3.2.1 CubeMX配置)
- [3.2.2 KEIL代码](#3.2.2 KEIL代码)
- [3.3 KEIL仿真](#3.3 KEIL仿真)
- 四、探究总结
一、探究目标
-
了解并掌握HAL库函数开发方法。安装 stm32CubeMX,配合Keil,使用HAL库方式完成下列任务:
1)重做上一个LED流水灯作业,用GPIO端口完成2只LED灯的周期闪烁。
2)接上,再用GPIO端某一管脚接2个开关(用杜邦线模拟代替)。采用中断模式编程,当2分开关接高电平时,对应的两个LED灯停止工作(即停止周期性闪烁),接低电平时,恢复工作。
-
在没有示波器条件下,使用Keil的软件仿真逻辑分析仪功能观察LED管脚的时序波形,分析上面作业按键中断时,LED灯的波形变化情况。
二、探究原理
2.1 ST开发库
ST 为开发者提供了非常方便的开发库,有标准外设库(SPL库)、HAL 库(Hardware Abstraction Layer,硬件抽象层库)、LL 库(Low-Layer,底层库)三种。前者是ST的老库已经停更了,后两者是ST现在主推的开发库。
我们之前所使用的寄存器开发是最底层的开发方法,开发者可以参照ST公司的数据手册迅速上手。HAL库和LL
2.1.1 直接配置寄存器
我们之前所使用的寄存器开发是最底层的开发方法。在之前学习51的过程中,我们是通过汇编语言直接操作寄存器实现功能的,而这种方法到了STM32就不太容易行得通了,因为STM32的寄存器数量是51单片机的十数倍,如此多的寄存器根本无法全部记忆,开发时需要经常的翻查芯片的数据手册,此时直接操作寄存器就变得非常的费力了。
但直接操作寄存器的方法更接近原理,而且适用性更广泛,只要拥有数据手册,什么芯片都可以直接上手。
2.1.2 标准外设库
ST公司为每款芯片都编写了一份库文件,也就是工程文件里stm32F1xx...之类的。在使用过程中我们只需要配置结构体变量成员就可以修改外设的配置寄存器,从而选择不同的功能。
标准库同时也是目前最多人使用的方式,很多人的STM32启蒙------江协科技也是用到标准库教学的。
2.1.3 HAL库
HAL(Hardware Abstraction Layer,抽象印象层)库是ST公司目前主力推的开发方式。使用ST公司研发的STMcube软件,可以通过图形化的配置功能,直接生成整个使用HAL库的工程文件,而无需像标准库那样配置文件,可以说是方便至极。
2.2 HAL开发
2.2.1 环境配置
环境配置可参考博客STM32_Cube MX配置及使用HAL库
2.2.2 时钟配置
在方框内输入72,回车确认。
2.2.3 GPIO配置
由于我们LED所接引脚为PB9,因此我们需要将PB9引脚初始化为高电平输出,即High。
2.2.4 工程创建
Generate后工程就创建成功啦,此时我们只需要open project就可以打开KEIL工程了。
2.2.5 KEIL代码
在敲代码的时候要注意,要把代码卸载BEGIN和END之间,写在外面的会在你操作cube生成代码的时候被清理掉。
c
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
一个简简单单的LED灯闪烁就这样写好了。
2.2.6 注意:加入核心文件stm32f10x_md.s
我们可以将之前标准库文件中的md.s文件复制粘贴到Drivers中,但是注意:如果更改cubeMX并generate文件都会把这个清除,需要重新添加。
2.3 GPIO函数
- HAL_GPIO_WritePin函数:写入引脚高低电平
c
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_PIN_ACTION(PinState));
if (PinState != GPIO_PIN_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;
}
}
- HAL_GPIO_TogglePin函数:引脚电平翻转
c
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
uint32_t odr;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
/* get current Output Data Register value */
odr = GPIOx->ODR;
/* Set selected pins that were at low level, and reset ones that were high */
GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
}
三、代码实现
3.1 实验一
用GPIO端口完成2只LED灯的周期闪烁。
这里用PB8、PB9输出。
3.1.1 CubeMX配置
按照2.2的步骤操作配置好时钟后,在GPIO选择我们需要的引脚PB8、PB9。
初始化后我们可以观察到,生成的gpio.c文件中,有如上代码。
3.1.2 KEIL代码
想要实现LED1、LED2周期闪烁,我们可以用翻转电平操作。
由于初始LED1(PB9)高电平熄灭,LED2(LED8)低电平点亮。
加入延时函数,让二者电平翻转。
c
while (1)
{
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
3.2 实验二
再用GPIO端某一管脚接2个开关(用杜邦线模拟代替)。采用中断模式编程,当2分开关接高电平时,对应的两个LED灯停止工作(即停止周期性闪烁),接低电平时,恢复工作。
3.2.1 CubeMX配置
配置输入,假如两个开关分别连引脚PA5\PA6。
将PA5、PA6选择为GPIO_Input模式。
3.2.2 KEIL代码
开关接高电平时LED灭,低电平时LED亮。
因此我们需要用到HAL_GPIO_ReadPin函数读取开关的输入电平。
c
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
GPIO_PinState bitstatus;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
{
bitstatus = GPIO_PIN_SET;
}
else
{
bitstatus = GPIO_PIN_RESET;
}
return bitstatus;
}
因此主函数的代码写简单几句就能实现。
c
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define KEY1_State HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)
#define KEY2_State HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)
/* USER CODE END PD */
c
/* USER CODE BEGIN WHILE */
while (1)
{
if(KEY1_State==GPIO_PIN_RESET){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
}
if(KEY2_State==GPIO_PIN_SET){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
/* USER CODE END WHILE */
3.3 KEIL仿真
四、探究总结
HAL库开发只要熟悉函数,很容易就能进行开发。但是HAL库的覆盖程度有限,有些芯片并没有HAL库,因此掌握寄存器开发和标准库开发还是很有必要的。
以上则是我本次探究的全部内容,如有错漏请在评论区指正。