我们通过下面的实验来分析实时性:
按下并松开按键1,通过串口打印"key1",按下并松开按键2打印"key2"
轮询系统(某外设某事件的flag)
在main中,轮询两个按键对应的GPIO口的端口输入数据寄存器(GPIOx_IDR)
while(1)
{
if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
{
printf("key1\n");
}
if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )
{
printf("key2\n");
}
}
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
/*等待按键释放 */
//有按键按下时,cpu会一直卡在这儿
while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
}
//没有按键按下时,函数立即返回
else
return KEY_OFF;
}
key1卡着的时候,可能key2已经是一次完整地按下又松开了,
所以轮询系统可能会丢失事件
key1卡着的时候,key2也一直在按着,等到key1处理完毕才能再处理key2的事件,
所以轮询系统可能不能及时处理事件,实时性不好
前后台系统(某外设某事件的中断)
main:循环处理key1、key2的事件 因为是根据flag顺序处理事件,所以不能及时处理事件
key1->EXTI0_IRQHandler:下降沿中断, 中断,可以及时响应事件key1,简单处理或立flag
key2->EXTI15_10_IRQHandler:下降沿中断 中断,可以及时响应事件key2,简单处理或立flag
(这里简单的处理printf可以在中断里运行,复杂的处理需要等到main里循环到才能执行)
#define KEY1_IRQHandler EXTI0_IRQHandler
#define KEY2_IRQHandler EXTI15_10_IRQHandler
void KEY1_IRQHandler(void)
{
//确保是否产生了EXTI Line中断
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
{
// LED1 取反
LED1_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
printf("key1\n");
while(1);
}
}
void KEY2_IRQHandler(void)
{
//确保是否产生了EXTI Line中断
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET)
{
// LED2 取反
LED2_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
printf("key2\n");
while(1);
}
}
中断
中断确保程序可以及时响应事件key1和key2
main->EXTI0_IRQHandler(key1)->main
现场的保存和恢复
嵌套
中断嵌套,确保优先级高的key1事件先处理
当key2运行的时候,按下并松开key1,key1的中断打断了key2的中断,此时两个中断都是active
main-> EXTI15_10_IRQHandler(key2)-> EXTI0_IRQHandler(key1)
pend
key1能打断key2,但是反过来就不行
从实时性角度来考虑,高优先级的中断正在运行,你当然只有等着啦(pend)
多任务系统
及时响应事件 | 中断可以打断正在运行的多任务系统里的某个任务 设置按键任务的信号量,让按键任务就绪 |
及时处理事件 | 退出中断时,运行OSIntExt,去运行更高优先级的就绪任务——按键任务。 中断退出后,返回被中断的任务 或运行 一个更高优先级的就绪任务。 |
任哲 3.4.3 P110
优先运行优先级最高的就绪任务:
1任务中,OSSched
一个任务结束了,下一个任务应该运行谁呢?这个思考决策的过程,就是调度啊。
2中断中,OSIntExt
来了中断,不仅要及时响应事件,还要及时处理事件,所以调度是必要的,因为很可能某个高优先级的任务(按键处理任务)就绪了。
任务级调度器OSSched()
task->OSTimeDly->OSSched
一个任务,正常运行到底时,调用OSTimeDly,OSTimeDly调用OSSched,去运行下一个就绪的优先级最高的任务。(任哲4.3.1 P156 )
一个任务运行过程中,被中断,中断退出后运行优先级更高的任务
那么什么时候恢复现场,继续运行呢?
todo:能运行到底的,不能运行到底的分两种
实验一:任务运行完后的切换
实验二:任务运行一半,按键中断,做了简单的事情,返回被中断的任务,继续处理
实验二:任务运行一半,按键中断,切换到按键任务,之后怎么返回到被中断的任务呢?
不返回的时候,进入某个状态,等按键任务结束之后,OSSched
中断级调度器OSIntExt()
中断退出后,返回被中断的任务,或运行 一个更高优先级的就绪任务。
(任哲4.1.2 P147)
总结
前后台,因为加了中断,所以可以及时响应事件
多任务,有中断,而且中断退出时,进行调度,切换到优先级更高的按键任务去及时处理事件,所以不仅能及时响应,而且能及时处理。