8

我正在尝试将一些 Arduino 库移植到 stm32。在 Arduino 中,millis()返回自启动以来的毫秒数。stm32中是否有等效功能?我正在使用 stm32f0 MCU。

4

8 回答 8

15

你可以使用HAL_GetTick(): this function gets current SysTick counter value (incremented in SysTick interrupt) used by peripherals drivers to handle timeouts.

于 2016-05-23T08:11:47.473 回答
14

SysTick是为此目的提供的 ARM 内核外设。根据您的需要进行调整:

首先,初始化它

// Initialise SysTick to tick at 1ms by initialising it with SystemCoreClock (Hz)/1000

volatile uint32_t counter = 0;
SysTick_Config(SystemCoreClock / 1000);

提供中断处理程序。您的编译器可能需要用其他属性修饰中断处理程序。

SysTick_Handler(void) {
  counter++;
}

这是您的millis()功能,再简单不过了:

uint32_t millis() {
  return counter;
}

需要注意的一些警告。

  1. SysTick 是一个 24 位计数器。它会在溢出时换行。当您比较值或实施延迟方法时,请注意这一点。

  2. SysTick 源自处理器内核时钟。如果您弄乱了核心时钟,例如减慢它以节省电力,那么也必须手动调整 SysTick 频率。

于 2016-06-04T08:12:14.870 回答
2

我建议用计时器来做。这样你也可以得到1us的步长,只是控制你的时间步长。无论如何,大多数 STM32 MCU 都有 8 个或更多定时器,所以在大多数情况下,您可以随意选择一个。我将展示如何做到这一点的非常简单的基本想法。

只需创建计时器:

uint32_t time = 0;

void enable_timer(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE);
    TIM_TimeBaseInitTypeDef timerInitStructure;

    /* if MCU frequency 48 MHz, prescaler of value 48 will make 1us counter steps
    timerInitStructure.TIM_Prescaler = 48;

    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    /*how often you'll get irq*/
    timerInitStructure.TIM_Period = 0xFFFF; // will get irq each 65535us on TIMx->CNT overflow
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM16, &timerInitStructure);
    TIM_Cmd(TIM16, ENABLE);
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM16_IRQn;
    /*for more accuracy irq priority should be higher, but now its default*/
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    TIM_ClearITPendingBit(TIM16,TIM_IT_Update);
    NVIC_Init(&NVIC_InitStruct);
    TIM_ITConfig(TIM16,TIM_IT_Update,ENABLE);
}

在 IRQ 你必须控制定时器计数器的溢出并更新你的全局时间

void TIM16_IRQHandler(void){
if (TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET){
    TIM_ClearITPendingBit(TIM16, TIM_IT_Update);
    time +=65535;
}

}

实时将是:

uint32_t real_time_us = time + (uint32_t)TIM16->CNT;

但是如果你可以自由使用 32 位定时器,你甚至可以在没有 IRQ 的情况下做到这一点,只需简单地 time=TIMx->CNT。是的,这取决于计时器配置和您的需求,您还必须知道 uint32_t 时间变量也可能溢出,但这是一个细节,它可以轻松管理。

于 2017-11-08T11:36:43.860 回答
2

我建议设置自己的计时器。

要制作计时器,您必须在 CubeMX 中或手动配置预标量和周期。
时钟配置

因为我的时钟是 72MHz,这意味着我想要一个 72MHz / 1MHz - 1 = 71 的预分频因此我的周期将是 1MHz / 1kHz - 1 = 999,因为我希望中断每 1 毫秒触发一次。
预标量计算

这是 CubeMX 中的样子。
定时器配置

然后你想在定时器回调函数中添加一个计数器增量。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */
  if (htim->Instance == TIM10) {
    counter++;
  }
  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}
于 2019-06-24T23:07:53.167 回答
1

您需要先初始化 SysTick,通过使用 SystemCoreClock (Hz)/1000 对其进行初始化,使其在 1ms 处滴答。

于 2021-05-01T11:06:35.720 回答
1

HAL 库使用 Timer(您可以在 STM32CubeMX 中选择它)来生成 Tick 计数器。每个 Tick 需要 1ms。您可以按如下方式使用它来测量经过的时间:

   uint32_t startTime = HAL_GetTick();
                .
                .
                .
   uint32_t endTime = HAL_GetTick();
   uint32_t elapsedTime = endTime-startTime; // in ms 
于 2021-08-29T22:45:52.573 回答
0

在某些情况下,您可能不会为此目的使用 SysTick。例如,在使用已经实现 SysTick 的 FreeRTOS 时。在这种情况下,在任务中运行您的代码,您可以使用 vTaskDelay。根据您想要做什么,软件计时器也可以解决问题:http ://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html

如果您不能使用 SysTick,并且您没有 FreeRTOS 或类似软件,您可以设置一个带有中断的计时器并将您的代码放在适当的回调中。

于 2016-11-18T16:21:26.653 回答
0

好吧,我想我需要更多信息才能得到正确的答案,但我会给你最好的机会。

您需要为您的应用考虑一个问题,如果您要进行高分辨率测量(需要准确的时间),您将需要提供一个外部晶振以确保精度,因为 MCU 的内部时钟不太准确。

考虑到这一点,您应该执行以下操作:

  1. 配置一个 TIM,使其可以每 1ms 执行一次中断
  2. 启用 TIM 中断,
  3. 在 TIM 中断中,增加一个定义为该模块的全局变量的计数器(这将是您的时间)。

void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }

  1. 创建一个名为millis()返回计数器的函数,例如:

uint32_t millis(void){ return counter; }

通过这种方式,您可以在此 MCU 中使用相同的功能。

于 2017-06-26T22:29:29.990 回答