在了解中断子系统之前,首先要了解中断的概念。你正在看书,这时电话响了,你会怎么做呢?相信大多数人会这样:先标记看到的位置,接完电话回来后继续阅读。这就是一个现实生活中中断的例子,我们把“电话响了”成为中断源。Arduino UNO R3的主处理器ATMega328P拥有26个中断源,如下表所示:
<table border="1" style="width: 586px;">
<tbody>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center"><strong>向量号</strong></p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p align="center"><strong>程序地址</strong></p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p align="center"><strong>中断源</strong></p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p align="center"><strong>中断定义</strong></p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p align="center"><strong>中断服务程序名称</strong></p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">1</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0000</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>RESET</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>外部电平复位,上电复位,掉电检测复位,看门狗复位</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p> </p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">2</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0002</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>INT0</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>外部中断请求0</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>INT0_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">3</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0004</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>INT1</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>外部中断请求1</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>INT1_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">4</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0006</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>PCINT0</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>引脚电平变化中断请求0</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>PCINT0_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">5</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0008</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>PCINT1</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>引脚电平变化中断请求1</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>PCINT1_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">6</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x000A</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>PCINT2</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>引脚电平变化中断请求2</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>PCINT2_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">7</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x000C</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>WDT</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>看门狗溢出中断</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>WDT_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">8</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x000E</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER2 COMPA</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器2比较匹配A</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER2_COMPA_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">9</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0010</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER2 COMPB</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器2比较匹配B</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER2_COMPB_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">10</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0012</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER2 OVF</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器2溢出</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER2_OVF_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">11</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0014</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER1 CAPT</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器1事件捕捉</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER1_CAPT_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">12</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0016</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER1 COMPA</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器1比较匹配A</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER1_COMPA_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">13</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0018</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER1 COMPB</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器1比较匹配B</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER1_COMPB_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">14</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x001A</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER1 OVF</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器1溢出</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER1_OVF_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">15</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x001C</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER0 COMPA</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器0比较匹配A</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER0_COMPA_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">16</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x001E</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER0 COMPB</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器0比较匹配B</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER0_COMPB_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">17</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0020</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TIMER0 OVF</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>定时/计数器0溢出</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TIMER0_OVF_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">18</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0022</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>SPI STC</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>SPI串行传输结束</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>SPI_STC_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">19</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0024</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>USART RX</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>USART接收结束</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>USART_RX_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">20</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0026</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>USART UDRE</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>USART数据寄存器空</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>USART_UDRE_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">21</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0028</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>USART TX</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>USART,发送结束</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>USART_TX_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">22</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x002A</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>ADC</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>模数转换结束</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>ADC_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">23</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x002C</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>EE READY</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>EEPROM准备好</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>EE_READY_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">24</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x002E</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>ANALOG COMP</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>模拟比较器</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>ANALOG_COMP_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">25</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0030</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>TWI</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>两线串行接口</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>TWI_vect</p>
</td>
</tr>
<tr>
<td style="width: 19px;" valign="center" width="60">
<p align="center">26</p>
</td>
<td style="width: 85px;" valign="center" width="73">
<p>0x0032</p>
</td>
<td style="width: 84px;" valign="center" width="74">
<p>SPM READY</p>
</td>
<td style="width: 190px;" valign="center" width="231">
<p>保存程序存储器内容就绪</p>
</td>
<td style="width: 148px;" valign="center" width="130">
<p>SPM_ready_vect</p>
</td>
</tr>
</tbody>
</table>
这里以外部中断0为例了解对中断子系统的编程,沿用上一章中用于数字输入示例的电路,这个示例使得按键在按下时LED的状态取反:
<pre style="overflow-x:auto; background-color:#e9e9e9;">// Interrupt.ino
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}</pre>
与外部中断相关的Arduino库函数有:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode):启用指定引脚的外部中断并连接到指定中断服务程序
pin:指定外部中断的引脚
ISR:指定中断服务程序的名称
mode:LOW(低电平触发中断),CHANG(逻辑电平变化触发中断),RISING(上升沿触发中断)或FALLING(下降沿触发中断)
detachInterrupt(digitalPinToInterrupt(pin)):禁用指定中断
pin:指定取消外部中断的引脚
interrupts():开启总中断
noInterrupts():禁用总中断
ATMega328P的外部中断由2个相关寄存器控制,外部中断控制寄存器EICRA的结构如下图所示:
<table border="1">
<tbody>
<tr>
<td valign="top" width="81">
<p align="center"> </p>
</td>
<td valign="top" width="81">
<p align="center"> </p>
</td>
<td valign="top" width="81">
<p align="center"> </p>
</td>
<td colspan="2" valign="top" width="162">
<p align="center">INT1</p>
</td>
<td colspan="2" valign="top" width="162">
<p align="center">INT0</p>
</td>
</tr>
<tr>
<td valign="top" width="81">
<p align="center"> </p>
</td>
<td valign="top" width="81">
<p align="center"> </p>
</td>
<td valign="top" width="81">
<p align="center"> </p>
</td>
<td valign="top" width="81">
<p align="center">ISC11</p>
</td>
<td valign="top" width="81">
<p align="center">ISC10</p>
</td>
<td valign="top" width="81">
<p align="center">ISC01</p>
</td>
<td valign="top" width="81">
<p align="center">ISC00</p>
</td>
</tr>
</tbody>
</table>
ISCx[1:0](x = 0, 1)位用于设置外部中断的触发方式,如下表所示:
<table border="1" style="width: 257px;">
<tbody>
<tr>
<td style="width: 101px;" valign="center" width="91">
<p align="center"><strong>ISCx[1:0]</strong></p>
<p align="center"><strong>(x = 0, 1)</strong></p>
</td>
<td style="width: 140px;" valign="center" width="476">
<p align="center"><strong>外部中断触发方式</strong></p>
</td>
</tr>
<tr>
<td style="width: 101px;" valign="center" width="91">
<p align="center">00</p>
</td>
<td style="width: 140px;" valign="center" width="476">
<p align="justify">低电平</p>
</td>
</tr>
<tr>
<td style="width: 101px;" valign="center" width="91">
<p align="center">01</p>
</td>
<td style="width: 140px;" valign="center" width="476">
<p align="justify">逻辑电平变化</p>
</td>
</tr>
<tr>
<td style="width: 101px;" valign="center" width="91">
<p align="center">10</p>
</td>
<td style="width: 140px;" valign="center" width="476">
<p align="justify">下降沿</p>
</td>
</tr>
<tr>
<td style="width: 101px;" valign="center" width="91">
<p align="center">11</p>
</td>
<td style="width: 140px;" valign="center" width="476">
<p align="justify">上升沿</p>
</td>
</tr>
</tbody>
</table>
外部中断屏蔽寄存器EIMSK用于设置是否屏蔽外部中断,它的结构如下图所示:
<table border="1" style="width: 385px;">
<tbody>
<tr>
<td style="width: 40px;" valign="top" width="81">
<p align="center"> </p>
</td>
<td style="width: 40px;" valign="top" width="81">
<p align="center"> </p>
</td>
<td style="width: 40px;" valign="top" width="81">
<p align="center"> </p>
</td>
<td style="width: 40px;" valign="top" width="81">
<p align="center"> </p>
</td>
<td style="width: 40px;" valign="top" width="81">
<p align="center"> </p>
</td>
<td style="width: 70px;" valign="top" width="81">
<p align="center">INT1</p>
</td>
<td style="width: 69px;" valign="top" width="81">
<p align="center">INT0</p>
</td>
</tr>
</tbody>
</table>
若向其中某位写入1,则该位控制的外部中断启用;写入0则禁用。
通过直接访问寄存器改写以上程序为:
<pre style="overflow-x:auto; background-color:#e9e9e9;">// Interrupt_reg.ino
volatile byte state = LOW;
void setup() {
DDRB |= (1 << PB5);
DDRD &= ~(1 << PD2);
PORTD |= (1 << PD2);
EICRA &= ~(1 << ISC01) & ~(1 << ISC00);
EIMSK |= (1<< INT0);
sei(); // 启用总中断
}
void loop() {
if (state == HIGH) {
PORTB |= (1 << PB5);
} else {
PORTB &= ~(1 << PB5);
}
}
// 外部中断0中断处理函数
ISR(INT0_vect) {
state = !state;
}</pre>
转自:<a href="http://www.cnblogs.com/lets-blu/p/7513709.html">Lets_Blu</a>