簡體   English   中英

stm32中的Arduinomillis()

[英]Arduino millis() in stm32

我正在嘗試將一些 Arduino 庫移植到 stm32。 在 Arduino 中, millis()返回自啟動以來的毫秒數。 stm32 中是否有等效的功能? 我正在使用 stm32f0 MCU。

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

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

我建議用計時器來做。 這樣你也可以得到 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 時間變量也可能溢出,但這是一個細節,它可以輕松管理。

我建議設置自己的計時器。

要制作計時器,您必須在 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 */
}

您需要先初始化 SysTick,通過使用 SystemCoreClock (Hz)/1000 對其進行初始化,以 1ms 為單位進行滴答。

在某些情況下,您可能不會為此目的使用 SysTick。 例如,當使用已經實現 SysTick 的 FreeRTOS 時。 在這種情況下,在任務中運行您的代碼,您可以使用 vTaskDelay。 根據您想做什么,軟件計時器也可以解決問題: http : //www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html

如果您不能使用 SysTick,並且您沒有 FreeRTOS 或類似軟件,您可以設置一個帶有中斷的計時器並將您的代碼放在適當的回調中。

好吧,我想我需要更多信息才能得到正確的答案,但我會盡力而為。

您需要為您的應用考慮,如果您要進行高分辨率測量(需要精確的時間),您將需要提供一個外部晶振以提高精度,因為 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 中使用相同的功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM