跳转至

微秒级滴答操作

微秒级延时函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include "stm32f4xx_hal.h"

void delay_us(unsigned long us)
{
    volatile uint32_t currentTicks = SysTick->VAL;
    const uint32_t tickPerMs = SysTick->LOAD + 1;
    const uint32_t nbTicks = ((us - ((us > 0) ? 1 : 0)) * tickPerMs) / 1000;
    uint32_t elapsedTicks = 0;
    volatile uint32_t oldTicks = currentTicks;
    do
    {
        currentTicks = SysTick->VAL;
        elapsedTicks += (oldTicks < currentTicks) ? tickPerMs + oldTicks - currentTicks : oldTicks - currentTicks;
        oldTicks = currentTicks;
    } while (nbTicks > elapsedTicks);
}

原理:直接使用 SysTick 定时器的内部计数值,而不依靠 1ms 的中断触发。SysTick 定时器往往工作在较高频率,如 84MHz,因此可以用于实现微秒级的延时。

微秒级滴答计时

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include "stm32f4xx_hal.h"

unsigned long get_tick_us()
{
    uint32_t m0 = HAL_GetTick();
    volatile uint32_t u0 = SysTick->VAL;
    uint32_t m1 = HAL_GetTick();
    volatile uint32_t u1 = SysTick->VAL;
    const uint32_t tms = SysTick->LOAD + 1;
    if (m1 != m0)
    {
        return (m1 * 1000 + ((tms - u1) * 1000) / tms);
    }
    else
    {
        return (m0 * 1000 + ((tms - u0) * 1000) / tms);
    }
}

原理:使用 SysTick 定时器的内部计数值计算出低于毫秒精度的部分,并结合 HAL_GetTick 函数的返回的毫秒计数值,计算出微秒级的计数值。
注意:由于在调用 HAL_GetTick 函数和读取 SysTick->VAL 寄存器之间可能恰好触发 SysTick 中断并发生计数值重置,导致 1ms 的误差,因此需要读取两次,以规避这种误差(由于读取过程极快,可以认为不可能两次读取都被中断打断)。

作者:ArcticLampyrid