正文
目录会跟随阅读位置移动。
阅读进度

非阻塞式延时应用广泛,当前以定时器TIM2实现非阻塞式程序为例。
非阻塞式延时的核心:用定时器中断生成时间基准,主循环通过时间戳判断是否到点,不阻塞CPU运行。
定时器实现非阻塞式是非阻塞延时的一种典型实现(但二者并不等价),接下来以定时器TIM2为例。
tick()| 参数 | 配置值 | 说明 |
|---|---|---|
| 定时器时钟 | 72MHz | APB1总线时钟倍频后 |
| 预分频值 (PSC) | 71 | 72MHz / (71+1) = 1MHz |
| 自动重装载值 (ARR) | 999 | 1MHz / (999+1) = 1kHz → 1ms中断 |
| 中断优先级 | 2 |
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period =1000-1;
TIM_TimeBaseInitStructure.TIM_Prescaler =72-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//ITConfig开启中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//优先级分配
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
该中断函数应用于定时任务的执行:定时器溢出中断,用于实现周期性任务,比如定时翻转LED、生成PWM波、任务调度。
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) ==SET)
{
/*Tick时间戳:此处放入基于Tick的定时任务,如:
Key_Tick();
LED_Tick();*/
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
Tick时间戳说明:
- 中断内每1ms执行一次
Key_Tick()/LED_Tick(),完成Tick计数累加- 通过Tick计数判断延时是否到达,实现非阻塞延时,彻底替代
delay()死等。 比如可以在Key_Tick()中进行累计计数,每当数到20ms时会进行一次事件检测,去查看按键的状态,而相对于delay(),只是站在主程序(它)旁边,不干涉它的前进,等监测到想要的结果,就告知它,等它做完了,就退开,等待下一次的监测结果;而不是堵着主干道,一定得等到结果才允许通行,导致使用任务都被卡死。- 主循环全程不阻塞,可并行处理多个任务
结尾总结
在该篇中,通过定时器实现非阻塞式程序,一般需要配置定时器和中断服务函数,并且还需要通过Tick()来具体实现各个模块的周期性监测(?还有其他功能吧)