首页 > 编程知识 正文

HAL库学习笔记-10 HAL库外设驱动框架概述

时间:2023-05-06 06:34:13 阅读:26966 作者:3236

目录HAL库外围设备设计思想HAL库与Cube MX的结合一、封装到外围设备的——句柄结构二、外围设备初始化初始化结构初始化的逻辑三、外围设备使用逻辑通用接口函数初始化函数I/O操作函数状态参数扩展接口函数

HAL库外围设备设计思想HAL库参考面向对象的设计思想,面向外围设备驱动软件包。

采用这种开发方式具有以下特点。

屏蔽底层硬件:只有了解相关接口函数的功能和参数要求才能提高开发效率。 开发难度低、开发周期短、后期维护升级和硬件平台移植等工作量少的程序的执行效率。 由于考虑了程序的牢固性、可扩展性、可移植性,将程序代码繁杂、肥大化、执行效率低的HAL库与Cube MX结合起来

另一方面,外设封装——手柄结构以芯片为中心设计的外设多种多样,功能也越来越多。 HAL库是统一的外围设备句柄数据类型PPP_handletypedef(PPP表示外围设备名称),以便统一管理这些外围设备。 例如,计时器手柄:

/** * @brief热心芝麻timebasehandlestructuredefinition */typedef struct {热心芝麻_TypeDef *Instance; //! Register base address */热心芝麻_Base_InitTypeDef Init; //! 热心芝麻timebaserequiredparameters */Hal _热心芝麻_ActiveChannel Channel; //! 活动通道*/DMA _ handle typedef * hdma [7]; //! dmahandlersarraythisarrayisaccessedbya @ re FDMA _ handle _ index */Hal _ locktypedeflock; //! Locking object */__IO HAL_热心芝麻_StateTypeDef State; //! 热心的芝麻操作状态*/}热心的芝麻_HandleTypeDef; 保护锁是HAL库提供的安全机制,可避免同时访问外围设备。

二、外围设备初始化从上述手柄结构可以看出,我们需要定义外围设备手柄指针,并在其中输入参数。 其中最重要的是初始化参数。 因此,在HAL库中为每个外围设备定义了不同初始化结构体,另外,相同外围设备的不同功能也有不同的初始化结构体,例如计时器,根据情况有基本单元初始化结构体、输入初始化结构体和输出初始化结构体等,分别被输入的盖

初始化步骤使用CubeMX配置自动生成初始化代码,大大降低开发难度。 以下初始化函数代码由CubeMX自动生成并带有MX前缀:

要初始化结构代码,请执行以下操作:

/** * @brief热心芝麻timebaseconfigurationstructuredefinition */typedef struct { uint 32 _ tprescaler; uint 32 _ t计数器模式; uint32_t Period; uint 32 _ t时钟division; uint32_t RepetitionCounter; uint 32 _ t自动加载预加载; }热心的芝麻_Base_InitTypeDef; /** * @brief热心芝麻inputcaptureconfigurationstructuredefinition */typedef struct { uint 32 _ TIC polarity; uint 32 _ t IC选择; uint32_t ICPrescaler; uint 32 _ t IC过滤器; }热心芝麻_IC_InitTypeDef; /** * @brief热心芝麻outputcompareconfigurationstructuredefinition */typedef struct { uint 32 _ TOC mode; uint32_t Pulse; uint32_t OCPolarity; uint32_t OCNPolarity; uint32_t OCFastMode; uint32_t OCIdleState; uint32_t OCNIdleState; }热心的芝麻_OC_InitTypeDef; 初始化逻辑

HAL_PPP_Init )初始化函数将句柄结构中的初始化参数转换为

存入寄存器,即进行相关参数的传入赋值,然后调用HAL_PPP_MspInit()函数完成具体的时钟、引脚等资源初始化,完成围绕具体MCU的配置;MSP函数调用完成后,回到HAL_PPP_Init()函数调用现场,根据返回值情况进入下一步,最后完成外设初始化。
以串口为例:
代码如下(示例):

UART_HandleTypeDef huart1;DMA_HandleTypeDef hdma_usart1_rx;DMA_HandleTypeDef hdma_usart1_tx;void MX_USART1_UART_Init(void){ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); }}void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){ GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 DMA Init */ /* USART1_RX Init */ hdma_usart1_rx.Instance = DMA1_Channel5; hdma_usart1_rx.Init.Request = DMA_REQUEST_2; hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.Mode = DMA_NORMAL; hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx); /* USART1_TX Init */ hdma_usart1_tx.Instance = DMA1_Channel4; hdma_usart1_tx.Init.Request = DMA_REQUEST_2; hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_tx.Init.Mode = DMA_NORMAL; hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); }} 三、外设使用逻辑 通用接口函数

初始化函数

通过上述的初始化步骤完成调用。

I/O操作函数

根据不同的功能使用,设计了三种不同的编程模型:轮询、中断和DMA。
以后缀区分,入口参数均为外设句柄的指针,其中轮询模式还需要传入超时时间参数。三种不同编程模型的具体实现可参考串口的三篇笔记。

控制函数

可以在使用中,动态的调节外设的参数,如中断及时钟。

状态参数

可以清除和查询一些标志位,获取外设的运行状态以及出错信息。

扩展接口函数

设计扩展接口函数可以兼顾STM32各产品系列的特有功能和扩展功能,兼顾同一个产品系列中不同芯片的特有功能。通过单独定义后续为ex的文件来实现。如stm32fxxx_hal_ppp_ex.h和stm32fxxx_hal_ppp_ex.c

总结

HAL库外设的使用步骤总结如下:

定义并填充PPP外设句柄结构体如果遵循HAL库规范,通过HAL_MspInit()函数,实现外设底层资源的初始化,包括但不限于GPIO、时钟、DMA、中断等资源的初始化调用HAL库的对应外设初始化函数,形如:HAL_PPP_Init()初始化完成,开始使用外设使用方法具体查看对应外设的HAL库驱动包中的说明:##### How to use this driver#####

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。