使用HAL库开发STM32(基于F4):概述与常用系统函数说明

目的

使用HAL库开发STM32是目前ST官方主要推荐的方式,本篇文章对HAL做个基础说明。

HAL库概述

STM32F4的HAL库综述在文档《UM1725 - User Manual: Description of STM32F4 HAL and LL drivers》的第二篇章《Overview of HAL drivers》(文档版本DocID025834 Rev 5 ),官方文档本身写得非常详细,这里做下简单梳理。
下文中出现的。

文件说明

库文件

在这里插入图片描述
上图是HAL库文件与引用包含关系,其中 ppp 用来指代外设,例如 gpio uart adc 等,箭头起始文件引用包含了箭头指向的文件,如user file引用了stm32f4xx_hal.h文件。主要文件描述如下:

文件 描述
stm32f4xx_hal_ppp.c
stm32f4xx_hal_ppp.h
外设基本驱动文件
stm32f4xx_hal_ppp_ex.c
stm32f4xx_hal_ppp_ex.h
外设扩展驱动文件
stm32f4xx_hal.c
stm32f4xx_hal.h
包含HAL初始化、DBGMCU、系统时间相关内容
stm32f4xx_hal_def.h 公共枚举与宏定义等资源

用户文件

这里的用户文件指的是使用stm32cube生成的项目所需的文件:

文件 描述
system_stm32f4xx.c 主要包含SystemInit(),用来初始化系统时钟等
startup_stm32f4xx.s 目标芯片启动文件
stm32f4xx_hal_msp.c 外设系统级初始化与反初始化
stm32f4xx_hal_conf.h HAL库配置,用以适配项目
stm32f4xx_it.c
stm32f4xx_it.h
包含项目涉及的中断服务程序
main.c
main.h
包含各类初始化以及用户程序主入口

API

分类与命名

HAL库大多数功能的外设API可以分为两类,Generic和Extension,这点从文档目录和库文件命名上就可以看出。
Generic APIs就是指普通的、通用的API,一般来说这部分API是兼容所有STM32系列芯片的,如果你的项目中只用到这部分API的话那就可以非常方便的更换MCU型号。很多时候我们也只用到这些API就可以完成项目开发了。
Extension APIs指扩展的API,这部分API涉及不同STM32系列MCU差异部分功能的操作,所以并不兼容所有STM32芯片。这部分API细分的话也可以分成两类Family specific APIs(不同系列芯片差异,比如F0、F1、F4等)和Device part number specific APIs(具体不同型号芯片差异,比如F401、F405、F429等)

命名规则见下表:
在这里插入图片描述
HAL库中命名还是挺统一与简单易懂的,比如使用某个GPIO口输出使用,一般就是设置输出电平,就算没有实际用过也能知道相关函数是 HAL_GPIO_xxxxx ,使用UART发送相关函数是 HAL_UART_xxxxx ,配合IDE的代码补全功能开发起来就得心应手:
在这里插入图片描述

基本API说明

功能分类

单个外设的API大体上可以分为四类:

类别 说明 举例
Initialization 初始化与反初始化 HAL_ADC_Init()
IO operation 启动、停止、读写、回调函数等 HAL_ADC_Start ()
HAL_ADC_ConvCpltCallback()
Control 相关参数设置 HAL_ADC_ConfigChannel()
State and Errors 获取状态与错误信息 HAL_ADC_GetState()
HAL_ADC_GetError()

操作模型

对于外设IO中很多耗时操作HAL库提供了三种模型:轮询、中断、DMA。比如串口读写数据就有三类方式:

  • 轮询:HAL_UART_Transmit() & HAL_UART_Receive()
  • 中断:HAL_UART_Transmit_IT() & HAL_UART_Receive_IT()
  • DMA:HAL_UART_Transmit_DMA() & HAL_UART_Receive_DMA()

轮询是一种阻塞的方式、中断和DMA是非阻塞方式(一般结合回调函数一起使用)。对于同一个外设使用时最好不要混用,不然可能会发生不可预知的问题。

扫描二维码关注公众号,回复: 8727462 查看本文章

回调函数

HAL库对很对操作编写了用 __weak 符号修饰的回调函数,用户可以在自己的代码中重新定义该回调函数实现具体功能,比如下面就是串口收发完成的回调函数:
HAL_UART_TxCpltCallback() & HAL_UART_RxCpltCallback()

公共资源

公共资源指全局的宏定义、枚举、结构体等,主要定义在stm32fxxx_hal_def.h文件中。
这里主要提一个HAL Status:

typedef enum 
{
  HAL_OK       = 0x00U,
  HAL_ERROR    = 0x01U,
  HAL_BUSY     = 0x02U,
  HAL_TIMEOUT  = 0x03U
} HAL_StatusTypeDef;

这个枚举类型经常出现在操作设置等的返回值中,比如HAL_StatusTypeDef HAL_UART_Transmit(),写代码时可以通过该状态知道操作是否成功等。

常用系统函数

STM32F4的HAL库系统函数介绍在文档《UM1725 - User Manual: Description of STM32F4 HAL and LL drivers》的第五篇章《HAL System Driver》(文档版本DocID025834 Rev 5 )。这里列出在STM32CubeMX生成代码时不会用到的部分常用的函数:

  • __weak uint32_t HAL_GetTick(void)
    返回从系统运行开始经过的时间,默认情况下单位为ms;
  • __weak void HAL_Delay(uint32_t Delay)
    延时,该延时是阻塞的,默认情况下延时单位为ms,该函数不能在等于或高于系统时钟源优先级(默认情况下为0)的中断程序中使用,不然程序就阻塞在这里不动了;
  • __weak void HAL_SuspendTick(void)
    暂停系统时间运行,记得与HAL_ResumeTick()成对使用;
  • __weak void HAL_ResumeTick(void)
    继续系统时间运行;
  • uint32_t HAL_GetUIDw0(void)
    uint32_t HAL_GetUIDw1(void)
    uint32_t HAL_GetUIDw2(void)
    STM32芯片 96位全球唯一ID。

特殊函数

特殊操作一般用的不多,这里列举部分常用的:

全局中断

使用下面函数关闭/开启全局中断:
__disable_irq(); //关闭全局中断,等同于__set_PRIMASK(1);
__enable_irq(); //开启全局中断,等同于__set_PRIMASK(0);
__disable_irq()操作相当于把当前运行的代码优先级调整至0,所有其它用户中断程序将不会运行,直至重新开启全局中断。

使用下面函数也可以关闭/开启全局中断(有些系列的芯片没有该组函数):
__disable_fault_irq(); //关闭全局中断,等同于__set_FAULTMASK(1);
__enable_fault_irq(); //开启全局中断,等同于__set_FAULTMASK(0);
__disable_fault_irq()操作相当于把当前运行的代码优先级调整至-1,硬件错误也将被屏蔽;

软复位系统

使用 NVIC_SystemReset() 函数可以软复位系统,最好配合关闭全局中断使用,以免出现意外操作。

总结

HAL整体功能组织、命名还是比较不错的。刚从标准外设库(STD)转过来的开发者可能会不太习惯,主要是两者的设计思路上有区别。了解HAL库的功能组织和命名习惯对于理解HAL库设计思路、使用HAL库进行开发还是有促进作用的。

发布了66 篇原创文章 · 获赞 176 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/Naisu_kun/article/details/98661882