stm32 计时
- hal_init()里面HAL_InitTick()会设置好CM3内部的systick模块的时钟源头,为sysclk的/8,和节拍中断优先级。
- stm32 在设置好时钟树之后,sysclk = 72MHZ
- delay的初始化delay_init(),也就是设置按照当前的sysclk来说,计算得出1us要多少个时钟周期计数。或运行OS,则设置好LOAD为系统节拍(之后就不会变了)
- 之后就可以开始使用delay_us, delay_ms这些延时函数了
systick模块,sysclk时钟源 和 tick节拍

systick是一个模块,是CM3内部的固有硬件,负责给整个系统提供一个简易的定时。

1次节拍 = LOAD次 计数
1次计数 = 1/(9M)s 或者 1/(72M)s
= 1/9 us 或者 1/72 us
delay_us
无OS
void delay_us(uint32_t nus) { uint32_t temp; SysTick->LOAD = nus * g_fac_us;
SysTick->VAL = 0x00;
SysTick->CTRL |= 1 << 0 ;
do { temp = SysTick->CTRL; } while ((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~(1 << 0) ; SysTick->VAL = 0X00;
}
|
直接设置一个节拍的LOAD计数 = 总共的计数(根据n us * g_per_us)
通过读systick是否完成LOAD的计数来判断
有OS
void delay_us(uint32_t nus) { uint32_t ticks; uint32_t told, tnow, tcnt = 0; uint32_t reload; reload = SysTick->LOAD;
ticks = nus * g_fac_us;
delay_osschedlock();
told = SysTick->VAL;
while (1) { tnow = SysTick->VAL; if (tnow != told) { if (tnow < told) { tcnt += told - tnow; } else { tcnt += reload - tnow + told; } told = tnow; if (tcnt >= ticks) break;
} }; delay_osschedunlock();
}
|
通过数总的计数,不能修改systick的LOAD。
delay_ms
无OS
void delay_ms(uint16_t nms) {
uint32_t repeat = nms / 1000; uint32_t remain = nms % 1000; while (repeat) { delay_us(1000 * 1000); repeat--; } if (remain) { delay_us(remain * 1000); }
}
|
有OS
void delay_ms(uint16_t nms) {
if (delay_osrunning && delay_osintnesting == 0) { if (nms >= g_fac_ms)
{ delay_ostimedly(nms / g_fac_ms);
} nms %= g_fac_ms;
}
delay_us((uint32_t)(nms * 1000)); }
|
大于OS延时的用OS内部的延时,不足的部分,用delay_us来凑。不过此时任务无法调度,因为OS的delay_us下锁调度。