tim2 定时器是一个 32 位分辨率的定时器,你想要一个 64 位的分辨率。有两种方法可以模拟 64 位计数器,以跟踪您的正常运行时间。
-
每次达到要跟踪的时间单位时,都会增加一个变量。但这将是极其低效的,因为微控制器会进行大量持续的上下文切换。
-
第二种方法是使用 32 位变量扩展计时器。然后在溢出时增加此类变量。
MSB LSB
+--------------+ +--------------+
| 32bit uint | | 32bit timer |
+--------------+ +--------------+
它的工作方式是,在定时器达到0xffffffff(这是 32 位无符号计数器的最大值)后,定时器将溢出并从 0 开始。如果在第 32 位之后还有另一个位,它将翻转(与递增相同)。你可以做的是通过增加一个变量来模拟这种精确的行为。
首先,设置你的计时器。
static TIM_HandleTypeDef s_TimerInstance = {
.Instance = TIM2
};
void setup_timer()
{
__TIM2_CLK_ENABLE();
s_TimerInstance.Init.Prescaler = ##; //Chose the correct value that fits your needs
s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
s_TimerInstance.Init.Period = 0xffffffff; //Chose the correct value that fits your needs
s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //Also choose this value
s_TimerInstance.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&s_TimerInstance);
HAL_TIM_Base_Start(&s_TimerInstance);
}
你的处理程序,每次你的计时器到达0xffffffff时都必须调用它
extern void TIM2_IRQHandler();
void TIM2_IRQHandler()
{
HAL_TIM_IRQHandler(&s_TimerInstance);
}
uint32_t extension;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
extension++; //Increment
}
结合扩展变量和计时器值。每次要获取扩展器计数器值时使用此函数。您可以将其设为内联以避免额外调用,也可以将其设为宏。
uint64_t get_time()
{
return (extension << 32) & (__HAL_TIM_GET_COUNTER(&s_TimerInstance));
}
现在把所有东西粘在一起
int main(void)
{
HAL_Init(); //Initialize HAL library
InitializeTimer(); //Initialize timer
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
while(1);
}
注意,现在 tim2 将被使用直到它溢出。不应更改,否则以下代码将不起作用。此外,设置除法器,使计时器按您之前所述每微秒递增一次。
此外,您可以使用计时器来计算秒数,然后计算微秒。如果您计算秒数,则最多可以数到 2^32 秒,即 4294967296。一年大约有 31536000 秒。使用 32 位计数器 (4294967296/31536000),您最多可以计算 136.19252 年的正常运行时间。然后通过将正常运行时间除以 1000000 (uptime/1000000) 来获得微秒。我不知道你打算用微控制器做什么,但数秒对我来说听起来更有意义。
如果您真的想要精确,您仍然可以通过计算秒数来做到这一点,您可以将计时器计数器值添加到微秒计数中,您可以通过将秒数降低到微秒来获得,这样您就可以抵消没有的微秒' t 被添加到第二个计数中。