【沧海拾昧】第三章_HAL库概述(STM32F1_HAL库官方手册中文版翻译)

#C0107


沧海茫茫千钟粟,且拾吾昧一微尘

——《沧海拾昧集》@CuPhoenix


【阅前敬告】
沧海拾昧集仅做个人学习笔记之用,所述内容不专业不严谨不成体系
【如有问题必是本集记录有谬,切勿深究】

(本文翻译自 STM32F1_HAL 库与低层驱动器说明手册,笔者水平有限,不对正确性进行保证,仅供参考)


3 HAL库概述

3.1 HAL库和用户程序文件

​ 略。

3.2 HAL库的数据结构

  • 每个 HAL 驱动程序可能包含以下数据结构:

  • 外设句柄结构体

  • 初始化/配置结构体

  • 特定进程的结构体

3.2.1 外设句柄结构体(译注:是HAL库的重要特点)

​ HAL 库的 API 具有模块化的通用多实例架构,允许同时操作多个 IP 实例。PPP_HandleTypeDef *handle 是 HAL 驱动程序中实现的主要结构(称为句柄)。句柄处理 外设 / 模块 的配置和寄存器,并包含所有该外设设备流所需的结构和变量。

​ 外设句柄用于以下目的:

  • 多实例支持:每个 外设 / 模块实例都有其自己的句柄,因此实例资源是独立的。
  • 外设进程间通信:句柄用于管理进程例程之间的共享数据资源。(如:全局指针、DMA 句柄、状态机等)
  • 存储:句柄也能用于管理给定 HAL 驱动程序中的全局变量。

句柄示例(USART的句柄):

typedef struct {
   
    USART_TypeDef *Instance;         	    /* USART 寄存器的基地址 */
    USART_InitTypeDef Init;          	    /* USART 通信参数 */
    uint8_t *pTxBuffPtr;             	    /* USART 发送数据缓冲区的指针 */
    uint16_t TxXferSize;             	    /* USART 发送传输数据大小 */
    __IO uint16_t TxXferCount;      	    /* USART 发送传输计数器 */
    uint8_t *pRxBuffPtr;            	    /* USART 接收数据缓冲区的指针 */
    uint16_t RxXferSize;             	    /* USART 接收传输数据大小 */
    __IO uint16_t RxXferCount;       	    /* USART 接收传输计数器 */
    DMA_HandleTypeDef *hdmatx;       	    /* USART 发送 DMA 句柄参数 */
    DMA_HandleTypeDef *hdmarx;       	    /* USART 接收 DMA 句柄参数 */
    HAL_LockTypeDef Lock;            	    /* 锁定对象 */
    __IO HAL_USART_StateTypeDef State;  	/* USART 通信状态 */
    __IO HAL_USART_ErrorTypeDef ErrorCode; 	/* USART 错误码 */
} USART_HandleTypeDef;

注:

  • 多实例支持表明程序中使用的所有 API 都是可重入的(译注:可重入函数 reentrant 指可被递归调用的函数),因此必须避免在这些 API 中使用全局变量(否则若递归调用时依赖的某个全局变量值被更改,程序将无法保持可重入性)。因此,需遵守以下规则:
    • 可重入代码中不含任何静态(或全局)非常量数据:可重入函数可以使用全局数据。例如,可重入中断服务例程可以获取一个硬件状态(如串口读缓冲区),该状态不仅是全局的,而且是易变的。然而,通常不建议使用静态变量和全局数据,即这些变量应仅使用原子读-改写-写指令。(译注:原子操作,即一种不可被中断的操作,不应被任何调度机制打断执行)执行原子操作期间,不能发生中断或信号。
    • 可重入代码不得修改其自身的代码。
  • 当外设能够通过 DMA 同时管理多个进程时(全双工情况),每个进程的 DMA 接口句柄会被添加到 PPP_HandleTypeDef 中。
  • 对于可共享的系统外设,不使用句柄或实例对象。包括: GPIO、SYSTICK、NVIC、PWR、RCC、FLASH。

3.2.2 初始化/配置结构体

​ 结构体在通用驱动程序头文件中定义,适用于所有型号。此外,对于独有的功能,结构体会在每个型号的扩展头文件中定义。例如:

typedef struct {
   
    uint32_t BaudRate;        /* 配置 UART 通信的波特率 */
    uint32_t WordLength;      /* 指定帧中传输或接收的数据位数 */
    uint32_t StopBits;        /* 指定传输的停止位数 */
    uint32_t Parity;          /* 指定校验模式 */
    uint32_t Mode;            /* 指定接收模式或发送模式是否启用 */
    uint32_t HwFlowCtl;       /* 指定硬件流控制模式是否启用 */
    uint32_t OverSampling;    /* 指定是否启用超采样8,以实现更高的速度(最高可达fPCLK/8) */
} UART_InitTypeDef;

通过初始化结构体进行配置,例如:

HAL_ADC_ConfigChannel (ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)

3.2.3 特定进程的结构体

​ 特定进程的结构体用于处理特定的进程。这些结构在通用驱动程序头文件中定义(通用 API)。例如:

HAL_PPP_Process (PPP_HandleTypeDef* hadc,PPP_ProcessConfig* sConfig)

3.3 API类型

​ HAL 库中的 API 被分为以下三类:

  • 通用 API: 适用于所有 STM32 设备的通用 API,存在于所有 STM32 微控制器的通用 HAL 驱动程序文件中。例如:
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc); 
HAL_StatusTypeDef HAL_ADC_DeInit(ADC_HandleTypeDef *hadc); 
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); 
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc); 
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc); 
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc); 
void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc);
  • 扩展 API

    • 系列特定 API:适用于某一特定系列的 API。这些 API 位于扩展 HAL 驱动程序文件中,例如:
    HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc, uint32_t SingleDiff); uint32_t HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef* hadc, uint32_t SingleDiff);
    
    • 器件编号特定 API:这些 API 实现在扩展文件中,并由特定的定义语句与特定器件编号相关联,例如:
    #if defined (STM32F101xG) || defined (STM32F103x6)|| defined (STM32F103xB) || defined (STM32F105xC) || defined (STM32F107xC) || defined (STM32F103xE) || defined (STM32F103xG) 
    /* ADC 并行模式(multimode) */HAL_StatusTypeDef
    HAL_ADCEx_MultiModeStart_DMA(ADC_HandleTypeDef *hadc, uint32_t *pData, uint32_tLength);
    HAL_StatusTypeDef HAL_ADCEx_MultiModeStop_DMA(ADC_HandleTypeDef *hadc);
    #endif /* STM32F101xG || defined STM32F103x6 || defined STM32F103xB || defined STM32F105xC || defined STM32F107xC || defined STM32F103xE || defined STM32F103xG */
    

3.4 HAL库支持的设备

​ 略。

3.5 HAL库通用规则

3.5.1 HAL库的命名规则

​ HAL 库中使用以下命名规则:

通用 系列特定 器件特定
文件名 stm32f1xx_hal_ppp (c/h) stm32f1xx_hal_ppp_ex (c/h) stm32f1xx_ hal_ppp_ex (c/h)
模块名 HAL_PPP_ MODULE HAL_PPP_ MODULE HAL_PPP_ MODULE
函数名 HAL_PPP_FunctionHAL_PPP_FeatureFunction_MODE HAL_PPPEx_FunctionHAL_PPPEx_FeatureFunction_MODE HAL_PPPEx_FunctionHAL_PPPEx_FeatureFunction_MODE
句柄名 PPP_HandleTypedef NA NA
初始化结构体名 PPP_InitTypeDef NA PPP_InitTypeDef
枚举名 HAL_PPP_StructnameTypeDef NA NA
  • PPP 前缀(译注:在本手册中 PPP 是一种占位符,就像 xxx 一样)指的是外设功能模式,而不是外设本身。例如,USART 外设的 PPP 可以是 USART、IRDA、UART 或 SMARTCARD,具体取决于外设模式。
  • 一个文件中使用的常量定义在该文件内。若一个常量在多个文件中使用,则定义在头文件中。所有常量均采用大写字母,外设驱动函数参数除外。
  • typedef 变量名应以 _TypeDef 结尾。
  • 寄存器被视为常量,通常使用大写字母,并采用 STM32F1 参考手册中的相同缩写。
  • 外设寄存器在 CMSIS 头文件中的 PPP_TypeDef 结构体中声明(例如,ADC_TypeDef):stm32f1xxx.h 对应 stm32f100xb.h、stm32f100xe.h、stm32f101x6.h、stm32f101xb.h、stm32f101xe.h、stm32f101xg.h、stm32f102x6.h、stm32f102xb.h、stm32f103x6.h、stm32f103xb.h、stm32f103xe.h、stm32f103xg.h、stm32f105xc.h 和 stm32f107xc.h。
  • **外设函数名以 HAL_ 为前缀,后接对应的外设缩写(大写),然后是一个下划线。每个单词的首字母大写(例如 HAL_UART_Transmit())。**函数名中只允许一个下划线,用于分隔外设缩写和函数名的其他部分。
  • 包含 PPP 外设初始化参数的结构体名为 PPP_InitTypeDef(例如 ADC_InitTypeDef)。
  • 包含 PPP 外设特定配置参数的结构体名为 PPP_xxxxConfTypeDef(例如 ADC_ChannelConfTypeDef)。
  • 外设句柄结构体名为 PPP_HandleTypedef(例如 DMA_HandleTypeDef)。
  • 用于根据 PPP_InitTypeDef 中指定的参数初始化 PPP 外设的函数名为 HAL_PPP_Init(例如 HAL_TIM_Init())。
  • 用于将 PPP 外设寄存器重置为默认值的函数名为 HAL_PPP_DeInit(例如 HAL_TIM_DeInit())。
  • MODE 后缀指的是处理模式,可以是轮询、中断或 DMA。例如,当使用 DMA 作为额外资源时,函数应命名为:HAL_PPP_Function_DMA()。
  • Feature 前缀应指代新功能。

3.5.2 HAL通用命名规则

​ 对于共享和系统外设,不使用句柄或实例对象。此规则适用于 GPIO、SYSTICK、NVIC、RCC、FLASH。例如,HAL_GPIO_Init() 仅需要 GPIO 地址和其配置参数:

HAL_StatusTypeDef HAL_GPIO_Init (GPIO_TypeDef* GPIOx, GPIO_InitTypeDef *Init) {
   
	/*GPIO 初始化内容 */
}

​ 处理中断和特定时钟配置的宏在每个外设/模块驱动程序中定义。这些宏在外设驱动程序的头文件中导出,以便扩展文件可以使用。下表列出了这些宏:

宏定义 说明
_HAL_PPP_ENABLE_IT(__HANDLE__, __INTERRUPT_) 启用特定外设的中断
__HAL_PPP_DISABLE_IT(__HANDLE_, __INTERRUPT__) 禁用特定外设的中断
__HAL_PPP_GET_IT(__HANDLE_, __INTERRUPT__) 获取特定外设的中断状态
__HAL_PPP_CLEAR_IT(__HANDLE_, __INTERRUPT__) 清除特定外设的中断状态
__HAL_PPP_GET_FLAG(__HANDLE_, __INTERRUPT__) 获取特定外设的标志状态
__HAL_PPP_CLEAR_FLAG(__HANDLE_, __INTERRUPT__) 清除特定外设的标志状态
__HAL_PPP_ENABLE(__HANDLE_) 启用外设
__HAL_PPP_DISABLE(__HANDLE_) 禁用外设
__HAL_PPP_XXXX(__HANDLE_, __PARAM__) 特定 PPP HAL 驱动程序宏
__HAL_PPP_GET_IT_SOURCE(__HANDLE_, __INTERRUPT__) 检查指定中断的来源

注:

  • NVIC 和 SYSTICK 是 Arm Cortex 的核心功能,相关的 API 位于 stm32f1xx_hal_cortex.c 文件中。

  • 当从寄存器中读取状态位或标志时,其值由位移值组成,这取决于读取值的数量和大小。返回的状态宽度为 32 位。如:STATUS = XX | (YY << 16)STATUS = XX | (YY << 8) | (YY << 16) | (YY << 24)

  • 在使用 HAL_PPP_Init() API 之前,PPP 句柄必须有效。初始化函数在修改句柄字段之前会执行检查。

  • 以下宏定义被使用:

    • 条件宏:

      #define ABS(x) (((x) > 0) ? (x) : -(x))
      
    • 伪代码宏(多条指令宏)

      #define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD_, __DMA_HANDLE_) \ 
      do{
               \ 
      (__HANDLE__)->__PPP_DMA_FIELD_ = &(__DMA_HANDLE_); \ 
      (__DMA_HANDLE_).Parent = (__HANDLE__); \ 
      } while(0)
      

3.5.3 HAL中断处理程序和回调函数

  • HAL 外设驱动程序还包括:

    • HAL_PPP_IRQHandler() 外设中断处理程序,应从 stm32f1xx_it.c 文件中调用。
    • 用户回调函数。这些回调函数被定义为空函数,并具有“weak”(弱)属性。用户需要在其代码中定义这些函数。
  • 用户回调函数有三种类型:

    • 外设系统级 初始化 / 去初始化 回调:HAL_PPP_MspInit()HAL_PPP_MspDeInit()

      例如:HAL_USART_MspInit(),从 HAL_PPP_Init() API 函数中调用,用于执行外设系统级初始化(如 GPIO、时钟、DMA、中断)。

    • 处理完成回调:HAL_PPP_ProcessCpltCallback

      例如:HAL_USART_TxCpltCallback,当处理完成时,由外设或 DMA 中断处理程序调用。

    • 错误回调:HAL_PPP_ErrorCallback

      例如:HAL_USART_ErrorCallback,当发生错误时,由外设或 DMA 中断处理程序调用。

  • 译注:回调函数,是一个被作为参数传递的函数。例如,函数 F1 调用函数 F2 的时候,函数 F1 通过参数给 函数 F2 传递了另外一个函数 F3 的指针,在函数 F2 执行的过程中,函数F2 调用了函数 F3,这个动作就叫做回调(Callback),而先被当做指针传入、后面又被回调的函数 F3 就是回调函数。使用回调函数而不是普通函数的具体意义在于解耦。如下代码片段,对于库中封装的 Library 函数,通过对 Callback 函数的修改与传入,可以使 Library 函数实现不同功能,而并不需要修改库中已经固定的函数。

    #i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值