Servus
Da wir in der Vorlesung jetzt mit Assembler begonnen haben und ich in den Ferien nicht weiter dazu gekommen bin mich mit dem Thema zu befassen muss ich doch wieder eine Grundlagen Frage stellen.
Interrupts wurden nicht behandelt, kamen aber im Beispielprogramm vor. Also zum AVR Tutorial und nachgesehen:
Zitat von
AVR Tutorial
Aufbau der Interruptvektortabelle
Jetzt müssen wir dem Assembler nur noch klarmachen, dass er unser rjmp interrupt0 an die richtige Stelle im Programmspeicher schreibt, nämlich an den Interruptvektor für INT0. Dazu gibt es die Assemblerdirektive. Durch .org 0x001 sagt man dem Assembler, dass er die darauffolgenden Befehle ab Adresse 0x001 im Programmspeicher platzieren soll. Diese Stelle wird von INT0 angesprungenen.
Damit man nicht alle Interruptvektoren immer nachschlagen muss, sind in der Definitionsdatei m8def.inc einfach zu merkende Namen für die Adressen definiert. Statt 0x001 kann man z.B. einfach INT0addr schreiben. Das hat außerdem den Vorteil, dass man bei Portierung des Programms auf einen anderen AVR-Mikrocontroller nur die passende Definitionsdatei einbinden muss, und sich über evtl. geänderte Adressen für die Interruptvektoren keine Gedanken zu machen braucht.
Nun gibt es nur noch ein Problem: Beim Reset (bzw. wenn die Spannung eingeschaltet wird) wird das Programm immer ab der Adresse 0x000 gestartet. Deswegen muss an diese Stelle ein Sprungbefehl zum Hauptprogramm erfolgen, z.B. rjmp RESET um an die mit RESET: markierte Stelle zu springen.
Wenn man mehrere Interrupts verwenden möchte, kann man auch, anstatt jeden Interruptvektor einzeln mit .org an die richtige Stelle zu rücken, die gesamte Sprungtabelle ausschreiben:
.include "m8def.inc"
.org 0x000 ; kommt ganz an den Anfang des Speichers
rjmp RESET ; Interruptvektoren überspringen
; und zum Hauptprogramm
rjmp EXT_INT0 ; IRQ0 Handler
rjmp EXT_INT1 ; IRQ1 Handler
rjmp TIM2_COMP
rjmp TIM2_OVF
rjmp TIM1_CAPT ; Timer1 Capture Handler
rjmp TIM1_COMPA ; Timer1 CompareA Handler
rjmp TIM1_COMPB ; Timer1 CompareB Handler
rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART_RXC ; USART RX Complete Handler
rjmp USART_DRE ; UDR Empty Handler
rjmp USART_TXC ; USART TX Complete Handler
rjmp ADC ; ADC Conversion Complete Interrupthandler
rjmp EE_RDY ; EEPROM Ready Handler
rjmp ANA_COMP ; Analog Comparator Handler
rjmp TWSI ; Two-wire Serial Interface Handler
rjmp SPM_RDY ; Store Program Memory Ready Handler
RESET: ; hier beginnt das Hauptprogramm
Hier ist es unbedingt nötig, bei unbenutzten Interruptvektoren statt des Sprungbefehls den Befehl reti reinzuschreiben. Wenn man einen Vektor einfach weglässt stehen die nachfolgenden Sprungbefehle sonst alle an der falschen Adresse im Speicher.
Hilft nur auch nicht weiter. Mein Problem: Die Adressierung. Uns wurde gesagt "BLOß KEINE FESTEN ADRESSEN FÜR DAS HAUPTPROGRAM!!!" und wenn ich das richtig sehe vergebe ich doch eine feste Adresse für das Hauptprogramm? Und für die Interrupts ebenso... Beispiel aus unserem Code:
Code:
.cseg
.org 0x0000
rjmp Progstart ; Interrupt Vektor für Reset
.org 0x0002
rjmp Extint1 ; Interrupt Vektor für externen Interrupt 1
.org 0x0018
rjmp TC1int ; Interrupt Vektor für Timer/Counter 1-Interrupt
.org 0x0045 ; Ende der Interrupt Vektor Tabelle
Progstart:
[...]
Extint1: ; ISR für externen Interrupt 1
reti
TC1int: ; ISR für Timer/Counter 1 Interrupt
reti
.exit
Beide Interrupts werden sonst nicht verwendet. Aber: Man benutzt doch einen Adressraum im Speicher für das Hauptprogramm, oder nicht? Von $0000 bis $0002 wenn ich das richtig sehe... Soll man aber doch nicht machen. Und warum werden Adressen für Interrupts ausgegeben die in ihrer Subroutine nichts tun auser an die Stelle zurück zu Springen an der sie benutzt werden ..
Ich bin verwirrt, helft mir
[/code]
Lesezeichen