Arduino中的中断

什么是中断

中断(Interrupt)是一种在计算机中被广泛应用的一种重要的技术,它是一种CPU事件处理机制。其本质是一个电信号,这个信号由某个硬件或软件产生并由处理器处理。当处理器接收到中断信号时会暂停当前任务,跳到一个叫中断服务例程(ISR)的一段程序中处理中断,当中断被处理完成后,CPU将回到原来的任务继续工作。与中断相对的事件处理机制是轮询,顾名思义就是不断的询问相关的硬件是否做好准备。
​ 中断的一个比较常见的例子是磁盘读写。我们都知道,磁盘的速度与CPU的速度不在一个数量级上面(ms和ns的区别),当CPU希望从磁盘上面拷贝一个或多个扇区到内存时,如果采用轮询的方法,CPU需要在这个过程中不断的将数据从磁盘读入寄存器,再从寄存器写入到内存中。需要注意的是CPU与磁盘的速度有着巨大的差异,两者相差将近6个数量级,这样会使得CPU在把大部分的时间都花在等待磁盘响应上面,这无疑是一种浪费——在磁盘读写期间CPU完全可以进行其他的运算,却浪费在了无意义的等待上面。而如果使用中断的方法,CPU将会把磁盘请求发送给一个叫DMA控制器的硬件,然后把当前任务挂起,先执行其他任务。DMA会“接管”这个工作,有它负责代替CPU完成轮询的工作,并通过总线直接将数据写到内存上面。复制完成后,它会触发一个中断通知CPU已经复制完成,CPU响应后就可以继续执行请求磁盘读写的任务。这样一来,CPU就不再需要等待拖拉的磁盘了。事实上,现代计算机都离不开中断,我们对计算机的任何的一个操作(包括鼠标或键盘),都会触发相应的中断,系统调用也需要通过中断完成(起码经典过程是如此)。
​ 根据中断的来源,我们可以把中断分为软中断和硬中断,顾名思义他们分别就是由软件和硬件触发的中断。

在Arduino中使用中断

Arduino中主要有时钟中断和外部中断,本文所说的中断指的是外部中断。Arduino中的外部中断通常是由Pin口(数字Pin口,不是模拟口)电平改变触发的。每种型号的Arduino版都有数个Pin口可以用来注册中断,具体如下:

开发板 可以用来注册中断的Pin口
Uno, Nano, Mini, other 328-based 2, 3
Uno WiFi Rev.2 所有数字口
Mega, Mega2560, MegaADK 2, 3, 18, 19, 20, 21
Micro, Leonardo, other 32u4-based 0, 1, 2, 3, 7
Zero 除了4号口外的所有数字口
MKR Family boards 0, 1, 4, 5, 6, 7, 8, 9, A1, A2
Due 所有数字口
101 所有数字口 (只有 2, 5, 7, 8, 10, 11, 12, 13数字口可以使用CHANGE类型中断,中断类型在下文有介绍)

注册中断主要是通过attachInterrupt()函数实现的,其原型为:

void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode);
  1. 第一个参数为中断号,Arduino上每个可以注册中断的Pin口都会被分配一个中断号,这里需要传入的是中断号而不是Pin口号。但是不同的Arduino开发板上面的中断号分配并不完全一样。各个开发板的Pin口号和中断号对应关系如下:

    开发板 中断号0 中断号1 中断号2 中断号3 中断号4 中断号5
    Uno, Ethernet PIN 2 PIN 3
    Mega2560 PIN 2 PIN 3 PIN 21 PIN 20 PIN 19 PIN 18
    基于32u4的开发板 如 Leonardo, Micro PIN 3 PIN 2 PIN 0 PIN 1 PIN 7

    从上表中可以看出同一个Pin口在不同的开发板上可能会有不同的中断号,这势必会影响程序的可移植性。幸运的是,Arduino还提供了另一个函数digitalPinToInterrupt(int)。从名字就能看出,这个函数能输入Pin口号并输出对应的中断号。需要注意的是,输入的Pin口号需要在上述的支持列表当中。所以,Arduino官方推荐我们使用

    attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); 
    

    这种方式来注册中断号。

  2. 第二个参数是中断服务例程(ISR)的函数指针,在C/C++中直接写该函数的函数名即可。在触发时,该函数将会被调用。该函数必须没有任何的参数也没有任何的返回值。

  3. 第三个参数是中断触发条件,由几个可选的值:

    LOW 当中断所在Pin口处于低电平时触发

    CHANGE 当中断所在Pin口电平改变时触发

    RISING 当中断所在Pin口从低电平变为高电平(上升沿)时触发

    FALLING 当中断所在Pin口从高电平变为低电平(下降沿)时触发

    对于Due,Zero和MKR1000开发板,还有一个HIGH表示当中断所在Pin口处于高电平时触发



在Arduino中使用中断需要注意的问题

  1. 由于中断会打断正常代码的运行,因此ISR的应该尽可能快地执行完毕。
  2. 在ISR中修改的全局变量要用volatile修饰符修饰以防止编译器优化
  3. 在ISR中不能使用其他用中断实现的函数,如millis() delay() 等。延时可以使用 delayMicroseconds(),它不是用中断实现的。

你可能感兴趣的:(Arduino)