Forum: Mikrocontroller und Digitale Elektronik AVR External Interrupt Hilfe


von Crafter C. (crafter_c)


Lesenswert?

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 
46
  sts EICRA,r16
47
48
  sei            ;enable interrupts
49
loop:
50
  rjmp loop
51
52
LED_ON:
53
  cli            ;disable Interrupt
54
  sbi PORTB,5        ;set bit 5 
55
  sei            ;enable interrupts
56
  reti          ;return to Interrupt

von Karl M. (Gast)


Lesenswert?

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            ;disable Interrupt
3
  sbi PORTB,5        ;set bit 5 
4
  sei            ;enable interrupts
5
  reti          ;return to Interrupt
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
ldi r16, 0b00100000    ;set PB5 as OUTPUT
2
out DDRB, r16      ;load to DDRB

Also read modify write, kann man natürlich auch über ein weiteres Macros 
lösen.
1
xIn r16,DDRB
2
ori r16,(1<<PB5)
3
xOut DDRB,r16

Gleiches für diese Zeile:
1
ldi r16, 0b00000100;set PD2 as PULLUP
2
out PortD, r16 ;load to PortD

Neu:
1
xIn r16,DDRD
2
andi r16,~(1<<PD2) ; clear bit, set to input
3
xOut DDRD,r16

xIn r16,PortD
ori r16,(1<<PD2) ; set bit, set pullup on
xOut PortD,r16[/c]
1
;INT0: ISC0[1:0] = 10 - falling edge!
2
xIn r16, EICRA
3
andi r16,~((1<<ISC01)|(1<<ISC00)) ; clear bits
4
ori r16,((1<<ISC01)|(0<<ISC00)) ; set bits, for the programmer
5
xOut EICRA,r16
6
7
; Nicht vergessen sollte man auch das INTF0 Flag zu löschen
8
ldi r16,(1<<INTF0)
9
xOut EIFR,r16 ; ja das macht man so!
10
11
; enable INT0 interrupt request
12
xIn r16, EIMSK
13
ori r16,(1<<INT0)
14
xOut EIMSK,r16

von Dirk B. (Gast)


Lesenswert?

rjmp  init      ;RESET
rjmp  LED_ON      ;INT0
geht schief, da der ATMega328P long jmp als Interruptvektoren hat
rjmp  init nop     ;RESET
rjmp  LED_ON nop     ;INT0
oder
jmp  init      ;RESET
jmp  LED_ON      ;INT0
reti nop
...
'erwischt'  int0 besser.
oder
.org 0
rjmp  init      ;RESET .org 1 unprogrammed
.org 2
rjmp  LED_ON      ;INT0

von Peter D. (peda)


Lesenswert?

Dirk B. schrieb:
> .org 0
> rjmp  init      ;RESET .org 1 unprogrammed
> .org 2
> rjmp  LED_ON      ;INT0

Man sollte es besser gleich richtig machen:
1
        .org    INT0addr
2
        rjmp    LED_ON

von Crafter C. (crafter_c)


Lesenswert?

Danke für die Antworten, das Programm läuft jetzt. Ich habe aber noch 
einige Fragen zu den Befehlen
1
andi r16,~((1<<ISC01)|(1<<ISC00)) ; clear bits
Was bedeutet dieses "~"?
1
.org 0
2
rjmp  init      ;RESET
3
.org 2
4
rjmp  LED_ON      ;INT0      
5
reti          ;INT1
6
reti          ;PCINT0
7
reti          ;PCINT1
8
reti          ;PCINT2
9
reti          ;WDT
10
.
11
.
12
.
Was hat es mit dem ".org" auf sich?

von Karl M. (Gast)


Lesenswert?

Hallo,

da hilft Dir dann die Dokumentation zum AVR Assembler weiter.

Damit kannst Du dir selbst, auch zusätzlich mit dem Datenblatt des AVR 
µC, einige Frage beantworten:

https://www.microchip.com/webdoc/avrassembler/avrassembler.wb_expressions.html

Beitrag #5583240 wurde von einem Moderator gelöscht.
von Karl M. (Gast)


Lesenswert?

Jetzt kannst Du durchstarten!

Es ist über die Suchfunktion sehr einfach auch die ORG Anweisung zu 
finden:

https://www.microchip.com/webdoc/avrassembler/avrassembler.wb_directives.html

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

: Bearbeitet durch User
von Dirk B. (Gast)


Lesenswert?

.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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.