HAL_GetTick()是返回刻度还是毫秒? (以及如何以微秒为单位测量)

时间:2017-03-12 12:00:58

标签: stm32

我是使用HAL功能的新手。函数HAL_GetTick()的{​​{3}}表示它在毫秒"中提供 tick 值。

我不明白这个函数是返回tick还是毫秒。当然要从刻度转换为毫秒,我需要知道一毫秒内有多少刻度,以及它的CPU特定。

那么HAL_GetTick()究竟返回了什么?

修改

我真正的问题是知道如何以微秒为单位测量时间。所以我想从HAL_GetTick()得到滴答并将它们转换为微秒。这在评论和至少其中一个答案中得到了解决,所以我也在这里提到这一点并编辑了标题。

6 个答案:

答案 0 :(得分:12)

HAL_GetTick() 应该返回自启动以来经过的毫秒数,因为很多HAL函数都依赖于它。你如何实现它取决于你。默认情况下,HAL_Init()查询系统时钟速度,并将SysTick频率设置为1/1000:

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /*Configure the SysTick to have interrupt in 1ms time basis*/
  HAL_SYSTICK_Config(SystemCoreClock /1000);

  /*Configure the SysTick IRQ priority */
  HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0);

   /* Return function status */
  return HAL_OK;
}     

然后默认的SysTick中断处理程序调用{​​{1}}每ms增加一次内部计数器,HAL_IncTick()返回该计数器的值。

所有这些函数都定义为HAL_GetTick(),因此您可以覆盖它们,只要您的weak版本以毫秒为单位返回已用时间,就可以了。你可以,例如替换HAL_GetTick()让SysTick以10 kHz运行,但是你应确保仅在每第10次中断时调用HAL_InitTick()。在216 MHz STM32F7控制器(或刚刚发布的400MHz STM32H743)上,您实际上可以降至1 MHz Systick,但是您应该非常小心地从处理程序中尽快返回。除非你在处理程序中做一些硬件计数器无法做到的事情,否则它仍会浪费宝贵的处理器周期。

或者您可以在不配置SysTick的情况下执行此操作(使用空函数覆盖HAL_IncTick()),但设置一个32位硬件计时器,并使用足够的预分频器来计算每微秒,并让{{1返回计时器计数器。

回到你真正的问题,测量微秒级的时间,有更好的方法。

如果你有一个32位定时器,那么你可以将相应APB时钟的MHz值放入预分频器,启动它,并且有你的微秒钟,而不是从你的应用程序中取走处理时间。此代码应在 STM32L151 / 152/162 STM32F4上启用(未测试):

HAL_InitTick()

然后通过阅读HAL_GetTick()随时获取其价值。

检查您的参考手册哪些硬件定时器具有32位计数器,以及它从何处获取时钟。它在整个STM32系列中变化很大,但应该在F4上。

如果你不能使用32位定时器,那么就有核心周期计数器。只需使用

启用一次
__HAL_RCC_TIM5_CLK_ENABLE();
TIM5->PSC = HAL_RCC_GetPCLK1Freq()/1000000 - 1;
TIM5->CR1 = TIM_CR1_EN;

然后从TIM5->CNT读取值。请注意,当它返回经过的处理器周期时,它将在几秒钟内溢出。

<击>编辑:

<击>

我刚才注意到你正在使用STM32L0。因此,忘记32位定时器和200+ MHz内核。使用CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; ,或仔细考虑您想测量的间隔时间,以及准确度,然后选择16位计时器。您可以将其作为单独的问题发布,更详细地描述您的硬件的外观以及它应该做什么。可能有一种方法可以直接通过您想要计时的事件触发计数器启动/停止。

答案 1 :(得分:2)

两者兼而有之。大多数情况下,使HAL滴答计数器递增的函数挂钩到SysTick中断,该中断被配置为每1ms滴答一次。因此,HAL_GetTick()将返回自配置SysTick中断以来的毫秒数(基本上自程序启动以来)。这也可以是&#34; SysTick中断的次数&#39;勾选&#39;&#34;。

答案 2 :(得分:1)

尽管已经回答了该问题,但我认为了解HAL如何使用HAL_GetTick()来计数毫秒会有所帮助。可以在HAL的函数HAL_Delay(uint32_t Delay)中看到。

HAL_Delay(uint32_t Delay)stm32l0xx_hal.c的实现:

/**
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a period to guaranty minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait++;
  }

  while((HAL_GetTick() - tickstart) < wait)
  {
  }
}

答案 3 :(得分:1)

查看调试器时,我可以看到private static readonly int FIFO_SIZE = 244; ... if (txSize >= FIFO_SIZE) { /* Copy chunk of data to send */ Array.ConstrainedCopy(data, i * FIFO_SIZE, bytesToSend, 0, FIFO_SIZE); i++; /* Convert to IBuffer type */ dataToSend = CryptographicBuffer.CreateFromByteArray(bytesToSend); /* Write FIFO characteristic (244 bytes) >> observed physically 10 writes 0f 24 bytes + 1 write of 4 bytes */ status = await fifo.WriteValueAsync(dataToSend, GattWriteOption.WriteWithoutResponse); if (status != GattCommunicationStatus.Success) { System.Diagnostics.Debug.WriteLine("FIFO write error !"); } txSize -= FIFO_SIZE; } ... 全局变量可用,这似乎与针对我自己定义的全局变量调用uwTick的结果相同。

根据文档:

  

无效HAL_IncTick(无效)

     

调用此函数可增加使用的全局变量“ uwTick”   作为申请的时基。

     

注意:
  在默认实现中,此变量每1ms递增一次   在Systick ISR中。
  该函数声明为__weak   如果用户文件中有其他实现,则将其覆盖。

答案 4 :(得分:1)

我遇到了同样的问题,但是随后在PlatformIO中找到了一个库函数,该函数返回了微秒。

s = temp.assign(listofitemids=temp['listofitemids'].str.split(', ')).explode('listofitemids')
s = pd.crosstab(s['userid'], s['listofitemids']).mask(lambda x : x.eq(0))
s
Out[266]: 
listofitemids   10  20  30   40
userid                         
100            1.0   1   1  NaN
200            NaN   1   1  1.0

它位于〜/ .platformio / packages / framework-arduinoststm32 / libraries / SrcWrapper / src / stm32 / clock.c

但是看起来STM32CubeIde没有它,所以我只是从PlatformIO复制了它。另外我还必须复制LL_SYSTICK_IsActiveCounterFlag()函数:

uint32_t getCurrentMicros(void)
{
  /* Ensure COUNTFLAG is reset by reading SysTick control and status register */
  LL_SYSTICK_IsActiveCounterFlag();
  uint32_t m = HAL_GetTick();
  const uint32_t tms = SysTick->LOAD + 1;
  __IO uint32_t u = tms - SysTick->VAL;
  if (LL_SYSTICK_IsActiveCounterFlag()) {
    m = HAL_GetTick();
    u = tms - SysTick->VAL;
  }
  return (m * 1000 + (u * 1000) / tms);
}

答案 5 :(得分:-2)

我需要一个精度为1uS的时间戳,并且如上所述使用TIM5可以正常工作,但是需要进行一些调整。这就是我的想法。

/* Initialization */
__HAL_RCC_TIM5_CLK_ENABLE();
TIM5->PSC = HAL_RCC_GetPCLK1Freq() / 500000;
TIM5->CR1 = TIM_CR1_CEN;
TIM5->CNT = -10;

/* Reading the time */
uint32_t microseconds = TIM5->CNT << 1;

我没有完全探讨为什么我必须做我做的事情。但是我很快意识到了两件事。 (1)尽管看起来不错,但标量缩放无法工作。这是我尝试使其工作的几件事之一(基本上是半个时钟,然后将结果除以2)。 (2)时钟已经在运行,起初给出了奇怪的结果。我尝试了一些不成功的事情来停止,重新编程并重新启动它,并将计数设置为-10是一种粗略但有效的方法,只需使其完成当前循环,然后即可根据需要迅速开始工作。当然,有更好的方法可以实现这一目标。但总的来说,这是一种获得开销非常低的准确事件时间戳的简单方法。