完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1.问题提出
在STM32的HAL库使用中,会发现库函数大都被设计成了一对: HAL_PPP/PPPP_Init HAL_PPP/PPPP_MspInit 而且HAL_PPP/PPPP_MspInit函数的defination前面还会有__weak关键字 上面的PPP/PPPP代表常见外设的名称为3个字符或者4个字符 怎么理解这个设计呢? 2.问题分析 2.1 结论 首先说结论: HAL_PPP/PPPP_Init 是与具体芯片(无论是STM32F4/F1/F7)无关的设置 HAL_PPP/PPPP_MspInit 是与具体芯片相关的配置(如STM32F429IGTx) 这样的设计是将不变的东西以库函数HAL_PPP/PPPP_Init的形式固定下来,而将需要用户根据 芯片进行编写的部分抽象成函数HAL_PPP/PPPP_MspInit的形式,用户只需要编写这部分函数 即可,这样做减少了用户的代码编写量 __weak关键字的使用是定义一个弱函数,这个函数的函数体通常是空的 方便用户重写一个自己的函数HAL_PPP/PPPP_MspInit,来覆盖之前库函数中定义的函数带有 __weak关键字的HAL_PPP/PPPP_MspInit函数,编译器在编译的时候,如果检查到有重名的 (但不含__weak关键字)HAL_PPP/PPPP_MspInit的函数,此时就会默认编译这个用户写的函数 2.2 实例分析 下面以串口通信为例进行分析: 在编写串口通信的代码的时候,常使用正点原子提供的usart.c&usart.h组合,正点原子在usart.c中 定义了HAL_UART_MspInit作为回调函数: void HAL_UART_MspInit(UART_HandleTypeDef *huart) { // GPIO configuration GPIO_InitTypeDef GPIO_Initure; if(huart->Instance==USART1) { __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA 时钟 __HAL_RCC_USART1_CLK_ENABLE(); // 使能USART1 时钟 GPIO_Initure.Pin=GPIO_PIN_9; //PA9 GPIO_Initure.Mode=GPIO_MODE_AF_PP; // AF复用,PP为推挽(push pull) GPIO_Initure.Pull=GPIO_PULLUP; // 设置上拉 GPIO_Initure.Speed=GPIO_SPEED_FAST; // 设置为高速 GPIO_Initure.Alternate=GPIO_AF7_USART1; // 复用为USART1 HAL_GPIO_Init(GPIOA,&GPIO_Initure); // 初始化PA9 GPIO_Initure.Pin=GPIO_PIN_10; //PA10 HAL_GPIO_Init(GPIOA,&GPIO_Initure); // 初始化PA10 #if EN_USART1_RX HAL_NVIC_EnableIRQ(USART1_IRQn); // 使能USART1中断通道 HAL_NVIC_SetPriority(USART1_IRQn,3,3); // 抢占优先级3, 子优先级3 #endif } } 这个库同时提供了一个调用串口初始化的接口:void uart_init(u32 bound) // bound为波特率 void uart_init(u32 bound) { //UART initialization UART1_Handler.Instance=USART1; // USART1 UART1_Handler.Init.BaudRate=bound; // 设置波特率 UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; // 字长为8位的数据格式 UART1_Handler.Init.StopBits=UART_STOPBITS_1; // 一个停止位 UART1_Handler.Init.Parity=UART_PARITY_NONE; // 无奇偶校验位 UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; // 无硬件流控 UART1_Handler.Init.Mode=UART_MODE_TX_RX; // 收发模式 HAL_UART_Init(&UART1_Handler); // HAL_UART_Init() 会使能UART1 HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE); // 该函数会开启接收中断,标志位UART_IT_RXNE,并设置接收缓冲以及接收缓冲的最大接收数量 } 这样在main函数中,首先调用函数uart_init() 然后uart_init()函数就会去调用HAL_UART_Init,这个函数就是HAL库中的函数 跳转到文件stm32f4xx_hal_uart.c,找到函数HAL_UART_Init的定义: /** * @brief Initializes the UART mode according to the specified parameters in * the UART_InitTypeDef and create the associated handle. * @param huart: pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval HAL status */ HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart) { /* Check the UART handle allocation */ if(huart == NULL) { return HAL_ERROR; } /* Check the parameters */ if(huart->Init.HwFlowCtl != UART_HWCONTROL_NONE) { /* The hardware flow control is available only for USART1, USART2, USART3 and USART6 */ assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance)); assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl)); } else { assert_param(IS_UART_INSTANCE(huart->Instance)); } assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength)); assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling)); if(huart->gState == HAL_UART_STATE_RESET) { /* Allocate lock resource and initialize it */ huart->Lock = HAL_UNLOCKED; /* Init the low level hardware */ HAL_UART_MspInit(huart); } huart->gState = HAL_UART_STATE_BUSY; /* Disable the peripheral */ __HAL_UART_DISABLE(huart); /* Set the UART Communication parameters */ UART_SetConfig(huart); /* In asynchronous mode, the following bits must be kept cleared: - LINEN and CLKEN bits in the USART_CR2 register, - SCEN, HDSEL and IREN bits in the USART_CR3 register.*/ huart->Instance->CR2 &= ~(USART_CR2_LINEN | USART_CR2_CLKEN); huart->Instance->CR3 &= ~(USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN); /* Enable the peripheral */ __HAL_UART_ENABLE(huart); /* Initialize the UART state */ huart->ErrorCode = HAL_UART_ERROR_NONE; huart->gState= HAL_UART_STATE_READY; huart->RxState= HAL_UART_STATE_READY; return HAL_OK; } 可以看到函数HAL_UART_Init中调用了函数HAL_UART_MspInit 在库文件中本身是有一个同名的使用__weak关键字定义的函数, /** * @brief UART MSP Init. * @param huart: pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval None */ __weak void HAL_UART_MspInit(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ UNUSED(huart); /* NOTE: This function Should not be modified, when the callback is needed, the HAL_UART_MspInit could be implemented in the user file */ } 由于使用了正点原子的库,所以编译器在编译的时候就不会再编译这个HAL库自带的函数HAL_UART_MspInit 而是编译引入的库函数HAL_UART_MspInit 3. STM32程序的一般执行流程 由上面1.2节的分析,对于一个真实的STM32应用程序可以总结其运行一般执行(编写)流程如下: 以一个真实的点亮跑马灯的main.c为例进行分析(工程使用HAL库): #include "sys.h" #include "delay.h" #include "usart.h" void Delay(__IO uint32_t nCount); void Delay(__IO uint32_t nCount) { while(nCount--){} } int main(void) { GPIO_InitTypeDef GPIO_Initure; HAL_Init(); Stm32_Clock_Init(360,25,2,8); __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; GPIO_Initure.Pull=GPIO_PULLUP; GPIO_Initure.Speed=GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOB,&GPIO_Initure); while(1) { HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); Delay(0x7FFFFF); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); Delay(0x7FFFFF); } } 这里插入正点原子的图进行解释: 一个项目首先是引导程序先运行,汇编函数会引导SystemInit函数进行系统初始化的设置,再HAL库版本的项目中有这个函数的定义,在寄存器版本中通常会将汇编代码中引导SystemInit函数的语句删掉。然后引导程序会引导main函数,main函数被引导完成之后就会开始执行用户写的main函数中的代码。然后HAL_Init()函数会调用函数进行全局的MSP初始化,然后调用了正点原子提供的库函数Stm32_Clock_init函数,这个函数调用HAL_RCC_Oscconfig和HAL_RCC_ClockConfig函数进行系统时钟初始化,使用该函数需要导入SYSTEM库(正点原子提供),上面的一系列初始化都是常规操作,也就是每一个项目必做的系统的初始化。下面正式进入了用户自己编写得到逻辑,假设用户要使用PPP外设,那么就会调用HAL库中的函数HAL_PPP_Init,这个函数又会去尝试调用用户自定义的HAL_PPP_MspInit,然后进入用户自己定义的逻辑。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1614 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1541 浏览 1 评论
970 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
682 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1592 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 01:12 , Processed in 0.813384 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号