随着时代的逐步发展,联网、USB、文件系统、加密算法、RTOS、GUI等第三方组件变得越来越重要,简陋的标准库已经很难满足当代单片机开发需求了。
事实上,单片机开发在走PC、手机等以CPU为核心的产品的老路:底层和细节越来越成熟,ARM提供CPU的库、单片机厂商提供外设库,单片机软件工程师直接基于这些库来构建自己的应用。现在更倾向于提供一整套开发生态而不只是一个SDK包,于是HAL库应运而生,提供HAL抽象层驱动来加速产品移植和选型,增加客户粘度。
STM32软件开发的各种模式
第1代:寄存器开发
第2代:标准库开发
第3代:HAL/LL库 + STM32CubeMX工具开发
- HAL(hardware abstract layer)、LL(lowerlevel layer)
- HAL库的优势是便于在不同型号的STM32芯片之间移植,劣势是代码效率低。标准外设库可以很简单直接跟踪到底层寄存器,而HAL库里面的代码想要跟踪并理解底层很难。
- LL库几乎等同于直接操作寄存器
- CubeMX工具是ST的一站式开发包,层级高于SDK包,包含了STM32芯片开发的所有官方资源,提供了友好的使用方法;CubeMX是一个windows上的IDE软件;CubeMX是一个工具包加芯片容器,各系列芯片资料以插件补丁形式安装;
- HAL/LL库和CubeMX本质上是独立的东西,只是使用上纠缠在一起了而已。
- CubeMX和Keil MDK是不同作用的东西,要搞清楚。
那到底什么是HAL库呢?
STM32 HAL固件库是Hardware Abstraction Layer的缩写,中文名称是:硬件抽象层。HAL库是ST公司为STM32的MCU最新推出的抽象层嵌入式软件,为更方便的实现跨STM32产品的最大可移植性。HAL库的推出,可以说ST也慢慢的抛弃了原来的标准固件库,这也使得很多老用户不满。但是HAL库推出的同时,也加入了很多第三方的中间件,有RTOS,USB,TCP / IP和图形等等。
和标准库对比起来,STM32的HAL库更加的抽象,ST最终的目的是要实现在STM32系列MCU之间无缝移植,甚至在其他MCU也能实现快速移植。
并且从16年开始,ST公司就逐渐停止了对标准固件库的更新,转而倾向于HAL固件库和 Low-layer底层库的更新,停止标准库更新,也就表示了以后使用STM32CubeMX配置HAL/LL库是主流配置环境。
HAL库目录结构
STM32Cube_FW_F1_V1.8.4
HAL库的目录内容如下所示:
在第二个Documentation中有个文档,里面有目录结构说明:
相对标准库,重点多了个BSP,这里面放的是板级支持包,针对的是ST官方出的几款特定开发板。
另外,中间件也需要重点关注下。
其他和标准库的很类似,此处不赘述。
HAL项目解读
HAL工程创建后的文件目录如下:
其中.ioc就是mx项目文件。可双击后打开进行修改。用记事本打开,可以看到其内容,比如以下是该文件开头部分的几行:
注意:不同的MX版本、不同的固件版本、不同的芯片,其项目目录都可能有所差别。
所以,需要掌握本质的东西,才能举一反三。
重点关注各文件,以及文件的作用。
Core目录
这一块不要死记硬背,关键是要学会阅读源码。
Core目录应该是和内核相关的程序代码。
main文件
在main文件中,主要实现了如下功能:
在MX中配置的引脚的宏定义;
系统时钟配置;
引脚初始化;
stm32f1xx_hal_conf.h
这里面主要是一些配置信息。
模块使能的宏定义
定义各时钟源默认的时钟值
关于回调函数等的一些配置
网络相关的配置
SPI_CRC配置
指定模块的头文件包含
断言定义
stm32f1xx_it
定义了系统异常处理函数
需要处理中断直接在里面指示的位置写,调用和管理等都会交由 HAL 库完成。
头文件
c文件中基本都是空的,需要自己去定义如何处理这些异常
stm32f1xx_hal_msp.c
MSP即MCU Specific Package,也就是和具体的单片机相关的一些配置。例如在普通的 Init 函数中设置的是与具体 MCU 无关的参数,MspInit 中就会有些关于具体引脚的配置。举例来说,用 CubeMX 自动生成 USART 和 DMA 的配置,那么 MX_USART1_UART_Init 函数里面就会配置 USART 的一些约定参数例如波特率等,而在 HAL_UART_MspInit 函数中就会配置例如 USART 占用具体哪个脚,配置 DMA 占用哪个通道和其他参数等。
system_stm32f1xx.c
文件里面已经讲到了,重点如下:
SystemInit()初始化系统时钟;
SystemInit()在启动文件中被调用,且在复位之后,跳转到main之前被执行;
另外就是一个内核时钟HCLK变量以及和时钟更新函数。
MDK-ARM目录
这个目录里主要是生成的Keil工程。
除了.uvprojx之外,还有一个比较重要的文件,那就是startup_stm32f103xe.s
这就是程序的启动文件,主要是进行底层的初始化。
比如:
内存空间的相关设置
中断向量表定义
异常的系统化处理
比如在复位异常中,就能看到先执行的SystemInit函数,然后再执行main函数。
再就是堆栈的初始化
Drivers目录
STM32F1xx_HAL_Driver
这里面就是各个外设的驱动程序。
里面包含了HAL和LL的库文件,我们重点关注HAL库文件。
另外,对于有的外设,除了有常规的文件,还有一个ex扩展文件。
常规文件中是一些常用的功能,ex中是一些相对复杂不太常用的功能。
另外,在该目录中,还有一个不是特定外设的文件
stm32f1xx_hal
这个文件里放的是跟系统相关的一些内容
比如Tick时钟频率
各外设Debug模式的宏定义;
初始化/去初始化
Tick相关函数/省电模式相关函数/获取版本/获取ID号等函数
CMSIS目录
这里面内容比较多。
几个比较重要的文件提一下。
Device\ST\STM32F1xx\Include
stm32f1xx.h
这里面主要是选择设备、版本号、一些标志位状态位、头文件包含、带参宏等等。
具体查看源码。
stm32f103xe.h
另外,CMSIS\Device\ST\STM32F1xx\Source\Templates\arm
这里面有arm单片机的一些启动文件。
其他目录暂时不管,有需要再去看看。
打开MDK-ARM下的工程文件:
工程目录如下:
不赘述。
注意:
自动生成的project目录结构和名称等都是既定的,最好不要改;
由CubeMX工程到MDK工程是单向的,不能逆向同步;
STM32CubeMX工具只是生成工程和外设初始化代码,大量开发工作还是靠自己的;
HAL库是一套体系,有自己的架构,必须理解透彻,否则会有无处下手的感觉;
因为HAL库很庞大,整个编译一次很久,所以建议要点build而不是rebuild;
源码简读
自行阅读源码。
做好必要的记录。