整个STM32 HAL库总结了STM32 HAL库的详细情况和手动移植
本博客是对上述参考资源的二次总结和整理。
1 .对HAL库的文件结构开发人员来说,首先要弄清HAL库的文件结构。
根据文件类型的不同,可能有以下两个类别:
库文件: stm32f2xx_hal_ppp.c/.h//主要外围设备或模块的驱动程序源文件。 包含此外围设备的通用APIstm32f2xx_hal_ppp_ex.c/.h//外围设备或模块驱动程序扩展文件。 此文件包含特定型号或系列芯片的特殊API。 以及如果该特定芯片内部有不同的实现方式,则该文件中的特殊API将复盖_ppp中的通用API。 stm32f2xx_hal.c/.h//此文件用于初始化HAL,并包含相关的API和其他库文件用户级文件,如DBGMCU、重新映射和基于systick的延迟时间。 仅stm32f2xx_hal_msp_template.c//包含使用者APP应用程式中使用之周边设备的MSP初始化和反向初始化(主程式和回呼功能)。 用户将复制到自己的目录中并使用模板。 STM 32 f2xx _ Hal _ conf _ template.h//用户级库配置文件模板。 用户将复制到自己的目录中并使用system_stm32f2xx.c//。 此文件主要包含SystemInit ) )函数,在重置为main并即将跳转之前的启动过程中调用该函数。 **启动时不设置系统时钟**。 与标准库相反。 的配置是在用户文件中使用HAL API完成的。 startup_stm32f2xx.s//芯片启动文件主要是stm32f2xx_it.c/.h//中断服务函数的相关实现main.c/.h//,例如堆栈定义、终端表
http://www.Sina.com/main.c/. h http://www.Sina.com/STM 32 f2xx _ Hal _ MSP _ template.c http://www.Sina.com/STM
http://www.Sina.com/http://www.Sina.com/http://www.Sina.com /关于这三点,也请参考了解。
主函数:
HAL库在结构上为每个外围设备抽象为结构MSP初始化:,其中ppp是每个外围设备的名称。
与标准库的结构相比,中断服务函数:(例如,用户想要使用ADC,句柄),只要为不同的APP场景放置不同的结构成员就满足使用要求
MSP
MSP ) MCUspecificpackage,单片机具体方案(指回调函数
初始化函数有两个部分:
部分与MCU无关的通信协议; 部分与MCU相关,为引脚功能。 这里可以结合博客关于串行的说明USART and UART来理解。
以串行端口为例,使用3358www.Sina.com/函数初始化串行端口的波特率、停止位、奇偶校验等。 本部分的代码与1、关于句柄相关,与具体引脚无关,因此与MCU无关,是抽象的。
staticvoidmx _ usar t1 _ UART _ init (void ) { huart1.Instance=USART1; huart1.Init.BaudRate=115200; huar t1.init.word length=UART _ word length _ 8b; huar t1.init.stop bits=UART _ stop bits _ 1; huar t1.init.parity=UART _ parity _ none; huar t1.init.mode=UART _ mode _ tx _ rx; huar t1.init.hwflowctl=UART _ HW control _ none; huar t1.init.over sampling=UART _ over sampling _ 16; huar t1.init.onebitsampling=UART _ one _ bit _ sample _ disable; huar t1.advanced init.advfeatureinit=UART _ adv feature _ no _ init; if(Hal_Uart_init ) HuarT1 )!=HAL_OK ) {_error_handler(__file_,__LINE__ ); }_Hal_Uart_enable_it(HuarT1,UART_IT_IDLE );ppp_HandleTypeDef
l_msp.c 文件中的 HAL_UART_MspInit(UART_HandleTypeDef* huart) 函数中将串口所时用的 MCU 引脚模式进行配置,这部分是与 MCU 具体相关的。
void HAL_UART_MspInit(UART_HandleTypeDef* huart){ // 关于 GPIO 引脚初始化的流程与上面介绍的“四步”相同 GPIO_InitTypeDef GPIO_InitStruct; if(huart->Instance==USART2) // USART 2 { /* USER CODE BEGIN USART2_MspInit 0 */ /* USER CODE END USART2_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_USART2_CLK_ENABLE(); // 使能串口时钟 /**USART2 GPIO Configuration PA2 ——> USART2_TX PA3 ——> USART2_RX */ GPIO_InitStruct.Pin = USART2_TX_Pin|USART2_RX_Pin; // 收发引脚 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出 GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_USART2; // 复用功能配置 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 结构体初始化 /* USART2 DMA Init */ // DMA 方式收发初始化 /* USART2_RX Init */ hdma_usart2_rx.Instance = DMA1_Channel3; hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_rx.Init.Mode = DMA_NORMAL; hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } __HAL_DMA1_REMAP(HAL_DMA1_CH3_USART2_RX); __HAL_LINKDMA(huart,hdmarx,hdma_usart2_rx); /* USART2_TX Init */ hdma_usart2_tx.Instance = DMA1_Channel4; hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_tx.Init.Mode = DMA_NORMAL; hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } __HAL_DMA1_REMAP(HAL_DMA1_CH4_USART2_TX); __HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx); /* USART2 interrupt Init */ HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART2_IRQn); /* USER CODE BEGIN USART2_MspInit 1 */ /* USER CODE END USART2_MspInit 1 */ }}
3、回调函数
在标准库中,串口中断了以后,我们要先在中断中判断是否是接收中断,然后读出数据,顺便清除中断标志位,然后再是对数据的处理。这样如果我们在一个中断函数中写这么多代码,就会显得很混乱。
而在HAL库中,以GPIO为例,进入中断后,直接由HAL库中断函数HAL_GPIO_EXTI_IRQHandler() 进行托管。
而该函数主要完成两项任务:
清除中断标志位调用回调函数处理中断 // EXIT 外部中断服务函数void EXTI0_1_IRQHandler(void){ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);}// HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10)函数如下void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin){ /* EXTI line interrupt detected */ if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin); }}
在回调函数内对中断进行处理,这种方式增强了代码的逻辑性,但也增加了文件的嵌套程度。
3. HAL库编程方式
在 HAL 库中对外设模型进行了统一,支持三种编程方式:
轮询模式/阻塞模式中断方式DMA模式
以IIC为例,三种编程模式对应的函数如下:
1、轮询模式/阻塞模式
HAL_I2C_Master_Transmit(); HAL_I2C_Master_Receive(); HAL_I2C_Slave_Transmit(); HAL_I2C_Slave_Receive()HAL_I2C_Mem_Write(); HAL_I2C_Mem_Read(); HAL_I2C_IsDeviceReady()
2、中断模式
HAL_I2C_Master_Transmit_IT(); HAL_I2C_Master_Receive_IT(); HAL_I2C_Slave_Transmit_IT()HAL_I2C_Slave_Receive_IT(); HAL_I2C_Mem_Write_IT(); HAL_I2C_Mem_Read_IT()
3、DMA模式
HAL_I2C_Master_Transmit_DMA(); HAL_I2C_Master_Receive_DMA(); HAL_I2C_Slave_Transmit_DMA(); HAL_I2C_Slave_Receive_DMA(); HAL_I2C_Mem_Write_DMA(); HAL_I2C_Mem_Read_DMA()