HAL库--20170905
HAL库,全称Hardware Abstract Layer,也叫硬件抽象层。这里简单介绍一下利用cubeMX生成的程序结构。
这里的例子是stm32f103中的一个电机驱动程序,程序本身不重要,主要是看自动生成的程序的结构。
先看整个工程:
一共四个文件夹。
第一个文件夹是stm32f1xx_hal_driver,可以看作是以前的库函数文件夹。里面的c文件有三种:stm32f1xx_hal_ppp.c,stm32f1xx_hal_ppp_ex.c,stm32f1xx_hal.c。其中ppp代表外设名,stm32f1xx_hal_ppp.c包含了外设ppp相关的函数,stm32f1xx_hal_ppp_ex.c包含外设ppp的一些拓展函数,stm32f1xx_hal.c包含HAL库的初始化函数。后面会介绍一些其中的函数。
第二个文件夹是用户文件夹application/user,意味着里面的文件是根据用户自己的需求修改的,工程刚生成的时候有三个c文件:main.c,stm32f1xx_hal_msp.c,stm32f1xx_it.c。
stm32f1xx_it.c是中断文件,虽然在用户文件夹中,但是从来对它进行修改。需要写中断服务函数时,直接重新在main.c文件中写对应的回调函数即可。
stm32f1xx_hal_msp.c文件是一个比较重要的文件,虽然平时也不会对它进行修改。msp在这里是MCU specific package的缩写,可以理解为特别的包,“特别”是指这个文件里面的一些参数是由用户自己提供的,不是库自带的。在工程初始化的过程中,它会先用一个通用的初始化函数初始化一遍,然后再用带有用户给的参数的初始化函数初始化。后半段过程就需要msp这个文件里的函数,另外,带有用户参数的函数也会使用msp在函数名中体现出来,例如HAL_MspInit()与HAL_Init()。
main.c是主函数,下面过一遍主函数的执行流程。
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART2_UART_Init();
整体上看,首先是调用HAL_Init()函数对外设、flash接口与systick计时器进行初始化,然后是配置时钟,最后初始化外设。
具体到每个函数,在HAL_Init()函数中,按照默认的参数配置完优先级等参数,最后调用了HAL_MspInit()函数。这个函数在工程中一共有两个,一个由_weak定义,存在于库函数中。另一个在stm32f1xx_hal_msp.c中,按照用户的参数初始化了优先级等参数。第二个函数的存在会覆盖_weak定义的函数,这就起到了一个便于移植的效果。移植只需要更改用户文件里的东西,一方面,工程初始化时都会先使用默认的参数初始化一遍,即使不小心移植漏了一些配置代码,也不会出现致命的错误。另一方面,只需要改一个文件里的内容,即使不懂驱动层也可以改程序。
说完了HAL_Init()函数的工作方式,外设的初始化也是同样的思想。例如,对spi外设初始化的函数MX_SPI!_Init(),首先将用户的参数存在一个SPI的结构体中,再调用HAL_SPI_Init(&hspi1),该函数首先检查参数是否正确,然后就调用了HAL_SPI_MspInit(hspi),注意这里已经将前面提到的SPI结构体作为参数赋予了msp初始化函数。最终就根据SPI结构体的值,通过HAL_SPI_MspInit()函数进行初始化的过程,包括模式的选择、优先级的配置等等。
下一篇: 伦敦奥运会拒绝开源软件 称存在太多风险