别忘了随手关上“门”
0赞别忘了随手关上“门”
题目想表达的一个意思是“把门打开以后,别忘了随手关上门”。记得特权同学在第一个单位工作时,每天早晨上班都能提前个半小时,每次将电梯升上7楼以后, 都不忘按上1以后才出电梯。原因很简单,只是希望能给后面来的同事省一点时间,多一些便利。印象中好像也有那么一句话“……,别忘了把电梯降回一楼”。当 然,开篇那句话和这件事其实想表达的也都是一个意思。
之所以想起这码事,和近来在一个软件上遇到的几个问题解决过程中的所感所悟不无关系。这是一个与中断相关的问题,如图1所示,这是一个常见的带有中断的简 单软件流程图。通常只是在中断函数中置位中断标志位,然后回到主程序中检查到该中断标志位置位的时候才去执行相应的处理。
图1
光看流程图可能意思表达的不是很明白,简单的一段代码可能更贴切一些。
假定中断函数如下:
Void 中断函数名(void)
{
① 读状态寄存器,确认当前中断已经产生
② 清除中断寄存器相关标志位
③ 置位中断标志位(这是一个用户自定义的系统变量,有别于中断寄存器)
}
而通常情况下,我们会在主函数中做如下操作:
Void main(void)
{
If(中断标志位置位)
{
① 清除中断标志位
② 确认是否满足中断处理条件?是,则进入中断处理函数,否,则继续。
}
}
一般而言,这样的处理方式也没太有问题。当然对于多个中断的程序,并且还掺杂着优先级因素在里面的程序,就应另当别论了。而一般情况下,所谓的“把门关上”其实指的可能就是main函数中的“清除中断标志位”这一步了。
那,特权同学遇到的情况比较不一般,所以“关门”也就稍微费点劲。说白了,这是一个PIO下降沿捕获中断,而它的触发波形很不规则,或者你可以理解为“抖 动”比较厉害。这里不直接点名说的是什么情况,就当这个PIO输入源就是一个按键,那么这个按键在按下和拿起的时候都是有抖动的,如果没有任何消抖的措 施,恐怕用户想要的一次触发会演变为N次触发(N大于1),那用户肯定要抗议。那么问题就延伸到如何“消抖”上了。当然,为了有效滤除“按下”的抖动,我 们可能只需要在判断中断标志位置位与否后再加一个延时(按键的消抖通常取20ms),这个延时过后如果键值仍然处于按下状态,那么就认为确实按键被按下 了,而如果程序就此为止,其实也没有问题。有人可能会质疑按键释放的抖动如何滤除?其实在按下滤波的时候已经一并滤除了。
而特权同学遇到的问题如果仅仅停留于此,也就没有更多文章可作。如图2所示,在实际探索过程中发现这个PIO信号除了触发和释放过程有“抖动”,在中断处 理过程中也受影响有类似的“抖动”状况(产生中断源和处理中断的对象是一个芯片,至于为什么恐怕只有厂商知道了,经过多方测试验证,特权同学觉得这个不像 是干扰的问题,应该是由于芯片内部处理机制的问题)。
图2
这就产生了一个新的问题,在主函数还没有退出处理函数时,会再次产生一个新的中断。而如果在系统退出当前处理过程后,如果PIO本身的低电平状态还未退 出,那么有可能接着引发一次“误动作”,这个“误动作”还有可能随着PIO低电平的保持一致的连续下去,这是很可怕的。
在发现的问题之后,特权同学第一反应是在进入中断处理后直接关掉中断,直到完成一次中断处理后再次开启。而问题其实好像没有这么简单,因为如此处理后状况 依旧。为什么?因为中断虽然被关上了,但它本身其实依然在运转着,在判断到触发条件时仍然会改变当前的中断寄存器状态,而一旦重新开启中断后,立刻回进入 中断函数。那么这也导致了“噩梦”会周而复始的继续下去。寻根究底,问题还出在中断寄存器这“扇门”还未彻底的关上。于是,如果能在重新开启中断后执行的 第一条命令里关上这“扇门”,问题其实就能迎刃而解。我们习惯上并不会在意这个情况,因为我们总以为中断关上以后就万事大吉了,而实际上我们关上的只是中 断而已,并没有完全将外设的工作停止,所以在重新开启中断后势必会出现一些意料之外的状况。
另外,关于这滤除抖动的延时对系统是一个不小的时间开销,在多个中断源的系统中,如果包含了其他实时性处理要求较高的外设,那么很可能导致系统的性能大打 折扣。那么如何巧妙的处理这个不能不执行的“消抖”过程呢?呵呵,卖个关子,且待下回特权同学有空了再慢慢分析。