[英]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;
}
需要注意的一些注意事項。
SysTick 是一個 24 位計數器。 它將在溢出時包裝。 當您比較值或實施延遲方法時,請注意這一點。
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 的內部時鍾不太准確。
考慮到這一點,你要做的是:
void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }
millis()
的函數,它返回類似以下內容的計數器: uint32_t millis(void){ return counter; }
通過這種方式,您可以在該 MCU 中使用相同的功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.