在您实际的ISR开始之前,有很多PUSH'和POP'ing寄存器要进行堆栈操作,这是在您提到的5个时钟周期之上。看一下生成的代码的反汇编。
根据您使用的工具链,以各种方式转储列出我们的程序集。我在Linux命令行上工作,这是我使用的命令(它需要.elf文件作为输入):
avr-objdump -C -d $(src).elf
看一看我最近用于ATtiny的代码片段。这是C代码的样子:
ISR( INT0_vect ) {
uint8_t myTIFR = TIFR;
uint8_t myTCNT1 = TCNT1;
这是为其生成的汇编代码:
00000056 <INT0_vect>:
56: 1f 92 push r1
58: 0f 92 push r0
5a: 0f b6 in r0, SREG ; 0x3f
5c: 0f 92 push r0
5e: 11 24 eor r1, r1
60: 2f 93 push r18
62: 3f 93 push r19
64: 4f 93 push r20
66: 8f 93 push r24
68: 9f 93 push r25
6a: af 93 push r26
6c: bf 93 push r27
6e: 48 b7 in r20, TIFR ; uint8_t myTIFR = TIFR;
70: 2f b5 in r18, TCNT1 ; uint8_t myTCNT1 = TCNT1;
老实说,我的C例程使用了更多的变量来导致所有这些push's和pop',但您明白了。
加载一个32位变量看起来像这样:
ec: 80 91 78 00 lds r24, 0x0078
f0: 90 91 79 00 lds r25, 0x0079
f4: a0 91 7a 00 lds r26, 0x007A
f8: b0 91 7b 00 lds r27, 0x007B
将32位变量增加1如下所示:
5e: 11 24 eor r1, r1
d6: 01 96 adiw r24, 0x01 ; 1
d8: a1 1d adc r26, r1
da: b1 1d adc r27, r1
存储一个32位变量如下所示:
dc: 80 93 78 00 sts 0x0078, r24
e0: 90 93 79 00 sts 0x0079, r25
e4: a0 93 7a 00 sts 0x007A, r26
e8: b0 93 7b 00 sts 0x007B, r27
然后,当然,一旦离开ISR,您就必须弹出旧值:
126: bf 91 pop r27
128: af 91 pop r26
12a: 9f 91 pop r25
12c: 8f 91 pop r24
12e: 4f 91 pop r20
130: 3f 91 pop r19
132: 2f 91 pop r18
134: 0f 90 pop r0
136: 0f be out SREG, r0 ; 0x3f
138: 0f 90 pop r0
13a: 1f 90 pop r1
13c: 18 95 reti
根据数据表中的指令摘要,大多数指令为单周期,而PUSH和POP为双周期。您知道延迟来自何处?