9 HAL库驱动框架简述(STM32HAL库)

目录

HAL库驱动框架简述

HAL库外设设计思想

HAL库和Cube MX相结合

一、对外设的封装——句柄结构体

二、外设初始化

初始化结构体

初始化的逻辑

三、外设使用逻辑

通用接口函数

初始化函数

I/O操作函数

控制函数

状态参数

扩展接口函数

总结

补充:HAL库使用主线

HAL库驱动框架简述

参考于:HAL库学习笔记-10 HAL库外设驱动框架概述_hal库的外设句柄_Q-Stark的博客-CSDN博客

HAL库外设设计思想

HAL库借鉴面向对象的设计思想,将外设驱动封装为对象。

采用此种开发方式有以下特点:

  • 屏蔽底层硬件:只需了解相关接口函数的功能和参数要求即可
  • 提高开发效率:开发难度较小,开发周期较短,后期的维护升级、以及硬件平台的移植等工作量小
  • 程序执行效率:由于考虑了程序的稳健性、扩充性和可移植性,程序代码比较繁琐和臃肿,执行效率较低

HAL库和Cube MX相结合

一、对外设的封装——句柄结构体

围绕着芯片设计的外设多种多样,功能也越来越多,为了能够统一管理这些外设,HAL库设计了统一的外设句柄数据类型xxx_HandleTypeDef(PPP代表外设名称)。如定时器句柄:

/*** @brief  TIM Time Base Handle Structure definition*/
typedef struct
{TIM_TypeDef                 *Instance;     /*!< Register base address             */TIM_Base_InitTypeDef        Init;          /*!< TIM Time Base required parameters */HAL_TIM_ActiveChannel       Channel;       /*!< Active channel                    */DMA_HandleTypeDef           *hdma[7];      /*!< DMA Handlers array This array is accessed by a @ref DMA_Handle_index */HAL_LockTypeDef             Lock;          /*!< Locking object                    */__IO HAL_TIM_StateTypeDef   State;         /*!< TIM operation state               */
} TIM_HandleTypeDef;

保护锁是HAL库提供的一种安全机制,以避免对外设的并发访问。

二、外设初始化

由上述的句柄结构体可知,我们需要定义一个外设句柄指针,并向其中填充参数,其中最重要的就是初始化参数,为此HAL库为不同的外设定义了不同的初始化结构体,且相同外设的不同功能也有不同的初始化结构,如定时器,有时基单元初始化结构体、输入初始化结构体和输出初始化结构体等,分别用于输入捕获和输出比较等不同功能。

初始化这一步骤使用CubeMX配置,可自动生成初始化代码,大大减少了开发难度。如下的初始化函数代码即由CubeMX自动生成的,带有MX前缀。

初始化结构体

代码如下(示例):

/*** @brief  TIM Time base Configuration Structure definition*/
typedef struct
{uint32_t Prescaler;         uint32_t CounterMode;  uint32_t Period;           uint32_t ClockDivision;    uint32_t RepetitionCounter;  uint32_t AutoReloadPreload; 
} TIM_Base_InitTypeDef;
/*** @brief  TIM Input Capture Configuration Structure definition*/
typedef struct
{uint32_t  ICPolarity;  uint32_t ICSelection;  uint32_t ICPrescaler;  uint32_t ICFilter;     
} TIM_IC_InitTypeDef;
/*** @brief  TIM Output Compare Configuration Structure definition*/
typedef struct
{uint32_t OCMode;   uint32_t Pulse;        uint32_t OCPolarity;    uint32_t OCNPolarity;   uint32_t OCFastMode;   uint32_t OCIdleState;   uint32_t OCNIdleState;  
} TIM_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 ConfigurationPA9     ------> USART1_TXPA10     ------> 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_xxx_ex.h和stm32fxxx_hal_xxx_ex.c

总结

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

1、定义并填充xxx外设句柄结构体。

2、如果遵循HAL库规范,通过HAL_xxx_MspInit()函数,实现外设底层资源的初始化,包括但不限于GPIO、时钟、DMA、中断等资源的初始化。

3、调用HAL库的对应外设初始化函数,形如:HAL_xxx_Init()。

4、初始化完成,开始使用外设。

5、使用方法具体查看对应外设的HAL库驱动包中的说明:

##### How to use this driver #####

补充:HAL库使用主线

外设初始化

外设使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/4173.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新手快速搭建springboot项目

一、创建项目 1.1、创建项目 1.2、配置编码 1.3、取消无用提示 1.4、取消无用参数提示 二、添加POM父依赖 <!-- 两种方式添加父依赖或者import方式 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-p…

linux-2.6.22.6内核i2c驱动框架源码分析

i2c是常见的通信协议&#xff0c;协议比较简单&#xff0c;只有数据和时钟两条线&#xff08;SDA和SCL&#xff09;&#xff0c;i2c的通信分为主机和从机&#xff0c;主机一般占主导地位&#xff0c;从机可以有多个。 i2c通信的数据格式为(SDA上的数据)&#xff1a;开始的7位里…

【单片机】STM32单片机的矩阵键盘驱动,标准库,无阻塞方式的矩阵键盘读取

原理图&#xff1a; 从左到右、从上到下&#xff0c;按键是1到16&#xff0c;没有按键返回0&#xff1a; key.c #include "key.h"/* 按键初始化函数 */ void KEY_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, …

Eclipse中的实用工具之JUnit

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于JUnit的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 是什么 为什么要用 怎么用 是什么 JUnit…

UE4/5动画系列(4.足部ik制作)

目录 前期准备 添加虚拟骨骼 ​编辑 腿部函数&#xff1a; 前肢&#xff1a; ​编辑 盆骨函数&#xff1a; 后肢&#xff1a; 进入动画图表&#xff1a; 前期准备 首先准备一个后期处理动画蓝图 然后【因为笔者之前的大象因为不知明原因崩溃&#xff0c;这里就不展示如何…

PostgreSQL中HOT对cluster的作用

PG中cluster的作用是根据表的索引重新构建一张表&#xff0c;并且表根据该索引进行排序&#xff0c;索引必须提前建好。 注意&#xff1a;cluster操作加ACCESS EXCLUSIVE锁&#xff0c;会阻塞其它任何操作。 我们为什么要运行cluster? PG中的表是堆表&#xff0c;表中行的顺…

青少年机器人技术一级核心知识点:机械结构及模型(四)

随着科技的不断进步&#xff0c;机器人技术已经成为了一个重要的领域。在这个领域中&#xff0c;机械结构是机器人设计中至关重要的一部分&#xff0c;它决定了机器人的形态、运动方式和工作效率。对于青少年机器人爱好者来说&#xff0c;了解机械结构的基础知识&#xff0c;掌…

简述环保用电监管云平台

1、概述 推进打赢蓝天保卫战&#xff0c;打好碧水保卫战&#xff0c;打胜净土保卫战&#xff0c;加快生态环境保护、建设美丽中国&#xff0c;各省市结合物联网和大数据政策&#xff0c;也相继颁布有关污染治理设施用电监管平台等相关政策。针对企业内的环保设施、设备运行状况…

GitHub下载破千万!这份Java大厂面试指南,竟是阿里面试官上传的

前言 本以为在大厂可以逃过35岁的坎儿&#xff0c;结果还没到35就遇上了大裁员。。。被裁的那一个月&#xff0c;我拿着公司给的2N在家躺了大半个月&#xff0c;刚开始是不甘&#xff0c;到后面每个月一万多的房贷催着我不得不重新审视自己&#xff0c;随后踏上了海投之路。 …

【Spring Cloud系列】-Eureka服务端高可用详解

【Spring Cloud系列】-Eureka服务端高可用详解 文章目录 【Spring Cloud系列】-Eureka服务端高可用详解一. 序言二. 什么是高可用性三. 什么是CAP一致性&#xff08;Consistency&#xff09;可用性&#xff08;Availability&#xff09;分区容错&#xff08;Partition-toleranc…

Kubernetes-Ingress、Ingress Controller、Ingress Class

概念 1.Ingress 是对K8S集群中服务的外部访问进行管理的 API 对象。Ingress 公开从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。 2.Ingress Controller 通常负责通过负载均衡器来实现 Ingress。 3.必须拥有一个 Ingress Controller…

vue(typescript)项目在vs中打开出现的各种问题

目录 vue3 报错解决&#xff1a;找不到模块或其相应的类型声明。&#xff08;Vue 3 can not find module&#xff09; (TS) 未知的编译器选项“allowImportingTsExtensions”。 TS6046 (TS) “--moduleResolution”选项的参数必须为 node, classic, node16, nodenext。…