You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

问题分析与修复

核心问题点

  1. 错误使用中断模式启动定时器:调用HAL_TIM_Base_Start_IT会启用TIM11的更新中断,但未编写对应的中断处理函数TIM11_IRQHandler,一旦定时器溢出触发中断,会导致系统异常,进而使计数停滞。
  2. 定时器启动后未同步计数状态:调用启动函数后,TIM需要一个时钟周期才会开始计数,直接读取CNT可能拿到初始值0,导致延迟计算错误。
  3. 溢出处理缺失:当延迟时长超过定时器自动重装载值时,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:37:37