Takeaway
转载声明:
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
.
- 当
curr
≥ 0 时
通过(val < last) && (val >= curr)
来实现一次 temp 延时.
- 当
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
.