0 简介

HAL库是ST公司目前主力推的开发方式,全称就是Hardware Abstraction Layer(抽象印象层)。它的出现比标准库要晚,但其实和标准库一样,都是为了节省程序开发的时期,而且HAL库尤其的有效,如果说标准库把实现功能需要配置的寄存器集成了,那么HAL库的一些函数甚至可以做到某些特定功能的集成。也就是说,同样的功能,标准库可能要用几句话,HAL库只需用一句话就够了。并且HAL库也很好的解决了程序移植的问题,使用HAL库,只要使用的是相通的外设,程序基本可以完全复制粘贴。使用ST公司研发的STMcube软件,可以通过图形化的配置功能,直接生成整个使用HAL库的工程文件,可以说是方便至极,但是方便的同时也造成了它执行效率的低下,在各种论坛帖子真的是被吐槽的数不胜数。

1 CMSIS 标准及库层次关系

基于 Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难。为了解决不同的芯片厂商生产的 Cortex 微控制器软件的兼容性问题,ARM 与芯片厂商建立了 CMSIS 标准 (Cortex MicroController Software Interface Standard)。
所谓 CMSIS 标准,实际是新建了一个软件抽象层。
image.png
CMSIS 标准中最主要的为 CMSIS 核心层,它包括了:

  • 内核函数层:其中包含用于访问内核寄存器的名称、地址定义,主要由 ARM 公司提供。
  • 设备外设访问层:提供了片上的核外外设的地址和中断定义,主要由芯片生产商提供。

可见 CMSIS 层位于硬件层与操作系统或用户层之间,提供了与芯片生产商无关的硬件抽象层,可以为接口外设、实时操作系统提供简单的处理器软件接口,屏蔽了硬件差异,这对软件的移植是有极大的好处的。STM32 的库,就是按照 CMSIS 标准建立的。

库各文件间的关系

image.png
描述了 STM32 库各文件之间的调用关系,这个图省略了 DSP 核和实时系统层部分的文件关系。在实际的使用库开发工程的过程中,我们把位于 CMSIS 层的文件包含进工程,除了特殊系统时钟需要修改 system_stm32f1xx.c,其它文件丝毫不用修改,也不建议修改。对于位于用户层的几个文件,就是我们在使用库的时候,针对不同的应用对库文件进行增删(用条件编译的方法增删)和改动的文件。

2 cubemx

都用HAL库了还不用cubemx?

STM32CubeMX 是 ST 意法半导体近几年来大力推荐的STM32 芯片图形化配置工具,目的就是为了方便开发者, 允许用户使用图形化向导生成C 初始化代码,可以大大减轻开发工作,时间和费用,提高开发效率。STM32CubeMX几乎覆盖了STM32 全系列芯片。
在CubeMX上,通过傻瓜化的操作便能实现相关配置,最终能够生成C语言代码,支持多种工具链,比如MDK、IAR For ARM、TrueStudio等 省去了我们配置各种外设的时间,大大的节省了时间。
安装过程就不写了,网上一大把。

3 句柄

3.1 标准库

在标准库中初始化:固件库结构体变量+固件库Init函数实现

  1. USART_InitTypeDef USART_InitStructure;
  2. USART_InitStructure.USART_BaudRate = bound;//串口波特率
  3. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  4. USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  5. USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  6. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  7. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
  8. USART_Init(USART3, &USART_InitStructure); //初始化串口1

USART_InitStructure是一个在函数内部的局部变量,初始化完成之后,USART_InitStructure就失去了作用。

3.2 HAL库

需要定义全局变量

  1. UART_HandleTypeDef UART1_Handler;
  1. typedef struct
  2. {
  3. USART_TypeDef *Instance; /*!< UART registers base address */
  4. UART_InitTypeDef Init; /*!< UART communication parameters */
  5. uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
  6. uint16_t TxXferSize; /*!< UART Tx Transfer size */
  7. uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
  8. uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
  9. uint16_t RxXferSize; /*!< UART Rx Transfer size */
  10. uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
  11. DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
  12. DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
  13. HAL_LockTypeDef Lock; /*!< Locking object */
  14. __IO HAL_UART_StateTypeDef State; /*!< UART communication state */
  15. __IO uint32_t ErrorCode; /*!< UART Error code */
  16. }UART_HandleTypeDef;

UART1_Handler 就被称为串口的句柄,它被贯穿整个USART收发的流程。

4 MSP函数

MCU Specific Package (单片机的具体方案),MSP是指和MCU相关的初始化

我们要初始化一个串口,首先要设置和 MCU 无关的东西,例如波特率,奇偶校验,停止位等,这些参数设置和 MCU 没有任何关系,可以使用 STM32F1,也可以是 STM32F2/F3/F4/F7上的串口。而一个串口设备它需要一个 MCU 来承载,例如用 STM32F4 来做承载,PA9 做为发送,PA10 做为接收,MSP 就是要初始化 STM32F4 的 PA9,PA10,配置这两个引脚。所以 HAL驱动方式的初始化流程就是:

  1. HAL_USART_Init()—>HAL_USART_MspInit()

先初始化与 MCU无关的串口协议,再初始化与 MCU 相关的串口引脚。在 STM32 的 HAL 驱动中HAL_PPP_MspInit()作为回调,被 HAL_PPP_Init()函数所调用。当我们需要移植程序到 STM32F1平台的时候,我们
只需要修改 HAL_PPP_MspInit 函数内容而不需要修改 HAL_PPP_Init 入口参数内容。

在HAL库中,几乎每初始化一个外设就需要设置该外设与单片机之间的联系,比如IO口,是否复用等等
[

](https://blog.csdn.net/as480133937/article/details/99935090)