首页 > 代码库 > AVR开发 Arduino方法(二) 中断子系统
AVR开发 Arduino方法(二) 中断子系统
在了解ATMega328P的中断子系统之前,首先要了解中断的概念。你正在看书,这时电话响了,你会怎么做呢?相信大多数人会这样:先标记看到的位置,接完电话回来后继续阅读。这就是一个现实生活中中断的例子,我们把“电话响了”成为中断源。ATMega328P拥有26个中断源,如下表所示:
向量号 |
程序地址 |
中断源 |
中断定义 |
中断服务程序名称 |
1 |
0x0000 |
RESET |
外部电平复位,上电复位,掉电检测复位,看门狗复位 |
|
2 |
0x0002 |
INT0 |
外部中断请求0 |
INT0_vect |
3 |
0x0004 |
INT1 |
外部中断请求1 |
INT1_vect |
4 |
0x0006 |
PCINT0 |
引脚电平变化中断请求0 |
PCINT0_vect |
5 |
0x0008 |
PCINT1 |
引脚电平变化中断请求1 |
PCINT1_vect |
6 |
0x000A |
PCINT2 |
引脚电平变化中断请求2 |
PCINT2_vect |
7 |
0x000C |
WDT |
看门狗溢出中断 |
WDT_vect |
8 |
0x000E |
TIMER2 COMPA |
定时/计数器2比较匹配A |
TIMER2_COMPA_vect |
9 |
0x0010 |
TIMER2 COMPB |
定时/计数器2比较匹配B |
TIMER2_COMPB_vect |
10 |
0x0012 |
TIMER2 OVF |
定时/计数器2溢出 |
TIMER2_OVF_vect |
11 |
0x0014 |
TIMER1 CAPT |
定时/计数器1事件捕捉 |
TIMER1_CAPT_vect |
12 |
0x0016 |
TIMER1 COMPA |
定时/计数器1比较匹配A |
TIMER1_COMPA_vect |
13 |
0x0018 |
TIMER1 COMPB |
定时/计数器1比较匹配B |
TIMER1_COMPB_vect |
14 |
0x001A |
TIMER1 OVF |
定时/计数器1溢出 |
TIMER1_OVF_vect |
15 |
0x001C |
TIMER0 COMPA |
定时/计数器0比较匹配A |
TIMER0_COMPA_vect |
16 |
0x001E |
TIMER0 COMPB |
定时/计数器0比较匹配B |
TIMER0_COMPB_vect |
17 |
0x0020 |
TIMER0 OVF |
定时/计数器0溢出 |
TIMER0_OVF_vect |
18 |
0x0022 |
SPI STC |
SPI串行传输结束 |
SPI_STC_vect |
19 |
0x0024 |
USART RX |
USART接收结束 |
USART_RX_vect |
20 |
0x0026 |
USART UDRE |
USART数据寄存器空 |
USART_UDRE_vect |
21 |
0x0028 |
USART TX |
USART,发送结束 |
USART_TX_vect |
22 |
0x002A |
ADC |
模数转换结束 |
ADC_vect |
23 |
0x002C |
EE READY |
EEPROM准备好 |
EE_READY_vect |
24 |
0x002E |
ANALOG COMP |
模拟比较器 |
ANALOG_COMP_vect |
25 |
0x0030 |
TWI |
两线串行接口 |
TWI_vect |
26 |
0x0032 |
SPM READY |
保存程序存储器内容就绪 |
SPM_ready_vect |
这里以外部中断0为例了解对中断子系统的编程,沿用上一章中用于数字输入示例的电路:
1 const byte ledPin = 13; 2 const byte interruptPin = 2; 3 volatile byte state = LOW; 4 5 void setup() { 6 pinMode(ledPin, OUTPUT); 7 pinMode(interruptPin, INPUT_PULLUP); 8 attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE); 9 } 10 11 void loop() { 12 digitalWrite(ledPin, state); 13 } 14 15 void blink() { 16 state = !state; 17 }
与外部中断相关的Arduino库函数有:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode):启用指定引脚的外部中断并连接到指定中断服务程序
pin:指定外部中断的引脚
ISR:指定中断服务程序的名称
mode:LOW(低电平触发中断),CHANG(逻辑电平变化触发中断),RISING(上升沿触发中断)或FALLING(下降沿触发中断)
detachInterrupt(digitalPinToInterrupt(pin)):禁用指定中断
pin:指定取消外部中断的引脚
interrupts():开启总中断
noInterrupts():禁用总中断
ATMega328P的外部中断由3个寄存器控制,外部中断控制寄存器EICRA用于设置外部中断的触发方式,ISCx[1:0](x = 0, 1)设置为00时,由低电平触发中断;设置为01时,由逻辑电平变化触发中断;设置为10时,为下降沿触发中断;设置为11时,为上升沿触发中断。EICRA寄存器的结构如下图所示:
|
|
INT1 |
INT0 |
|||
|
|
|
ISC11 |
ISC10 |
ISC01 |
ISC00 |
外部中断屏蔽寄存器EIMSK用于设置是否屏蔽外部中断,若向其中某位写入1,则该位控制的外部中断启用;写入0则禁用。EIMSK寄存器的结构如下图所示:
|
|
|
|
INT1 |
INT0 |
外部中断标志寄存器EIFR在外部中断被触发时,相应的标志位被置1。该寄存器由CPU自动清0,不需要手动配置。
通过直接访问寄存器改写以上程序为:
1 volatile byte state = LOW; 2 3 void setup() { 4 DDRB |= (1 << PB5); 5 6 DDRD &= ~(1 << PD2); 7 PORTD |= (1 << PD2); 8 EICRA &= ~(1 << ISC01) & ~(1 << ISC00); 9 EIMSK |= (1 << INT0); 10 sei(); // 启用总中断 11 } 12 13 void loop() { 14 if (state == HIGH) { 15 PORTB |= (1 << PB5); 16 } else { 17 PORTB &= ~(1 << PB5); 18 } 19 } 20 21 // 外部中断0中断处理函数 22 ISR(INT0_vect) { 23 state = !state; 24 }
*中断源表摘自《Arduino高级开发权威指南(原书第2版)》,[美]Steven F. Barrett著 潘鑫磊译,机械工业出版社,2014年出版。
AVR开发 Arduino方法(二) 中断子系统