不用中断实现嘀嗒计数器

时间:2022-11-17 11:58:21


使用中断实现嘀嗒计数器

一般情况下,使用一个计数器设定为1ms来一次中断,在中断服务例程中将嘀嗒计数器加1。

uint32_t tick_count = 0;

void timer_isr(void)
{
tick_count++;
}

需要超时处理的代码每次比较嘀嗒计数器看是否超过预设值:

#define TICK_TIMEOUT    100
uint32_t tick_start = tick_count;
if(tick_count - tick_start > TICK_TIMEOUT) {
......
}

不用中断实现嘀嗒计数器

选择1个32位的定时器,设定定时器的预分频寄存器(prescaler),让计数器(counter)每1ms累加1。程序直接使用定时器的counter外设寄存器值作为嘀嗒计数器。

#define TICK_TIMEOUT    100
uint32_t tick_start = TIM0_CNT; // TIM0_CNT 为 定时器0的 counter 外设寄存器
if(TIM0_CNT - tick_start > TICK_TIMEOUT) {
......
}

预分频寄存器位数不够的情况

如果定时器的时钟频率比较高,而预分频寄存器(prescaler)位数不够,计数器(counter)做不到1ms累加一次,这种情况可以减小嘀嗒计数器的时间间隔,例如将间隔设定为0.1ms。如果嘀嗒计数器为32位整数,当嘀嗒间隔为1ms时,嘀嗒计数器的溢出时间大约是50天少一点;嘀嗒间隔减小到0.1ms后,嘀嗒计数器的溢出时间大约是5天少一点。如果要处理比溢出时间还要长的超时,那么需要额外的代码。

#define HAL_MS(ms)  ((ms) * 10)   // 定义一个宏,转换 ms 和嘀嗒数
#define TICK_TIMEOUT HAL_MS(100)
uint32_t tick_start = TIM0_CNT; // TIM0_CNT 为 定时器0的 counter 外设寄存器
if(TIM0_CNT - tick_start > TICK_TIMEOUT) {
......
}

只有16位定时器的情况

如果所需要的超时时间都是很短的,那么将嘀嗒计数器定义成16位整数。如果嘀嗒间隔为1ms,那么16位的嘀嗒计数器的溢出时间是65秒。如果嘀嗒间隔为0.1ms,那么溢出时间是6.5秒。这么短的溢出时间可能无法满足需求,那么定义32位的嘀嗒计数器,再定义一个嘀嗒计数器累加函数,尽量保证该函数在每个嘀嗒间隔内被调用至少一次。最坏情况下,必须在定时器溢出前调用一次。

// 定义 32 位的嘀嗒计数器
uint32_t tick32_count = 0;

// 定义嘀嗒计数器的累加函数,尽量保证该函数在每个嘀嗒间隔内被调用至少一次。
void tick_loop(void)
{
static uint16_t tick16_start = 0;
uint16_t tick16_count = TIM0_CNT; // 假设TIM0的 counter 寄存器为 16 位
tick32_count += tick16_count - tick16_start;
tick16_start = tick16_count;
}