完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
HAL名带msp的函数功能:MCU Specific Package 单片机的具体方案,即MSP是指和MCU相关的初始化
HAL名带MX前缀的函数:应该是与CubeMX相关(可能是与MX通用的意思) 带Config的一般是配置某种外设或者RCC,EXTI等的参数,一般不是库函数内的。 带IT的一般与中断有关(Interrupt) 小技巧
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin==(GPIO_PIN_5)){ } else if(GPIO_Pin==(GPIO_PIN_12)){ } }
开启PWM HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel); HAL_TIM_Base_Init(&htim2) 作用:应用参数基本参数配置对应定时器 CubeIDE中下面的函数很常见,一般这种函数之前会有对应的配置函数,然后在这里判断,如果判断条件成立,即HAL_TIM_Base_Init(&htim2) != HAL_OK,表示之前配置出错,调用错误处理函数Error_Handler(); if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } HAL_TIM_Base_MspInit(htim) 作用:初始化中断信息(该函数需要重写,CubeMX在配置生成代码时会自动重写该函数) 注意,该函数调用之后会重新设置寄存器的值,可以在 HAL_TIM_Base_Init(&htim2) 之后使能TIM中断,并清理TIM的更新中断寄存器 重写实现: void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM2) { /* USER CODE BEGIN TIM2_MspInit 0 */ /* USER CODE END TIM2_MspInit 0 */ /* TIM2 clock enable */ __HAL_RCC_TIM2_CLK_ENABLE(); /* TIM2 interrupt Init */ HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspInit 1 */ //清理TIM开启时的中断标识 __HAL_TIM_CLEAR_FLAG(tim_baseHandle, TIM_SR_UIF);//添加这条语句解决问题 //htim2.Instance->SR = 0; //这是另一种解决办法 //使能TIM中断 HAL_TIM_Base_Start_IT(tim_baseHandle); /* USER CODE END TIM2_MspInit 1 */ } } HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *TIM); 作用:开启定时器中断 __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE); 作用:清理TIM开启时的中断标识 中断处理: /** * @brief This function handles TIM2 global interrupt. */ void TIM2_IRQHandler(void) { /* USER CODE BEGIN TIM2_IRQn 0 */ /* USER CODE END TIM2_IRQn 0 */ HAL_TIM_IRQHandler(&htim2); /* USER CODE BEGIN TIM2_IRQn 1 */ /* USER CODE END TIM2_IRQn 1 */ } 一般会调用到下面这个中断处理主函数(看不懂又不敢乱删系列): /** * @brief This function handles TIM interrupts requests. * @param htim TIM handle * @retval None */ void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) { /* Capture compare 1 event */ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET) { { __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1); htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1; /* Input capture event */ if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U) { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->IC_CaptureCallback(htim); #else HAL_TIM_IC_CaptureCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } /* Output compare event */ else { #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->OC_DelayElapsedCallback(htim); htim->PWM_PulseFinishedCallback(htim); #else HAL_TIM_OC_DelayElapsedCallback(htim); HAL_TIM_PWM_PulseFinishedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED; } } } // ///* TIM Update event */ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->PeriodElapsedCallback(htim); #else HAL_TIM_PeriodElapsedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } // // } 定时器溢出中断HAL_TIM_PeriodElapsedCallback(htim); 作用:当计数溢出时调用的回调函数,需要用户根据实际需求具体实现(一般定时器使用,输入捕获也可通过该函数记录溢出次数),输入捕获有其特有的跳变检测中断 /** * @brief Period elapsed callback in non-blocking mode * @param htim TIM handle * @retval None */ __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* Prevent unused argument(s) compilation warning */ UNUSED(htim); /* NOTE : This function should not be modified, when the callback is needed, the HAL_TIM_PeriodElapsedCallback could be implemented in the user file */ } 输入捕获中断HAL_TIM_IC_CaptureCallback void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(TIM4 == htim->Instance) { } } HAL_TIM_Base_MspDeInit /** * 函数功能: 基本定时器硬件反初始化配置 * 输入参数: htim_base:基本定时器句柄类型指针 * 返 回 值: 无 * 说 明: 该函数被HAL库内部调用 */ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base) { if(htim_base->Instance==ADVANCED_TIMx) { /* 基本定时器外设时钟禁用 */ ADVANCED_TIM_RCC_CLK_DISABLE(); } } HAL_TIM_Base_MspInit /** * 函数功能: 基本定时器硬件初始化配置 * 输入参数: htim_base:基本定时器句柄类型指针 * 返 回 值: 无 * 说 明: 该函数被HAL库内部调用 */ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) { if(htim_base->Instance==ADVANCED_TIMx) { /* 基本定时器外设时钟使能 */ ADVANCED_TIM_RCC_CLK_ENABLE(); } } HAL_TIM_MspPostInit /** * 函数功能: 定时器硬件初始化配置 * 输入参数: htim:定时器句柄类型指针 * 返 回 值: 无 * 说 明: 该函数被GENERAL_TIMx_Init函数调用 */ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim) { GPIO_InitTypeDef GPIO_InitStruct; if(htim->Instance==GENERAL_TIMx) { /* 定时器通道功能引脚端口时钟使能 */ GENERAL_TIM_GPIO_RCC_CLK_ENABLE(); /* 定时器通道3功能引脚IO初始化 */ GPIO_InitStruct.Pin = GENERAL_TIM_CH3_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStruct); } } HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 0, 0);//观察函数名及参数可知,该函数用于设置某中断的优先级 HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);//一般会附加下面的函数来使能中断 HAL_GPIO_TogglePin(GPIOx,GPIO_Pin);//翻转对应的IO口,“Toggle”意为“切换” FLASH HAL_FLASHEx_Erase 作用:擦除Flash相应地址的内容 if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)//调用擦除函数并检验是否完成擦除 { while (1) { /* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */ HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8); HAL_Delay(100); HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8); HAL_Delay(2000); } } HAL_FLASH_Program 作用:对Flash特定区域进行烧写,三个参数分别表示:在指定地址编程的方式,地址,烧写数据 if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, DATA_64) == HAL_OK) { Address = Address + 8; /* increment to next double word*/ } PWR低功耗 HAL_PWR_EnterSTOPMode 作用:进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒 PWR_EnterSTOPMode(PWR_Regulator,PWR_STOPEntry_WFI); 第一个参数要配置电源低功耗模式 第二个参数是模式,可选择中断唤醒还是事件唤醒,或者两者都要; 退出低功耗的方法是用外部中断方式唤醒(定时中断不是外部中断却能唤醒停止模式)。退出STOPMode后,根据手册说明,会自动选择HSI作为sysclock,因此如果系统之前采用的是非HSI作为Sysclock,则必须重新调用System_init(),对RCC部分进行重新初始化。否则会影响系统性能。 低功耗模式有三种, void PWR_EnterSleepMode(uint8_t PWR_SLEEPEntry); //睡眠模式 void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry); //停机模式 void PWR_EnterSTANDBYMode(void); //待机模式 #define PWR_Regulator_ON //电源不进低功耗 唤醒基本没延迟 #define PWR_Regulator_LowPower //电源进去低功耗 不过唤醒启动有一点延迟 #define PWR_STOPEntry_WFI //中断唤醒 #define PWR_STOPEntry_WFE //事件唤醒 待机模式下的唤醒结论如下: 停机模式下的唤醒结论如下:通用 assert_param 作用:检查参数1,判断参数1是否为参数2基址中的一个,只要有一个为真则其值为真,否则为假, 定义: #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t*)__FILE__, __LINE__)) HAL库似乎比较喜欢使用分流的方式来使用中断,以外部中断为例,都是直接触发后调用同一个中断函数EXTI15_10_IRQHandler(不同中断线不一样),然后在该中断函数中调用所有中断(不需要担心误调用,每个中断函数会有自己的标志位判断): void EXTI15_10_IRQHandler(void) { /* USER CODE BEGIN EXTI15_10_IRQn 0 */ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); /* USER CODE END EXTI15_10_IRQn 0 */ /* USER CODE BEGIN EXTI15_10_IRQn 1 */ /* USER CODE END EXTI15_10_IRQn 1 */ } 然后跳到中断处理函数,并判断其中断标志位,然后清除标志位,调用回调函数: 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); } } 一般在该函数下面会有一个弱函数: __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 也就是说,我们可以在 stm32f3xx_it.c 增加 HAL_GPIO_EXTI_Callback() 的实现 系统滴答定时器 HAL_RCC_GetHCLKFreq 作用:得到系统时钟的某一个参数 应用:(系统时钟为72MHz时) // HAL_RCC_GetHCLKFreq()/1000 1ms中断一次,即HAL_Delay函数延时基准为1ms // HAL_RCC_GetHCLKFreq()/100000 10us中断一次,即HAL_Delay函数延时基准为10us // HAL_RCC_GetHCLKFreq()/1000000 1us中断一次,即HAL_Delay函数延时基准为1us HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000000); // 配置并启动系统滴答定时器 一般后面会跟着这两句: /* 系统滴答定时器时钟源 */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* 系统滴答定时器中断优先级配置 */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); 系统滴答定时器的使用即通过对系统时钟进行分频得到一个定时中断 串口 UART有开关中断的现象,而不是中断一直开着。1、串口发送/接收函数 HAL_UART_Transmit();串口轮询模式发送,使用超时管理机制 HAL_UART_Receive();串口轮询模式接收,使用超时管理机制 HAL_UART_Transmit_IT();串口中断模式发送 HAL_UART_Receive_IT();串口中断模式接收 HAL_UART_Transmit_DMA();串口DMA模式发送 HAL_UART_Transmit_DMA();串口DMA模式接收 2、串口中断函数 HAL_UART_TxHalfCpltCallback();一半数据发送完成时调用 HAL_UART_TxCpltCallback();数据完全发送完成后调用 HAL_UART_RxHalfCpltCallback();一般数据接收完成时调用 HAL_UART_RxCpltCallback();数据完全接受完成后调用 HAL_UART_ErrorCallback();传输出现错误时调用 |
|
|
|
GPIO口操作
ADC(含DMA) HAL_ADC_Start_DMA 采集固定次数 开启ADC对应的DMA通道,此时,&ADC_Value为内存地址,最后的100是采集次数,如果需要不断得获取新的数值,则需要重新开启转换。 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value, 100); 连续不断地采集 Mode 改为Circular, Increment Address 的√去掉。注意:如果是多通道采集的话,Increment Address 的√不能去掉,否则会被多通道数据覆盖。较好选择是创建一个和通道数大小相同的数组,这样依次存放的就是各个通道的ADC测量数值 uint16_t ADC_Value[100],ad1; float adv; //开启 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value, 100);//本次其实只用到了数组第一位 //回调函数,每次DMA转换完成就会被调用一次 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { ad1=ADC_Value[0]; adv = (float)ad1 / 4096 * 3.3; printf("adcV= %f ",adv); } a 激活ADC,启动转换规则组 HAL_ADC_Start(); HAL_ADC_Start_IT() 中断模式ADC_EOC_SINGLE_CONV通道转换结束,EOC_SEQ_CONV序列转换结束 HAL_ADC_Start_DMA(); b 关闭ADC,停止转换规则组 HAL_ADC_Stop(); HAL_ADC_Stop_IT() HAL_ADC_Stop_DMA() C 读取ADC值 HAL_ADC_GetValue() D 其它 HAL_ADC_PollForConversion() 等待转换结束,不适用一下情况:DMA模式且轮询每个转换 HAL_ADC_PollForEvent() // 回调函数,“weak”属性,使用时再在应用代码中实现 • HAL_ADC_ConvCpltCallback() 转换完成后回调,DMA模式下DMA传输完成后调用 • HAL_ADC_ConvHalfCpltCallback() 转换过程中回调 • HAL_ADC_LevelOutOfWindowCallback() • HAL_ADC_ErrorCallback() 状态函数--返回运行状态获取错误信息 • HAL_ADC_GetState() • HAL_ADC_GetError() 如果开启间断模式,每次需要先使用HAL_ADC_Start()(或HAL_ADC_Start_IT(),HAL_ADC_Start_DMA()下文不再赘述)启动转换,需要使用HAL_ADC_PollForConversion()等待转换完成,HAL_ADC_GetState()获取ADC转换状态(若返回值为HAL_OK说明转换完成),转换完成后使用HAL_ADC_GetValue()读取ADC原始值,读取完成后,使用HAL_ADC_Stop()停止转换,如需再次获取ADC数据,需重复执行上述步骤。 |
|
|
|
只有小组成员才能发言,加入小组>>
3308 浏览 9 评论
2988 浏览 16 评论
3490 浏览 1 评论
9049 浏览 16 评论
4083 浏览 18 评论
1167浏览 3评论
601浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
592浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2329浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1892浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 11:35 , Processed in 1.108600 second(s), Total 51, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号