Ich will mit Assember afangen und habe ein simples Interruptprogram
geschrieben, aber mein Problem ist, dass der Interrupt nicht ausgelöst
wird. Ich habe PB5 als Output und PD2 als input mit PULLUP eingestellt.
Der Interrupt INT0 ist eingeschaltet und sollte bei einem Pinchange
getriggert werden, aber nichts funktioniert, wenn ich den PD2 auf GND
stecke.
ATMega328P
1
.include "m328pdef.inc"
2
3
begin:
4
5
rjmp init ;RESET
6
rjmp LED_ON ;INT0
7
reti ;INT1
8
reti ;PCINT0
9
reti ;PCINT1
10
reti ;PCINT2
11
reti ;WDT
12
reti ;TIMER2_COMPA
13
reti ;TIMER2_COMPB
14
reti ;TIMER2_OVF
15
reti ;TIMER1_CAPT
16
reti ;TIMER1_COMPA
17
reti ;TIMER1_COMPB
18
reti ;TIMER1_OVF
19
reti ;TIMER0_COMPA
20
reti ;TIMER0_COMPB
21
reti ;TIMER0_OVF
22
reti ;SPI STC
23
reti ;USART_RX
24
reti ;USART_UDRE
25
reti ;USART_TX
26
reti ;ADC
27
reti ;EE READY
28
reti ;ANALOG COMP
29
30
init:
31
ldi r16, high(RAMEND) ;setup stack
32
out SPH, r16 ;
33
ldi r16,low(RAMEND) ;
34
out SPL, r16 ;
35
36
ldi r16, 0b00100000 ;set PB5 as OUTPUT
37
out DDRB, r16 ;load to DDRB
38
39
ldi r16, 0b00000100 ;set PD2 as PULLUP
40
out PortD, r16 ;load to PortD
41
42
ldi r16, 0b00000001 ;enable INT0 interrupt
43
out EIMSK,r16
44
45
ldi r16, 0b00000001 ;set when the Interrupt inerrupt
Hallo,
arbeite doch mit .org 0x0
für den Start der "Interrupt-Sprung-Tabelle" und mit einem weiteren .org
0x???? mit dem korrekten Start des Programms.
Dann dies hier, was soll das?
1
LED_ON:
2
cli;disableInterrupt
3
sbiPORTB,5;setbit5
4
sei;enableinterrupts
5
reti;returntoInterrupt
Weisst Du wie ein Interrupt Request bei einem Atmel µC finktioniert?
Es ist nicht notwendig und unnötig das "Global Interrupt Enable" Bit zu
verändern.
Register musst Du hier noch nicht sichern.
Ich verwende in Macro xIn und xOut, dass automatisch die Konvertierung
zu IN/ LDS und OUT/ STS durchführt.
Dann ist es problematisch bei großen Programmen so vorzugehen, da man
nie den aktuellen Zustand eines Registers mit einbezieht:
1
ldir16,0b00100000;setPB5asOUTPUT
2
outDDRB,r16;loadtoDDRB
Also read modify write, kann man natürlich auch über ein weiteres Macros
lösen.
1
xInr16,DDRB
2
orir16,(1<<PB5)
3
xOutDDRB,r16
Gleiches für diese Zeile:
1
ldir16,0b00000100;setPD2asPULLUP
2
outPortD,r16;loadtoPortD
Neu:
1
xInr16,DDRD
2
andir16,~(1<<PD2);clearbit,settoinput
3
xOutDDRD,r16
xIn r16,PortD
ori r16,(1<<PD2) ; set bit, set pullup on
xOut PortD,r16[/c]
Crafter C. schrieb:> Was hat es mit dem ".org" auf sich?
Damit wird die Adresse im flash festgelegt.
Übrigens funktioniert dein Programm nur weil du .org 2
stehen hast.
Alle AVRs über 8KB Flash sehen jmp vor (2 Words), alle AVRs mit
weniger als 8KB benutzen rjmp (1 Word).
Deswegen sollte beim ATMEGA328P jmp und nicht rjmp in der
INT-Vector Table stehen oder ein .org mit richtiger Adresse vor
dem entsprechenden INT-Vector.
.org definiert die Programmspeicheradresse an die der nächste Befehl
geschrieben wird. In deinem Fall stehen die Interupvektoren
reset: addr 0
int0: addr 2
... bei einem avr mit weniger Speicher der nur rjmp benötigt
reset:addr 0
int0: addr 1
mit dem tw. üblichen
rjmp reset
rjmp int0
....
stehen die Befehle gemäß der Länge der vorigen Befehle im
Programmspeicher. rjmp: 1 Word jmp:2 Word. Die Festlegung mit .org
[addr]ist also praktisch eine Versicherung, dass der Befehl richtig zum
Aufruf steht, der µC springt beim Imterupt int0 immer zur Adresse 2
(etwas schwer in Worten zu beschreiben)
.org 0
(r)jmp init ; mit der Sicherheit fester Adressen ist jmp/rjmp egal
.org INT0addr ;INT0addr bzw. XXXXaddr sind Bezeichner für die passenden
Adresse.
(r)jmp init0
wäre noch besser/verständlicher, aber ich war mir über die Schreibweise
nicht ganz sicher.
"~" ist invertiert d.h. ~00000001 ---> 11111110
wenn du bit0 (byte: 0000.0001) löschen möchtest, dann gibt aktuelles
byte (xxxx.xxxx) UND nicht (0000.0001) --> xxxx.xxx0; bit0 cleared