好吧,我想我需要更多的信息才能找到合适的答案,但我会尽力给你。
对于您的应用需要考虑的因素,如果您进行高分辨率测量(需要精确时间),则需要提供外部晶振以提高精度,因为MCU的内部时钟不是很准确。
考虑到这一点,您将要做的是以下内容:
void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }
millis()
uint32_t millis(void){ return counter; }
通过这种方式,您可以在此MCU中使用相同的功能。
SysTick 是为此目的提供的ARM核心外设。根据您的需求进行调整:
SysTick
首先,初始化它
// 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频率。
在某些情况下,您可能不会将SysTick用于此目的。例如,当使用已经实现SysTick的FreeRTOS时。在这种情况下,在任务中运行代码,您可以使用vTaskDelay。根据您的想法,软件计时器也可以制作技巧: http://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html
如果你不能使用SysTick,并且你没有FreeRTOS或类似的东西,你可以设置一个带有中断的Timer,并将你的代码放在适当的回调中。
你可以用 HAL_GetTick(): this function gets current SysTick counter value (incremented in SysTick interrupt) used by peripherals drivers to handle timeouts.
HAL_GetTick(): this function gets current SysTick counter value (incremented in SysTick interrupt) used by peripherals drivers to handle timeouts.
我建议用计时器做。通过这种方式,您还可以获得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的情况下完成它,只需要时间= TIMx-> CNT。是的,它取决于计时器配置和你的需求,你也必须知道uint32_t时间变量也可以溢出,但这是一个细节,它可以很容易地管理。