Arduino millis()在stm32

时间:2016-05-22 14:28:34

标签: arduino microcontroller stm32 milliseconds stm32f0

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

7 个答案:

答案 0 :(得分:11)

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频率。

答案 1 :(得分:4)

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

在某些情况下,您可能不会将SysTick用于此目的。例如,当使用已经实现SysTick的FreeRTOS时。在这种情况下,在任务中运行代码,您可以使用vTaskDelay。根据您的想法,软件计时器也可以制作技巧:http://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html

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

答案 4 :(得分:0)

嗯,我想我需要更多的信息才能找到合适的答案,但我会尽力给你。

对于您的应用需要考虑的因素,如果您要进行高分辨率测量(需要精确时间),则需要提供外部晶振以提高精度,因为MCU的内部时钟不是很准确。

记住这一点,你要做的是以下几点:

  1. 配置TIM,使其每1ms执行一次中断
  2. 启用TIM中断,
  3. 在TIM中断中,增加一个计数器(这将是您的时间),该计数器被定义为此模块的全局变量。
  4. void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }

    1. 创建一个名为millis()的函数,返回计数器,如:
    2. uint32_t millis(void){ return counter; }

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

答案 5 :(得分:0)

我建议用计时器来做。通过这种方式,您还可以获得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);
}
<\ n>在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的情况下完成它,只需要时间= TIMx-&gt; CNT。是的,它取决于计时器配置和你的需求,你也必须知道uint32_t时间变量也可以溢出,但这是一个细节,它可以很容易地管理。

答案 6 :(得分:0)

Systick并不总是以毫秒为单位。 尽管诸如freeRTOS之类的中间件可以假设其以毫秒为单位。 最好,最优雅的解决方案是制作自己的计时器!

要创建计时器,必须在CubeMX中或手动配置预分频器和周期。 Clock Configuration

因为我的时钟是100MHz,这意味着我想要一个100MHz / 1000Hz的预分频器-1 = 99 我的周期可以保持为0,因为我希望中断每1毫秒触发一次。 Prescalar Calculation

这是CubeMX中的外观: Timer Configuration

然后您要在计时器回调函数中添加计数器增量。

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 */
}

就这么简单:)

仅供参考,我的CubeMX版本是5.2.1