轮询还不够
想象一下,我们有一个PIC设备需要在其中一个引脚上接收数字信号时做某事。这可以使用探测输入引脚的while循环轻松实现,如果该引脚读取特定的数字级别,代码可以执行一些响应代码。但是,这种检测方法存在一些问题:
轮询可能会阻塞
信号可能会错过
当PIC轮询引脚并检测到未满足所需输入时,PIC只是处于环路中,直到检测到信号为止。这意味着在检测到输入之前没有其他代码可以执行,这可能是浪费。如果这还不够刺激,快速的外部信号呢?如果PIC引脚上的输入信号太快,则可能无法检测到,这意味着忽略了有效的输入脉冲。那么,我们如何解决这个问题呢?有没有办法检测不阻止我们的PIC的输入和其他事件,以便它可以在等待时执行其他任务?这是中断发挥作用的地方!
中断的作用大多数(如果不是所有PIC)都具有称为中断的功能,在检测到中断信号时强制PIC执行特定任务。因此,以前面的示例为例,PIC在检测到外部信号时需要执行特定任务。
我们可以定义一个在收到任何中断时运行的中断例程,而不是轮询。然后,在此中断服务程序(ISR)中,我们可以检查是否检测到外部信号。如果是,可以使PIC运行一些响应代码,否则我们可以忽略该中断(因为它可能来自我们不感兴趣的另一个源)。在主代码中,我们根本不进行任何轮询,因为它全部由我们半导体定义的硬件和中断例程处理。
但是,您必须了解中断服务程序不会与PIC执行的主代码同时运行; 相反,PIC停止运行主代码,运行中断服务程序,然后恢复主代码。这就是为什么中断服务程序应尽可能短而快,因为它们在运行时会阻塞主代码。
某些PIC器件具有中断优先级,但目前我们只考虑PIC16F819,它没有中断优先级。
编写中断服务程序(ISR)现在我们已经基本了解了中断的工作原理,让我们看看如何使用XC8为PIC16F819编写基本的ISR。关于XC8的一个很好的功能是它可以处理很多细节要求,比如上下文保存,所以我们只需要担心设置中断并写下PIC在检测到中断时的行为方式。
第一项任务是启用PIC的中断机制以及启用IC外设中断。大多数PIC都有一个名为INTCON的寄存器,该寄存器保存最重要的中断信息。GIE首先负责启用中断,而PEIE用于启用外设中断(包括INT引脚,ADC,SPI,I2C和I / O更改)。
下一步是使能INT引脚中断,通过将INTCON寄存器中的INTE位置1来完成。INT引脚位于RB0(引脚6)上,我们还通过确保其TRIS位置1来将该引脚配置为输入(在前一篇文章中介绍)。
我们可以改变的另一个位是INTEDG,它位于OPTION_REG寄存器中。该位置1时,INT引脚上的数字信号从逻辑0变为逻辑1(上升沿)时,中断将触发。该位清零时,当信号从逻辑1变为逻辑0(下降沿)时,将触发中断。
配置这些位后,PIC将在INT引脚检测到上升沿信号时执行中断程序。但是什么代码?ISR在哪里?这就是XC8让事情变得简单的地方!我们需要做的就是定义一个中断函数,XC8足够聪明,可以告诉PIC将代码放在正确的位置,以便PIC在接收到中断时执行它。下面是一个空中断服务程序,它显示了如何在XC8中定义中断例程。
当然,这个例程是空的,会引起一些问题。触发中断时,会置位标志位。当我们的ISR启动时,我们需要清除这些中断标志位,否则,ISR一旦完成就会再次运行(它是触发中断的标志位!)。因此,在我们的ISR中,第一个任务是检查INT标志是否已被引发(等于1)。如果有,我们将清除它,然后执行我们的响应代码。
所有中断源都有中断允许位和中断标志位,您可以使用数据表找到它们驻留在哪些寄存器中。在本例中,当在INT引脚上检测到上升沿时,我们会短暂打开连接到RA0的蜂鸣器。
我们的中断示例在我们的示例中,PIC执行以下任务:
闪烁LED(主代码中)
在INT(RB0)上检测到上升沿信号时发出短促的蜂鸣声(中断响应)
该程序的关键特性是LED代码将一直运行,直到检测到中断,在这种情况下执行ISR。一旦完成蜂鸣声(ISR),PIC将恢复正常操作并继续执行LED闪烁序列。请注意,PIC仍然可以在主代码中的for循环延迟期间检测到中断IC。这样,延迟不能阻止输入信号的检测。