likes
comments
collection
share

从代码层面分析STM32 标准库和HAL库的差异

作者站长头像
站长
· 阅读数 27

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情

  如果用过STM32系列单片机的朋友会比较清楚,一般在开发STM32单片机程序的时候首先要考虑选用那种方式来写代码。常见的有三种方式,寄存器版、标准库版、HAL库版。现在选用后两种的比较多,选择寄存器开发的可能比较少了。而后两种方式到底选用那种好呢?现在都是公说公有理,婆说婆有理,每个人的判断标准都不同。今天我不探讨这两种方式的优缺点,单纯的从代码的角度去分析对比这两种方式写代码的相同点和差异。

  为了更有对比性,我选择了功能一模一样的LED灯程序,一个是用标准库写的,一个是HAL库写的。 从代码层面分析STM32 标准库和HAL库的差异   看到这个文件名字,我想大多数人都比较熟悉了恶,我这里就不多做介绍,直接开始从代码的角度出去,去比较。 从代码层面分析STM32 标准库和HAL库的差异   左边的是HAL库,右边的是标准库,端口的初始化暂时先不看,直接看对IO口的操作。可以看出HAL库对端口置1和置0时,调用的是同一个函数,只是函数的参数不同。右边的标准库调用的是两个不同的函数,但是参数是一样的。下面直接对比一下端口设置的库函数。

从代码层面分析STM32 标准库和HAL库的差异   这两个版本的函数本质上操作的还是寄存器,不过HAL库操作的只是BSRR寄存器,而标准库端口置1的时候操作的是BSRR寄存器,端口清0的时候操作的是BRR寄存器。下面看看BSRR和BRR寄存器的区别。

从代码层面分析STM32 标准库和HAL库的差异 从代码层面分析STM32 标准库和HAL库的差异   通过官方的寄存器手册可以看出,BRR寄存器实际上就是BSRR寄存器的高16位,给BSRR寄存器的高16位写1就是清0对应端口,给BSRR低16位写1就是置1对应端口。

从代码层面分析STM32 标准库和HAL库的差异   在HAL库函数中可以看到,当传入的参数是 GPIO_PIN_RESET时,就左移16位,也就是给BSRR的高16位写1。

  通过对比可以看出,HAL库和标准库都是操作寄存器来实现端口输出高低电平的,唯一的区别就是HAL库将标准库的两个函数合成为一个,通过参数来区别。而标准库是参数不变,而调用的函数名发生了变化。

  接下来对比对LED端口的初始化。

从代码层面分析STM32 标准库和HAL库的差异   可以看到端口时钟使能的函数不一样了,HAL库是通过两个独立的函数来实现,没有参数,标准库是通过一个函数传入参数来实现的。下来进一步查看这两种的区别。

从代码层面分析STM32 标准库和HAL库的差异   HAL库将一段代码通过宏定义的方式封装成了一个函数,每个端口的时钟都单独的定义了一个名称,标准库是一个独立的函数,通过参数传递的方式来设置每个端口的时钟。但是它们操作的是依然都是 APB2ENR寄存器。

  接下来看GPIO口的初始化函数。 从代码层面分析STM32 标准库和HAL库的差异   这两个函数的入口参数都是一样的。

从代码层面分析STM32 标准库和HAL库的差异   将函数内部具体代码折叠起来可以看到,HAL库里面函数只有一个while循环,配置了端口的所有属性。而标准库里面是三个if语句,分别设置了引脚模式,端口的低16位,高16位。HAL库中的代码比标准库里面的代码多了很多行。

从代码层面分析STM32 标准库和HAL库的差异   标准库设置端口模式的时候,是在if语句中判断之后直接设置的,而HAL端口模式设置时,却使用了switch语句去设置,说明在HAL库中,端口模式和标准库中发生了改变。下面直接查看端口模式都具体有哪些。

从代码层面分析STM32 标准库和HAL库的差异   HAL库端口模式中,不仅包含了标准库中所有的端口模式,同时还多了几种模式。通过名字可以看出是外部事件模式和外部中断模式。

从代码层面分析STM32 标准库和HAL库的差异

  通过代码可以看出HAL库中端口中断模式和事件模式这块是空的,说明这个信号的单片机没有这种模式,也许其他型号的单片机就会有这种模式。继续往下看时,会发现HAL在GPIO初始化的时候,将IO的的中断模式也顺便配置了。而在标准库中,对中断的设置是堵路配置的。 从代码层面分析STM32 标准库和HAL库的差异    说明HAL库将关于IO口的所有属性都统一放到一个函数中处理了。既然提到了中断,那么在看看对于中断的配置,HAL库和标准库有什么区别。

   在找两个程序进行对比。

从代码层面分析STM32 标准库和HAL库的差异    这里将按键作为外部中断输入,首先看按键初始化。

从代码层面分析STM32 标准库和HAL库的差异    最开始是对按键端口的时钟进行使能,这个已经看过了,就不在进行对比了。接下来是IO口模式的设置,HAL库中将输入输出模式和上下拉模式分成了两个独立的参数,而标准库中上下拉和输入输出模式是合在一起的。    接下来看中断的初始化。

从代码层面分析STM32 标准库和HAL库的差异    可以看到HAL库中对中断的设置代码比较少,标准库中对中断的设置代码比较多。同时还发现HAL库中IO的设置中断时,直接在GPIO的属性里面设置就可以了,不需要在调用按键端口的初始化函数了。但是在标准库中,还需要先初始化按键端口,将按键设置为输入模式,然后在调用EXTI_Init()函数,对中断进行初始化,最后在调用NVIC_Init()函数,分别设置每个中断的优先级。相当于每个设置都是独立的函数。而在HAL库是将中断的设置直接集成在了GPIO口设置函数中,同时中断的中断源和中断优先级设置,都是通过调用函数,传递参数的方式进行设置的。代码写起来就比较少。

从代码层面分析STM32 标准库和HAL库的差异    最后看对中断函数的处理,标准库是在中断函数中直接处理代码,而HAL库在中断处理函数中又调用了公用的中断处理函数,在公用的中断函数中统一处理中断程序。

   通过上面的这些分析可以看出,标准库函数是对寄存器简单的进行了一次封装。将每个功能都独立的封装成一个函数。每个函数的功能比较单一。而HAL库相当于对寄存器进行了二次或者三次的封装,它将能合并的功能都合并在了一起。减小了写代码的难度。但是库函数本身阅读起来要比标准库要费劲一些。这样就对导致,如果程序出错的话调试起来要比标准库难一点。但是HAL写程序却比较简单,函数的名字也更容易理解。更接近于面向对象的思想。

  通过对比可以看出,没有那种方式更好,每种都有自己的优缺点,根据实际情况,自己喜欢用哪种就用那种。通过对官方的这两种库的对比,可以看出在产品开发中代码永远都有优化和改进的空间。以后自己在开发项目的时候,也可以用这两种不同的方式对自己的代码进行优化升级。