You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATmega328P中断向量表1字/2字条目均生效的原因探究

问题:ATmega328P中断向量表两种条目大小为何均能正常工作?

在搭载ATmega328P的Arduino Uno开发板与avr-g++编译环境中:

  • 使用标准启动文件和库的LED闪烁定时器中断代码,反汇编显示中断向量表每个条目为2字(4字节),代码运行正常;
  • 手写启动代码和中断向量表时,反汇编显示每个条目为1字(2字节),代码同样运行正常。

按逻辑,处理器应决定向量表条目大小,仅一种情况有效,但为何两种方式均能正常工作?


#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

ISR(TIMER1_COMPA_vect) {
  PORTB ^= _BV(PB5); // Toggle LED
}

int main(void) {
  DDRB |= _BV(DDB5); // Set PB5 as output

  // Configure Timer1: CTC mode, prescaler 256, 1Hz interrupt
  TCCR1A = 0;
  TCCR1B = _BV(WGM12) | _BV(CS12); // CTC mode, prescaler 256
  OCR1A = 62500 - 50000; // 16MHz / 256 / 1Hz
  TIMSK1 = _BV(OCIE1A); // Enable Timer1 Compare Match A interrupt

  sei(); // Enable global interrupts

  while (1) ;
}

编译命令

avr-g++ -mmcu=atmega328p -Os -o blink.elf blink.cpp -Wa,-adhlns=blink.lst -Wl,-Map,blink.map
avr-objcopy -O ihex blink.elf blink.hex
avr-objdump -d -S blink.elf > blink.final.lst

反汇编片段

...
00000000 <__vectors>:
   0:   0c 94 34 00     jmp 0x68    ; 0x68 <__ctors_end>
   4:   0c 94 3e 00     jmp 0x7c    ; 0x7c <__bad_interrupt>
...
  28:   0c 94 3e 00     jmp 0x7c    ; 0x7c <__bad_interrupt>
  2c:   0c 94 40 00     jmp 0x80    ; 0x80 <__vector_11>
  30:   0c 94 3e 00     jmp 0x7c    ; 0x7c <__bad_interrupt>
...
  64:   0c 94 3e 00     jmp 0x7c    ; 0x7c <__bad_interrupt>
:100000000C9434000C943E000C943E000C943E0082
:100010000C943E000C943E000C943E000C943E0068
:100020000C943E000C943E000C943E000C94400056
:100030000C943E000C943E000C943E000C943E0048
:100040000C943E000C943E000C943E000C943E0038
:100050000C943E000C943E000C943E000C943E0028
:100060000C943E000C943E0011241FBECFEFD8E04C
:10007000DEBFCDBF0E9452000C9463000C940000C0
:100080001F920F920FB60F9211248F939F9385B1F9
:1000900090E2892785B99F918F910F900FBE0F90A5
:1000A0001F901895259A109280008CE08093810013
:1000B00084ED90E3909389008093880082E08093A0
:0A00C0006F007894FFCFF894FFCF93
:00000001FF

手写启动代码的实现

.section .vectors, "ax", @progbits

    .global __vectors
__vectors:
    rjmp reset_handler           ; Vector 0: Reset

    ; Other interrupts can be dummy jumps to safe handlers or zeros
    rjmp dummy_handler           ; Vector 1
...
    rjmp dummy_handler           ; Vector 10

    .extern __vector_11          ; Declare ISR from C++
    rjmp __vector_11             ; Vector 11: Timer/Counter1 Capture Event ISR

    ; Further vectors...
    rjmp dummy_handler           ; Vector 12
...
    rjmp dummy_handler           ; Vector 26

.equ RAMEND, 0x08FF   ; Last SRAM address for ATmega328P
.equ SPL, 0x3D     ; I/O register address for Stack Pointer Low
.equ SPH, 0x3E     ; I/O register address for Stack Pointer High

reset_handler:
    ; Initialize stack pointer
    ldi r16, lo8(RAMEND)
    out SPL, r16
    ldi r16, hi8(RAMEND)
    out SPH, r16

    ; Call main()
    call main
    rjmp .                       ; Loop forever if main returns

dummy_handler:
    rjmp .                       ; Loop forever for unexpected interrupts

    .global main
#include <avr/io.h>
#include <avr/interrupt.h>

ISR(TIMER1_COMPA_vect) {
  PORTB ^= (1 << PB5);  // Toggle LED
}

void timer1CompASetup(uint16_t ocr1aValue) {
  TCCR1A = 0;

  TCCR1B = (1 << WGM12) | (1 << CS12); // CTC mode, prescaler 256
  OCR1A = ocr1aValue;                  // 16MHz / 256 / 1Hz

  TIMSK1 = (1 << OCIE1A); // Timer1 COMPA interrupt enable
}

int main(void) {
  timer1CompASetup(62500 - 1);

  DDRB |= (1 << 5); // PB5 output (LED pin)

  sei();

  while (1) ;
}

编译命令

avr-g++ -mmcu=atmega328p -Os -nostartfiles -nostdlib -nodefaultlibs -ffreestanding -o blink.elf blink.S blink.cpp -Wa,-adhlns=blink.lst -Wl,-e,__vectors,-Map,blink.map,--section-start=.vectors=0x0000
avr-objcopy -O ihex blink.elf blink.hex
avr-objdump -d -S blink.elf > blink.final.lst

反汇编片段

00000000 <__vectors>:
   0:   19 c0           rjmp    .+50        ; 0x34 <reset_handler>
   2:   1f c0           rjmp    .+62        ; 0x42 <dummy_handler>
...
  14:   16 c0           rjmp    .+44        ; 0x42 <dummy_handler>
  16:   16 c0           rjmp    .+44        ; 0x44 <__vector_11>
  18:   14 c0           rjmp    .+40        ; 0x42 <dummy_handler>
...
  32:   07 c0           rjmp    .+14        ; 0x42 <dummy_handler>
:1000000019C01FC01EC01DC01CC01BC01AC019C013
:1000100018C017C016C016C014C013C012C011C03B
:1000200010C00FC00EC00DC00CC00BC00AC009C06C
:1000300008C007C00FEF0DBF08E00EBF0E944100CF
:1000400000C000C01F920F920FB60F9211248F9321
:100050009F9385B190E2892785B99F918F910F90E9
:100060000FBE0F901F901895109280002CE02093E7
:100070008100909389008093880082E080936F00D4
:10008000089583E294EF0E943400259A7894FFCF7C
:00000001FF

内容的提问来源于stack exchange,提问作者vd1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 15:42:26