STM32F4 TIM11微秒延迟失效问题求助(软件SPI场景)
STM32F4 软件SPI中TIM11微秒延迟失效问题排查与解决建议
我在为STM32F4开发软件SPI时,尝试用TIM11实现1微秒级延迟,但编写的delay_us函数无法正常持续计数,运行一次后就停止。改用SysTick实现的延迟函数可以正常工作,但我希望解决TIM11的使用问题。
现有代码
TIM11延迟函数(失效版本)
void delay_us(uint32_t us) { HAL_TIM_Base_Start_IT(&htim11); uint16_t start_cnt = htim11.Instance->CNT; while (htim11.Instance->CNT - start_cnt < us); //HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); htim11.Instance->CNT = 0 ; __HAL_TIM_CLEAR_IT(&htim11, TIM_IT_UPDATE); HAL_TIM_Base_Stop(&htim11); }
软件SPI读取函数
uint8_t SoftSPI_Read(SoftSPI_TypeDef *SoftSPIx) { uint8_t data = 0; uint8_t i; // the line for spi write for (i = 0; i < 8; i++) { SCLK_Clr; //sysTickDelay_us(2); delay_us(2); SCLK_Set; delay_us(1); data <<= 1; if (MISO_Read == GPIO_PIN_SET) data |= 0x01; delay_us(1); } return data; }
可用的SysTick延迟函数
void sysTickDelay_us(int delay) { //Sets the reload value pSysTick->RVR = 20; //Clears the SysTick current value register pSysTick->CVR= 0; //Enable SysTick in the control register and select internal system clock source pSysTick->CSR= (1 << 0) | (1 << 2); for(int i=delay; i > 0; i--) { while(!(pSysTick->CSR & (1 << 16))); } //Disable SysTick counter in the Control Register pSysTick->CSR=0; }
问题分析与修复
核心问题点
- 错误使用中断模式启动定时器:调用
HAL_TIM_Base_Start_IT会启用TIM11的更新中断,但未编写对应的中断处理函数TIM11_IRQHandler,一旦定时器溢出触发中断,会导致系统异常,进而使计数停滞。 - 定时器启动后未同步计数状态:调用启动函数后,TIM需要一个时钟周期才会开始计数,直接读取
CNT可能拿到初始值0,导致延迟计算错误。 - 溢出处理缺失:当延迟时长超过定时器自动重装载值时,
CNT会溢出归零,此时无符号减法htim11.Instance->CNT - start_cnt会得到异常大数,导致循环提前退出。
修复后的TIM11延迟函数
void delay_us(uint32_t us) { // 用非中断模式启动定时器,避免不必要的中断触发 HAL_TIM_Base_Start(&htim11); uint16_t start_cnt = htim11.Instance->CNT; uint32_t elapsed = 0; uint16_t arr_val = htim11.Instance->ARR + 1; // 单次计数周期的总tick数 do { uint16_t current_cnt = htim11.Instance->CNT; // 处理溢出:当前计数小于起始值,说明已完成一次溢出循环 if (current_cnt < start_cnt) { elapsed += arr_val - start_cnt + current_cnt; } else { elapsed = current_cnt - start_cnt; } } while (elapsed < us); // 停止定时器并重置计数,保证下次调用的初始状态一致 HAL_TIM_Base_Stop(&htim11); htim11.Instance->CNT = 0; }
额外检查项
- TIM11初始化配置:确保TIM11的时钟分频正确,保证计数频率为1MHz(即每个tick对应1us)。例如STM32F4的APB2时钟为84MHz时,预分频器应设为
83(84-1),自动重装载值设为0xFFFF以支持最大延迟范围。 - 中断向量表清理:如果之前误开了TIM11中断,需移除工程中未实现的
TIM11_IRQHandler相关配置,避免触发硬错误。
验证方法
单独测试delay_us函数:在函数前后翻转GPIO引脚(比如PC13),用示波器抓取波形,测量高低电平时长是否符合预期延迟值,确认TIM11计数正常。
内容的提问来源于stack exchange,提问作者Mourad
相关产品推荐
相关产品推荐

