PY32 定时器中断回调不执行的解决办法

📅 2026/7/22 22:21:07
PY32 定时器中断回调不执行的解决办法
一发现问题我在调试 PY32 的定时器中断时按 HAL 库的流程配好了定时器也写了回调函数但全速运行后回调就是不执行。voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim){if(htim-InstanceTIM14){// 这里的代码从来不执行}}打断点发现 HAL 层的回调根本没被调用。二排查过程我先是检查了定时器分频、重装值、中断优先级都没问题。然后去查了一下发现根因在 startup 启动文件里PY32 的 startup 文件虽然标了TIM14_IRQHandler这个标签但它是一个weak 弱别名默认指向一个空函数。中断发生后 CPU 跳到了空函数里根本没进到 HAL 库。三解决方法手动实现TIM14_IRQHandler把中断重定向到HAL_TIM_IRQHandler。下面是一个完整的可运行例程#includepy32f0xx_hal.hTIM_HandleTypeDef htim14;volatileuint32_ttimer_irq_count0;staticvoidAPP_SystemClockConfig(void){RCC_OscInitTypeDef RCC_OscInitStruct{0};RCC_ClkInitTypeDef RCC_ClkInitStruct{0};RCC_OscInitStruct.OscillatorTypeRCC_OSCILLATORTYPE_HSI;RCC_OscInitStruct.HSIStateRCC_HSI_ON;RCC_OscInitStruct.HSIDivRCC_HSI_DIV1;RCC_OscInitStruct.HSICalibrationValueRCC_HSICALIBRATION_24MHz;HAL_RCC_OscConfig(RCC_OscInitStruct);RCC_ClkInitStruct.ClockTypeRCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;RCC_ClkInitStruct.SYSCLKSourceRCC_SYSCLKSOURCE_HSI;RCC_ClkInitStruct.AHBCLKDividerRCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDividerRCC_HCLK_DIV1;HAL_RCC_ClockConfig(RCC_ClkInitStruct,FLASH_LATENCY_0);}staticvoidAPP_TimerInit(void){__HAL_RCC_TIM14_CLK_ENABLE();htim14.InstanceTIM14;htim14.Init.Prescaler23999;// 24MHz/(239991) 1KHzhtim14.Init.CounterModeTIM_COUNTERMODE_UP;htim14.Init.Period999;// 1KHz/1000 1Hz 中断htim14.Init.ClockDivisionTIM_CLOCKDIVISION_DIV1;htim14.Init.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(htim14);HAL_NVIC_SetPriority(TIM14_IRQn,1,0);HAL_NVIC_EnableIRQ(TIM14_IRQn);HAL_TIM_Base_Start_IT(htim14);}/* 关键手动实现 IRQHandler调用 HAL 库的处理函数 */voidTIM14_IRQHandler(void){HAL_TIM_IRQHandler(htim14);}/* 定时器中断回调 */voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim){if(htim-InstanceTIM14){timer_irq_count;}}intmain(void){HAL_Init();APP_SystemClockConfig();APP_TimerInit();while(1){// 主循环timer_irq_count 每秒自增一次}}把上面这段代码复制到一个新工程添加 HAL 库后编译下载定时器中断就能正常工作了。四补充说明为什么 HAL 要用回调中断发生后CPU 直接跳到向量表里的函数。但 HAL 库不知道用户想在这个中断里做什么事所以它设计了两层 weak 定义TIM14_IRQHandler (weak) ← startup 给的默认空函数 ↓ 你实现了就覆盖 你写的 TIM14_IRQHandler → HAL_TIM_IRQHandler() ← HAL 帮你清标志 → HAL_TIM_PeriodElapsedCallback (weak) ← 你实现的回调HAL 负责通用操作判断哪个中断源、清标志用户只需实现回调。互不干扰。也可以不用回调直接在中断函数里处理所有事结果一样voidTIM14_IRQHandler(void){// 在这里判断标志、清标志、做事不经过 HAL}两种写法选一种即可没有强制。五总结PY32 的 startup 文件只给了中断入口标签默认是弱定义。想让 HAL 库的中断回调生效必须自己实现 IRQHandler 并调用对应的 HAL 处理函数。同理串口中断、外部中断 etc. 都需要手动重定向例如voidUSART2_IRQHandler(void){HAL_UART_IRQHandler(huart2);}voidEXTI0_1_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);}这个步骤容易忽略希望能帮到遇到同样问题的人。如果有纰漏之处欢迎指正。