【问题标题】:How to write a time difference function to STM32F4STM32F4如何写一个时差函数
【发布时间】:2019-06-26 16:30:37
【问题描述】:

我正在研究 STM32F4 并且非常新。我知道 C 的基础知识,但经过超过 1 天的研究,我仍然没有找到解决方案。

我只是想自己做一个延迟函数,处理器运行在 168MHz ( HCLK )。所以我的直觉说它每秒产生 168x10^6 个时钟周期。所以方法应该是这样的,

1-将当前时钟计数存储到变量中

2-Time diff = (任意时刻的时钟值-存储的起始时钟值) / 168000000

这个流程应该给我以秒为单位的时间差,然后我可以用它来转换我想要的任何东西。

但是,不幸的是,尽管它看起来很简单,但我无法为 MCU 实现任何方法。

我试过 time.h 但它不能正常工作。例如,clock() 一遍又一遍地给出相同的结果,而时间(自 1970 年以来返回秒数)给出十六进制 0xFFFFFFFF(-1,我猜是错误)。

谢谢。

编辑:在编写时我假设某些函数(如 clock())会返回自程序流开始以来的总时钟计数,但现在我认为在 40 亿/1.68 亿秒后它会溢出 uint32_t 大小。我真的很困惑。

【问题讨论】:

  • systick 中断。 clock() 是一个标准库函数。很可能您将gcc 与`newlib` 与nosys.specs 一起使用,它只是将clock 实现为retunrning -1。同样clock() 返回clock_t,它可能不是uint32_t,而是你想要的。
  • @Kamil Cuk 是不是和TIMERS有关?
  • datashett 更具体地提到了“SysTick”,而不是计时器,它是一个单独的中断。通常人们在实现中使用hal functions。您的目标是自己触摸寄存器还是使用一些 HAL 层?
  • 如果您碰巧将newlibnosys 一起使用,那么clock() 只需调用_times_r(),它只返回-1 并设置errno=ENOSYS。在嵌入式平台上,您必须自己实现系统(或使用某些实现)。使用newlib,您可以使用clock_t 的实现添加machine/_types.h 文件,并使用您自己的clock_t clock(void) { return HAL_GetTick(); } 实现进行编译
  • 外设时钟(那些驱动定时器和其他外设硬件)通常比 CPU 时钟慢得多。您多次获得相同的时间并不令我感到惊讶。请耐心等待,它可能每秒只更改一次。编写一个循环轮询,直到更改并进行某种输出。您可能会看到 1Hz 模式。

标签: c time delay stm32


【解决方案1】:

答案取决于所需的精度和间隔。

对于具有亚微秒精度的较短间隔,有一个cycle counter。您的怀疑是正确的,它会在 232/168*106 ~ 25.5 秒后溢出。

对于更长的时间间隔,有可以预分频的计时器以支持 168 MHz 时钟的任何可能细分。最常用的设置是将 SysTick 定时器设置为以 1 kHz 频率生成中断,这会增加软件计数器。读取此计数器将给出自启动以来经过的毫秒数。由于它通常是一个 32 位计数器,它会在 49.7 天后溢出。 HAL 库以这种方式设置 SysTick,然后可以使用 HAL_GetTick() 函数查询计数器。

对于更长或更专业的计时要求,您可以使用保持日历时间的RTC 外围设备,或TIM 外围设备(基本、通用和高级定时器),它们有自己的预分频器,并且可以安排在主从设置中提供几乎任意的精度和间隔。

【讨论】:

  • 您好,谢谢您的回答。我用HAL_GetTick(),根据上面的cmets实现了毫秒精度的时间计算。我对您的回答不清楚的是:1kHz 频率中断到底是什么意思?它是基于时间还是时钟周期? 1000 increment / 1 seconds1 increment per 1000 clock cycles ?好像是前者吧?
  • 对。 1 kHz 表示某事发生 1000 次/秒。如果系统时钟为 168 MHz(1.68 亿周期/秒),则应将 SysTick 配置为每 168000 个周期触发一次中断。
  • 嘿,谢谢你的回答。我快哭了,我正在阅读 systick hal 函数的文档几个小时,请告诉我为什么HAL_SetTickFreq(100); 不会导致系统每 100 毫秒而不是每毫秒输入SysTick_Handler 的原因?我在 while(1) 循环之前写 HAL_SetTickFreq(100); 并且再也没有将其设置回 1,我在 SysTick_Handler 中写了 XOR 一个 LED,但我无法观察到它只是打开的闪烁。 void SysTick_Handler(void) { HAL_IncTick(); GPIOD->ODR ^= LED4_Pin ; }
  • 使用 HAL 及其所谓的文档将一事无成。 现在忘记它,否则以后会变得更糟。如果你放弃 HAL,SysTick 变得容易:SysTick->LOAD = 16799999;SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; 并且中断来了 10 次/秒(加载值 = 系统时钟 / 所需频率 - 1)。 SysTick 的完整文档在编程手册中,其他定时器在参考手册中,both available from ST
  • SysTick->LOAD = 168000000 / 10 - 1 ; 我通过调试意识到,在执行这一行之后,LOAD 值变成了22783,而不是应该是167999999。我查了一下是uint32_t,所以我不明白为什么会发生这样的事情。编辑:我现在确信这是关于这个溢出的事情,因为无论是 HAL 还是直接寄存器编码,我都无法获得 10Hz 频率,而 1kHz 和 100Hz 是可以实现的。
猜你喜欢
  • 2022-11-28
  • 2023-03-28
  • 2018-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-10
  • 2012-12-25
相关资源
最近更新 更多