当需要在没有RTC的情况下记录系统运行时间时,我们可以使用STM32的系统滴答定时器(SysTick)来实现。
系统滴答定时器是一个24位的计数器,它可以按照预设的时间间隔(通常为1ms)自动递减,当计数器减为0时,就会产生一次SysTick中断。在中断服务程序中,我们可以记录系统的运行时间,并进行相应的处理。
为了精确到us,我们需要根据SysTick定时器的时钟频率来计算每个SysTick定时器中断所表示的时间。在STM32F4上,SysTick定时器的时钟频率是AHB总线时钟频率(通常等于系统时钟频率)的1/8。因此,如果我们的系统时钟频率是180MHz,则SysTick定时器的时钟频率是180/8=22.5MHz。
计算每个SysTick中断所表示的时间(即SysTick定时器的计数周期)的方法如下:
由于SysTick定时器是一个24位的计数器,因此它的计数周期是2^24 = 16,777,216。
SysTick定时器的时钟频率是22.5MHz,因此每个SysTick中断所表示的时间是16,777,216/22.5MHz ≈ 0.744ms。
在中断服务程序中,我们可以记录系统的运行时间(以us为单位)的代码如下
volatile uint32_t systick_count = 0; // 系统运行时间(以us为单位)
void SysTick_Handler(void)
{
systick_count += 744; // 每个SysTick中断表示的时间是744us
}
uint32_t get_system_time_us(void)
{
uint32_t ticks;
uint32_t cnt;
do {
ticks = systick_count;
cnt = SysTick->VAL;
} while (ticks != systick_count);
return ticks + 744 - cnt / (SystemCoreClock / 22500000);
}
在上面的代码中,我们定义了一个全局变量systick_count来记录系统运行的时间(以us为单位),并在SysTick中断服务程序中每次增加744。这个数值是根据上面的计算得到的每个SysTick中断所表示的时间(即0.744ms)除以1000得到的,即744us。
在get_system_time_us()函数中,我们先读取当前的systick_count值和SysTick定时器的当前计数值(cnt),如果在读取过程中SysTick中断发生了,我们就再次读取,直到两次读取得到的systick_count值相同。然后我们将这两个值相加,并减去cnt/(SystemCoreClock/22500000)的值,得到系统运行的时间(以us为单位)。
这个差值的计算方法是根据SysTick计数器的减法计算方法得到的。当SysTick计数器减为0时,它会自动重载
使用DWT(Dat Watchpoint and Trace)寄存器进行计时
DWT寄存器是专门用来进行调试的寄存器,其中包括一个32位的计数器CYCCNT,可以实现精确计时。使用DWT寄存器需要开启调试功能,并且在编译时需要将调试信息加入代码中。
具体的使用方法如下:
在main函数中开启DWT寄存器,代码如下:
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
在需要进行计时的地方使用DWT_CYCCNT寄存器获取当前计数值,代码如下:
uint32_t start = DWT->CYCCNT;
algo();
uint32_t end = DWT->CYCCNT;
uint32_t cycles = end - start;
这样就可以使用DWT寄存器实现精确计时。
需要注意的是,DWT寄存器只能在调试模式下使用,而且在初始化时需要先开启调试模式才能使用DWT寄存器,这会对系统的性能产生一定影响。
总结:
以上是几种常用的方法,在STM32 F4上实现精确计时。不同的应用场景可以选择不同的方法来实现计时。需要根据实际情况选择合适的方法,权衡计时的精度和系统的性能。