完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1. HAL库文件结构
对于开发人员而言,首先要清楚 HAL 库的文件结构。 根据文件类型可认为以下两大类: 库文件: stm32f2xx_hal_ppp.c/.h // 主要的外设或者模块的驱动源文件,包含了该外设的通用API stm32f2xx_hal_ppp_ex.c/.h // 外围设备或模块驱动程序的扩展文件。这组文件中包含特定型号或者系列的芯片的特殊API。以及如果该特定的芯片内部有不同的实现方式,则该文件中的特殊API将覆盖_ppp中的通用API。 stm32f2xx_hal.c/.h // 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的时间延迟等相关的API 其他库文件 用户级别文件: stm32f2xx_hal_msp_template.c // 只有.c没有.h。它包含用户应用程序中使用的外设的MSP初始化和反初始化(主程序和回调函数)。使用者复制到自己目录下使用模板。 stm32f2xx_hal_conf_template.h // 用户级别的库配置文件模板。使用者复制到自己目录下使用 system_stm32f2xx.c // 此文件主要包含SystemInit()函数,该函数在刚复位及跳到main之前的启动过程中被调用。 **它不在启动时配置系统时钟(与标准库相反)**。 时钟的配置在用户文件中使用HAL API来完成。 startup_stm32f2xx.s // 芯片启动文件,主要包含堆栈定义,终端向量表等 stm32f2xx_it.c/.h // 中断服务函数的相关实现 main.c/.h // 与我们密切相关的有 主函数: main.c/.h MSP初始化: stm32f2xx_hal_msp_template.c 中断服务函数: stm32f2xx_it.c/.h 2. HAL库用户代码 HAL 库对底层进行了抽象,在此结构下,用户代码处理可分为三大部分: 句柄 MSP 回调函数 关于这三点,也可参考这里进行理解, 1、关于句柄 HAL库在结构上,对每个外设抽象成了一个称为ppp_HandleTypeDef的结构体,其中ppp就是每个外设的名字。 与标准库中的结构体相比,HAL 库中的结构体包含了其可能出现的所有定义,比如用户想要使用ADC,只要定义一个ADC_HandleTypeDef的全局变量,针对不同的应用场景配置不同结构体成员就可以满足使用要求。 2、MSP MSP(MCU Specific Package,单片机的具体方案),是指和MCU相关的初始化 初始化函数包含的内容可分为两部分: 一部分是与MCU无关的,通信协议; 一部分是与MCU相关的,引脚功能。 这里可以结合博主关于串口的说明USART and UART进行理解。 以串口为例,在 MX_USART1_UART_Init(void) 函数中初始化串口的波特率、停止位、奇偶校验等,这部分代码是与串口协议相关的,并未涉及到具体的引脚,因此与 MCU 是无关的,是抽象的。 static void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); } 在 stm32f0xx_hal_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() |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1792 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1626 浏览 1 评论
1094 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
732 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1682 浏览 2 评论
1943浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
740浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
577浏览 3评论
600浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
562浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 03:56 , Processed in 0.606630 second(s), Total 49, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号