STM32 HAL库与标准库的区别_浅谈句柄、MSP函数、Callback函数
最近笔者开始学习STM32的HAL库,由于以前一直用标准库进行开发,于是发现了HAL库几点好玩的地方,在此分享。
1.句柄
在STM32的标准库中,假设我们要初始化一个外设(这里以USART为例)
我们首先要初始化他们的各个寄存器。在标准库中,这些操作都是利用固件库结构体变量+固件库Init函数实现的:
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART3, &USART_InitStructure); //初始化串口1
可以看到,要初始化一个串口,需要对六个位置进行赋值,然后引用Init函数,并且USART_InitStructure并不是一个全局结构体变量,而是只在函数内部的局部变量,初始化完成之后,USART_InitStructure就失去了作用。
而在HAL库中,同样是USART初始化结构体变量,我们要定义为全局变量。
UART_HandleTypeDef UART1_Handler;
- 1
右键查看结构体成员
typedef struct
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef State; /*!< UART communication state */
__IO uint32_t ErrorCode; /*!< UART Error code */
}UART_HandleTypeDef;
我们发现,与标准库不同的是,该成员不仅包含了之前标准库就有的六个成员(波特率,数据格式等),还包含过采样、(发送或接收的)数据缓存、数据指针、串口 DMA 相关的变量、各种标志位等等要在整个项目流程中都要设置的各个成员。
该 UART1_Handler 就被称为串口的句柄
它被贯穿整个USART收发的流程,比如开启中断:
HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);
比如后面要讲到的MSP与Callback回调函数:
void HAL_UART_MspInit(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
在这些函数中,只需要调用初始化时定义的句柄UART1_Handler就好。
2.MSP函数
MCU Specific Package 单片机的具体方案
MSP是指和MCU相关的初始化,引用一下正点原子的解释,个人觉得说的很明白:
我们要初始化一个串口,首先要设置和 MCU 无关的东西,例如波特率,奇偶校验,停止
位等,这些参数设置和 MCU 没有任何关系,可以使用 STM32F1,也可以是 STM32F2/F3/F4/F7
上的串口。而一个串口设备它需要一个 MCU 来承载,例如用 STM32F4 来做承载,PA9 做为发
送,PA10 做为接收,MSP 就是要初始化 STM32F4 的 PA9,PA10,配置这两个引脚。所以 HAL
驱动方式的初始化流程就是: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口,是否复用等等,可见,HAL库相对于标准库多了MSP函数之后,移植性非常强,但与此同时却增加了代码量和代码的嵌套层级。可以说各有利弊。
同样,MSP函数又可以配合句柄,达到非常强的移植性:
void HAL_UART_MspInit(UART_HandleTypeDef *huart);
入口参数仅仅需要一个串口句柄,这样有能看出句柄的方便。
3.Callback函数
类似于MSP函数,个人认为Callback函数主要帮助用户应用层的代码编写。
还是以USART为例,在标准库中,串口中断了以后,我们要先在中断中判断是否是接收中断,然后读出数据,顺便清除中断标志位,然后再是对数据的处理,这样如果我们在一个中断函数中写这么多代码,就会显得很混乱:
void USART3_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART3); //读取接收到的数据
/*数据处理区*/
}
}
}
而在HAL库中,进入串口中断后,直接由HAL库中断函数进行托管:
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&UART1_Handler); //调用HAL库中断处理公用函数
/***************省略无关代码****************/
}
HAL_UART_IRQHandler这个函数完成了判断是哪个中断(接收?发送?或者其他?),然后读出数据,保存至缓存区,顺便清除中断标志位等等操作。
比如我提前设置了,串口每接收五个字节,我就要对这五个字节进行处理。
在一开始我定义了一个串口接收缓存区:
/*HAL库使用的串口接收缓冲,处理逻辑由HAL库控制,接收完这个数组就会调用HAL_UART_RxCpltCallback进行处理这个数组*/
/*RXBUFFERSIZE=5*/
u8 aRxBuffer[RXBUFFERSIZE];
在初始化中,我在句柄里设置好了缓存区的地址,缓存大小(五个字节)
/*该代码在HAL_UART_Receive_IT函数中,初始化时会引用*/
huart->pRxBuffPtr = pData;//aRxBuffer
huart->RxXferSize = Size;//RXBUFFERSIZE
huart->RxXferCount = Size;//RXBUFFERSIZE
则在接收数据中,每接收完五个字节,HAL_UART_IRQHandler才会执行一次Callback函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
在这个Callback回调函数中,我们只需要对这接收到的五个字节(保存在aRxBuffer[]中)进行处理就好了,完全不用再去手动清除标志位等操作。
所以说Callback函数是一个应用层代码的函数,我们在一开始只设置句柄里面的各个参数,然后就等着HAL库把自己安排好的代码送到手中就可以了~
综上,就是HAL库的三个与标准库不同的地方之个人见解。
个人觉得从这三个小点就可以看出HAL库的可移植性之强大,并且用户可以完全不去理会底层各个寄存器的操作,代码也更有逻辑性。但与此带来的是复杂的代码量,极慢的编译速度,略微低下的效率。看怎么取舍了。
转自:https://blog.csdn.net/weixin_43186792/article/details/88759321?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.control
STM32 HAL库与标准库的区别_浅谈句柄、MSP函数、Callback函数的更多相关文章
- Arduino库和STM32的寄存器、标准库、HAL库、LL库开发比较之GPIO
标题: Arduino库和STM32的寄存器.标准库.HAL库.LL库开发比较之GPIO 作者: 梦幻之心星 sky-seeker@qq.com 标签: [#Arduino,#STM32,#库,#开发 ...
- STL笔记(6)标准库:标准库中的排序算法
STL笔记(6)标准库:标准库中的排序算法 标准库:标准库中的排序算法The Standard Librarian: Sorting in the Standard Library Matthew A ...
- STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)
本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可. 1.键盘原理图: 原理举例:先把 F0-F7 内部拉高,这样 ...
- Lock与synchronized的区别(浅谈)
Lock是一个接口 synchronized是一个关键字 Lock用法: synchronized用法: lock.lock() ...
- STM32 之 HAL库(固件库) _
1 STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直 ...
- STM32 之 HAL库(固件库)
1 STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直 ...
- [技术] OIer的C++标准库 : STL入门
注: 本文主要摘取STL在OI中的常用技巧应用, 所以可能会重点说明容器部分和算法部分, 且不会讨论所有支持的函数/操作并主要讨论 C++11 前支持的特性. 如果需要详细完整的介绍请自行查阅标准文档 ...
- std 与标准库
1.命名空间std C++标准中引入命名空间的概念,是为了解决不同模块或者函数库中相同标识符冲突的问题.有了命名空间的概念,标识符就被限制在特定的范围(函数)内,不会引起命名冲突.最典型的例子就是st ...
- python标准库00 学习准备
Python标准库----走马观花 python有一套很有用的标准库.标准库会随着python解释器一起安装在你的电脑上的.它是python的一个组成部分.这些标准库是python为你准备的利器,可以 ...
随机推荐
- shell脚本实现文件的自动上传以及下载 scp sftp lftp 还有expect命令
转至: 最近需求要求定期从一个[定期更新的文件] 中解析员工信息 ,插入到数据库中. 按理来说很简单, 无非就是io流读文件,然后crud balalalala..... 其实不是的, 我我写的这个 ...
- 教程10--hexo搭建
1.安装node.js 下载系统对应的node安装包一直下一步完成 2.安装git 参照git安装https://www.cnblogs.com/daxiang2008/p/10687616.html ...
- 『无为则无心』Python日志 — 67、logging日志模块处理流程
目录 1.概括理解 2.详细说明 3.应用示例 1.概括理解 了解了四大组件的基本定义之后,我们通过图示的方式来理解下信息的传递过程: 也就是获取的日志信息,进入到Logger日志器中,传递给处理器确 ...
- AndroidMainifest.xml文件属性
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package=" ...
- pyqt(三)
六.按钮控件 QPushButton 常见的按钮实现类包括:QPushButton.QRadioButton和QCheckBox QPushButton是最普通的按钮控件,可以响应一些用户的事件 fr ...
- pip安装包失败的常见解决方法
pip安装包失败的常见解决方法 方法一 当安装包失效的时候可以去网站下载whl文件.下载的时候应该先查看电脑上 python 的版本. 地址:https://www.lfd.uci.edu/~gohl ...
- QQ音乐官方定制精简版v1.3.6 纯净无广告
介绍 近期腾讯推出了QQ音乐简洁版.顾名思义,QQ音乐简洁版就是官方精简后的版本,没有内置任何广告.完全专注于听歌,不存在直播.K歌.短视频等花里胡哨的内容.如有违规,请删删.. 结尾附pc端 QQ音 ...
- MM32F0140 UART1中断接收和UART1中断发送
目录: 1.MM32F0140简介 2.初始化MM32F0140 UART1和NVIC中断 3.编写MM32F0140 UART1使能中断发送函数 4.编写MM32F0140 UART1中断接收和中断 ...
- Latex 特殊字符汇总
- tensorflow源码解析之framework-allocator
目录 什么是allocator 内存分配器的管理 内存分配追踪 其它结构 关系图 涉及的文件 迭代记录 1. 什么是allocator Allocator是所有内存分配器的基类,它定义了内存分配器需要 ...