LOADING

加载过慢请开启缓存 浏览器默认开启

微秒级delay

2023/12/29 MCU

Takeaway

转载声明:

https://blog.csdn.net/qq153471503/article/details/102930097

F1系列(72M)

    void delay_us(uint32_t us)
    {
        uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
        while (delay--)
        {
            ;
        }
    }

备注

  • delay的计算
    使用GCC -O0编译显示,在while中需要重复执行5条指令,而M3内核的STM32整型运算性能为1.25DMIPS/MHz .

    非常凑巧的是:

      设 HAL_RCC_GetHCLKFreq() = f ,N = f / delay .
      则单位延时Time = [5 * (f / N)] / (1.25 * f) = 5 / (1.25 * N),Uint:us .
    

    故取N = 4000000恰好为1us .

  • 仔细编译优化等级

    • O1级优化,指令变少 .
    • O2级优化,只有一句跳转,不执行while .

Hal库通用

    #define CPU_FREQUENCY_MHZ    184		// STM32系统时钟主频
    void HAL_Delay_us(__IO uint32_t delay)
    {
        int last, curr, val;
        int temp;

        while (delay != 0)
        {
            temp = delay > 900 ? 900 : delay;
            last = SysTick->VAL;
            curr = last - CPU_FREQUENCY_MHZ * temp;
            if (curr >= 0)
            {
                do
                {
                    val = SysTick->VAL;
                }
                while ((val < last) && (val >= curr));
            }
            else
            {
                curr += CPU_FREQUENCY_MHZ * 1000;
                do
                {
                    val = SysTick->VAL;
                }
                while ((val <= last) || (val > curr));
            }
            delay -= temp;
        }
    }

备注

关于 SysTick可参考ST的CM3内核手册PM0056 Programming manual .

SysTick->LOAD 的值应为 (CPU_FREQUENCY_MHZ * 1000) -1 在此条件下 SysTick 1μs自减,1ms重载 .

当传入delay参数时,对其按照temp进行拆分———因为VAL不会超过1000 .

对拆分后的delay分段延时:(delay/temp)*temp + delay%temp .

  1. curr ≥ 0时

通过(val < last) && (val >= curr)来实现一次temp延时.

  1. curr < 0时

执行curr += CPU_FREQUENCY_MHZ * 1000

通过(val <= last) || (val > curr)来实现一次temp延时.

全通用

(这里是HAL写法),但需要占用一个定时器 .

    #define DLY_TIM_Handle (&htimx)
    void delay_us(uint16_t nus)
    {
        __HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
        __HAL_TIM_ENABLE(DLY_TIM_Handle);
        while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
        {
            ;
        }
        __HAL_TIM_DISABLE(DLY_TIM_Handle);
    }

备注

设置TIMx的计数周期为1μs,实现delay_us .