Forum: Mikrocontroller und Digitale Elektronik Schwierigkeiten mit den externen Interrupts vom Atmega328p


von Laie Jonas (Gast)


Lesenswert?

Ich versuche schon seit heute morgen mein Programm zum laufen zu bringen 
und mir sind mittlerweile die Möglichkeiten ausgegangen.
Ich möchte lediglich eine Led mit einem Taster ansteuern und dass über 
einen Interrupt (Ich weiß dass es eigentlich Sinnlos ist mit dem 
Interrupt).

Ich habe bereits viele Seiten abgeklettert, aber keins der Beiträge 
konnte mein Problem lösen.
Nicht einmal dieser hier: 
Beitrag "Externer Interrupt - ATmega328P - Assembler"
Dass es nicht funktioniert hat nichts mit meinem uC zu tun, denn ich 
teste die Programme immer zu erst mit dem AVR Simulator und auch da wird 
der INT0 nicht einmal angesprungen.

Vielleicht kann mir ja jemand helfen ^^
1
.equ XTAL = 16000000 ;16 mHz
2
3
.equ BTN  = 2 ;Pinnumber of PORT_D
4
.equ LED  = 3 ;Pinnumber of PORT_D
5
6
.def temp1 = r16
7
.def temp2 = r17
8
9
.MACRO store
10
  .if  @0>0x3F
11
    sts  @0, @1
12
  .else
13
    out  @0, @1
14
  .endif
15
.ENDMACRO
16
17
18
.org 0x000
19
  rjmp init
20
  rjmp int_0
21
22
.org 0x032
23
  reti
24
init:
25
  ;Init stackpointer
26
  ldi temp1, HIGH(RAMEND)
27
  out SPH,   temp1
28
  ldi temp1, LOW(RAMEND)
29
  out SPL,   temp1
30
31
  ;Set led pin to output
32
  ldi temp1, (1 << LED)
33
  out DDRD, temp1
34
35
  ldi   temp1, (1 << ISC01)|(1 << ISC01) ;INT0 bei steigender Flanke
36
  store EICRA, temp1
37
  ldi   temp1, (1 << INT0) ;Nur INT0 aktivieren
38
  store EIMSK, temp1
39
  ;ldi     temp1, 0b00000001 ;Keine Ahnung welchen Zweck die ext. int. Flag Register erfüllen
40
    ;store   EIFR, temp1
41
  sei ;Interrupts generell zulassen
42
43
main_loop:
44
  rjmp main_loop
45
46
int_0:
47
        ;save SREG
48
  push  temp1
49
  in    temp1, SREG
50
  push  temp1
51
52
  ldi   temp1, (1 << LED)
53
  out   PORTD, temp1
54
55
  ;restore SREG
56
  pop   temp1
57
  out   SREG, temp1
58
  pop   temp1
59
  reti

von Peter (Gast)


Lesenswert?

Vielleicht versuchst du es erstmal in c und dann in Assembler

von Laie Jonas (Gast)


Lesenswert?

Peter schrieb:
> Vielleicht versuchst du es erstmal in c und dann in Assembler

Wie oft muss ich das den noch gesagt bekommen.
C löst meine Probleme auch nicht!
Ich bringe mir bewusst Assembler bei, da ich die internen Abläufe einer 
MCU verstehen möchte.

von Peter D. (peda)


Lesenswert?

Laie Jonas schrieb:
> C löst meine Probleme auch nicht!

C nimmt zumindest den richtigen Interruptvector.

von MerryXmas (Gast)


Lesenswert?

>ldi   temp1, (1 << ISC01)|(1 << ISC01)

Wahrscheinlich meinst Du:

ldi   temp1, (1 << ISC01)|(1 << ISC00)

Solche Schludereien krass nix gut beim Proggen.

von Laie Jonas (Gast)


Lesenswert?

MerryXmas schrieb:
>>ldi   temp1, (1 << ISC01)|(1 << ISC01)
>
> Wahrscheinlich meinst Du:
>
> ldi   temp1, (1 << ISC01)|(1 << ISC00)
>
> Solche Schludereien krass nix gut beim Proggen.

Das ist schon besser, genau.
Aber es klappt dennoch nicht :/

von MerryXmas (Gast)


Lesenswert?

>  rjmp init
>  rjmp int_0

Da sind zwei "r" zuviel.

von Laie Jonas (Gast)


Lesenswert?

MerryXmas schrieb:
>>  rjmp init
>>  rjmp int_0
>
> Da sind zwei "r" zuviel.

Ist in meinem Fall aber nicht Nötig

von Laie Jonas (Gast)


Lesenswert?

Bzw. doch habe ich so eben herausgefunden.

von Laie Jonas (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch mal ein Anhang.
Darauf ist zu erkennen, dass der PIN_2 von PORT_D (von mir) auf HIGH 
geschaltet wurde und dennoch wird kein Interrupt ausgelöst.

> MerryXmas schrieb:
>>>  rjmp init
>>>  rjmp int_0
>>
>> Da sind zwei "r" zuviel.
Das habe ich jetzt auch korrigiert.
Noch irgendeine Idee?

von Heiligenacht (Gast)


Lesenswert?

MerryXmas schrieb:
> rjmp init
>  rjmp int_0
>
> Da sind zwei "r" zuviel.

Ich würde sagen ein nop zu wenig.

von MerryXmas (Gast)


Lesenswert?

>Noch irgendeine Idee?

Nein. Habe es gerade im Simulator getestet. Bei mir funktioniert es.

von Peter (Gast)


Lesenswert?

Laie Jonas schrieb:
> Peter schrieb:
> Vielleicht versuchst du es erstmal in c und dann in Assembler
>
> Wie oft muss ich das den noch gesagt bekommen.
> C löst meine Probleme auch nicht!
> Ich bringe mir bewusst Assembler bei, da ich die internen Abläufe einer
> MCU verstehen möchte.

Das ist lobenswert. Aber wie man sieht wohl einfach etwas viel für den 
Anfang. Außerdem kannst du dir wenn du es in c machst ja parallel den 
Assembler Code anschauen den der Compiler ausspuckt.

von Michael U. (amiga)


Lesenswert?

Hallo,

Laie Jonas schrieb:
> ;ldi     temp1, 0b00000001 ;Keine Ahnung welchen Zweck die ext. int.
> Flag Register erfüllen
>     ;store   EIFR, temp1

nur wegen der Frage: damit wird das Interrupt-Flag zurückgesetzt.
Das wird gesetzt, wenn der Interruot ausgelöst wird und vom Aufruf der 
Interruptroutine autimatisch wieder gelöscht. Es gibt auch Interrupts, 
wo das nicht automatisch passiert, das Datenbaltt weiß, welche.

Hir wird es gelöscht, um einfach sicherzustellen, daß es am Anfang 
gelöscht ist. Es wird von der Hardwrae ja auch dann gesetzt, wenn die 
Interrupts global noch gesperrt sind. Das kann dann ja nach Programm 
durchuaus ungewollte Ergebinsse bringen.
Man kann ja auch den Interrupt global gesperrt haben und fragt z.B. das 
Flag selber ab, ob ein Interrupt erzeugt wird.
Kann durchaus in einigen Fällen auch Sinn machen.

Programmanfang sah bei mir immer so aus:
1
.include "m16def.inc"
2
3
.include "Definitionen.inc"
4
5
;****************************** Verktor-Liste ****************************
6
.CSEG
7
                rjmp    reset
8
9
.org INT1addr  ;External Interrupt1 Vector Address
10
                rjmp  irq_rds
11
12
.org OC1Aaddr  ;Output Compare1A Interrupt Vector Address
13
                rjmp  irq_timer
14
15
16
;****************************** Programm-Beginn **********************
17
18
;*********************************************************************
19
;  Initialisierungsroutine
20
;*********************************************************************
21
; Hardware initialisieren
22
23
.org  INT_VECTORS_SIZE
24
25
reset:  ldi     TEMP_A,low(RAMEND)     ; Stack an das interne Ram-Ende
26
        out     SPL,TEMP_A
27
        ldi     TEMP_A,high(RAMEND)
28
        out     SPH,TEMP_A

wenn man jetzt den Prozessor wechselt, muß man kaum was anpassen.
Die Reihenfolge, in der man die Vectoren einträgt, ist egal.
Man kann auch einfach RETI eintragen, um einen Aufruf abzufangen, der 
noch nicht fertig ist. Oder auch rjmp statt jmp...

Definitionen.inc enthält bei generell die Beschreibungen der benutzten 
Pins als Kommentar, dazu den ganzen .equ Kram meiner eigenen Pin-, 
Register, Ram-Adressennamen usw.

So kann man das gut "recyclen" und ich kann es auch nach 10 Jahren noch 
enträtseln, was uch da verzapft habe...

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Laie Jonas schrieb:

> .org 0x032
>   reti
> init:


Besser ist:

.cseg
init:

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


Lesenswert?

Laie Jonas schrieb:
> Vielleicht kann mir ja jemand helfen ^^

 Und was genau soll deine INT-routine machen ?
1
  ldi   temp1, (1 << LED)
2
  out   PORTD, temp1

 Da wird, je nach Beschaltung, die LED ein einziges mal entweder
 ein- oder ausgeschaltet und das wars dann.

 Wenn die LED falschrum angeschlossen ist, wird sie nicht einmal
 aufleuchten.

von Dieter F. (Gast)


Lesenswert?

Laie Jonas schrieb:
> ldi   temp1, (1 << ISC01)|(1 << ISC01) ;INT0 bei steigender Flanke

Mit 2 mal ISC01 ist das = "fallender Flanke" - da kannst Du den Pin 
setzten, bis es Ostern wird :-)

von Peter D. (peda)


Lesenswert?

MerryXmas schrieb:
> Da sind zwei "r" zuviel.

Bzw. anders gesagt, das rjmp wird auf dem falschen Interruptvektor 
plaziert, da ein rjmp kürzer ist, als der Abstand der Vektoren.
Die saubere Lösung ist daher, mit der .org Anweisung immer die richtige 
Adresse zu erzwingen. Dann wäre es auf dem ATmega88 und auf dem 
ATmega328 lauffähig.
Mit Assembler muß man viel sorgfältiger und disziplinierter als mit C 
programmieren.

von Peter D. (peda)


Lesenswert?

Laie Jonas schrieb:
> C löst meine Probleme auch nicht!

Das ist aber sehr weit aus dem Fenster gelehnt. Du hast ja keine C-Code 
gepostet, den man reviewen könnte.

Peter schrieb:
> Aber wie man sieht wohl einfach etwas viel für den
> Anfang.

Den Eindruck habe ich auch. Man baut damit nur noch weitere Fehler ein, 
anstatt sich besser auf das eigentliche Problem zu fokussieren.
Abgesehen davon, daß es hier mehr C-Experten gibt.

von Dieter F. (Gast)


Lesenswert?

Ich bin jetzt kein Assembler-Freak - aber so sollte es funktionieren 
(zumindest im Simulator, da prellt nichts ...):
1
.equ XTAL = 16000000 ;16 mHz
2
3
.equ BTN  = 2 ;Pinnumber of PORT_D
4
.equ LED  = 3 ;Pinnumber of PORT_D
5
6
.def temp1 = r16
7
.def temp2 = r17
8
9
.MACRO store
10
  .if  @0>0x3F
11
    sts  @0, @1
12
  .else
13
    out  @0, @1
14
  .endif
15
.ENDMACRO
16
17
;Address Labels Code Comments
18
.org 0x0000 jmp RESET      ; Reset Handler
19
.org 0x0002 jmp EXT_INT0    ; IRQ0 Handler
20
21
RESET: 
22
  ldi r16, high(RAMEND)    ; Main program start
23
  out SPH,r16      ; Set Stack Pointer to top of RAM
24
  ldi r16, low(RAMEND)
25
  out SPL,r16
26
27
28
init:
29
  ;Set led pin to output
30
  ldi temp1, (1 << LED)
31
  out DDRD, temp1
32
33
  ldi   temp1, (1 << ISC00)|(1 << ISC01)  ;INT0 bei steigender Flanke
34
  store EICRA, temp1
35
  ldi   temp1, (1 << INT0)    ;Nur INT0 aktivieren
36
  store EIMSK, temp1
37
38
  sei          ;Interrupts generell zulassen
39
40
41
main_loop:
42
  rjmp main_loop
43
44
45
46
47
48
EXT_INT0:
49
  ;save SREG
50
  push  temp1
51
  in    temp1, SREG
52
  push  temp1
53
54
  sbi   PIND, LED            ; PIN 2 von Port D togglen
55
56
  ;restore SREG
57
  pop   temp1
58
  out   SREG, temp1
59
  pop   temp1
60
  reti

von Laie Jonas (Gast)


Lesenswert?

Dieter F. schrieb:
> Ich bin jetzt kein Assembler-Freak - aber so sollte es funktionieren
> (zumindest im Simulator, da prellt nichts ...):

Das ist genau der gleiche Code den ich bei mir verwende (Nach der 
Korrektur natürlich).
Leider scheint auch das nicht bei mir zu funken.
Wenn es bei dir und @MerryXmas funktioniert, dann stimmt wohl etwa nicht 
mit meiner AVR-Studio Version (Erst kürzlich heruntergeladen).

von Dieter F. (Gast)


Lesenswert?

Laie Jonas schrieb:
> Leider scheint auch das nicht bei mir zu funken.

Fällt mir schwer, das nachzuvollziehen.

Laie Jonas schrieb:
> Wenn es bei dir und @MerryXmas funktioniert, dann stimmt wohl etwa nicht
> mit meiner AVR-Studio Version (Erst kürzlich heruntergeladen).

Ich verwende die aktuelle Atmel Studio 7 Version (7.0.1931). Mit meiner 
Version funktioniert es prima (im Simulator).

von Oliver S. (oliverso)


Lesenswert?

Mit deinem Studio wird schon alles stimmen. Das verhält sich 
grundsätzlich seltsam bei Interrupts.

Setz mal in die ISR einen Breakpoint, um setze den Eingang per 
Stimuli-File.

Oder probier es gleich auf der echten Hardware. Wenn die led leuchtet, 
hat es geklappt.

Oliver

von Laie Jonas (Gast)


Lesenswert?

Ich habe es jetzt mal mit dem Beispielprogramm vom Tutorial getestet:
https://www.mikrocontroller.net/articles/AVR-Tutorial:_Interrupts#Beispiel

Wahnsinn, auch hier wird bei mir im AVR Simulator nicht in die Int. 
Vektor Tabelle gesprungen.
Die Endlosschleife läuft einfach weiter.
...

von Laie Jonas (Gast)


Lesenswert?

Oliver S. schrieb:
> Oder probier es gleich auf der echten Hardware. Wenn die led leuchtet,
> hat es geklappt.

Es hat geklappt.
Nach mehrmaliger Fehlkorrektur hatte ich es einfach sein gelassen es auf 
echter Hardware zu testen und habe einfach den Simulator benutzt.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Also ich probiere es immer auf der echten Hardware. Den Simulator 
benutze ich nur, wenn ich wissen möchte, was intern mit den Registern 
passiert, bzw. wenn irgendwelche Stringfunktionen baue oder der berühmte 
Dauerbrenner Umwandlung von Zahlen oder "irgendwas von und nach ASCII".

Ich finde auch nicht, daß das zu schwer oder zuviel für den Anfang ist. 
Eine LED leuchten lassen ist irgendwann geschafft, ein "Hallo Welt!" auf 
einem Display ist irgendwann geschafft - und dann gibt es immer was 
neues, was sich auszuprobieren und zu lernen lohnt. Dabei gibts 
natürlich auch neue Fehler zu machen, neue Probleme und neue Fragen. 
Finde ich völlig normal so.

Muss aber dazu sagen, daß ich schon Erfahrung mit Assembler vom x86 
hatte. Und der hat die deutlich besseren Debugger, was die Bedienung 
angeht. Der muss aber keine extra Hardware beherrschen, vielleicht 
liegt's daran.

Lass Dich von den C-Fanboys hier nicht unterkriegen. Assembler auf dem 
AVR ist cool und macht Spaß. Beim PIC könnte ich verstehen wenn man sagt 
C ist besser. Der bietet nur sehr wenige Befehle und keinen großen 
Registersatz wie der AVR, das braucht man aber, um mit Assembler Spaß 
dran zu haben. Ich programmiere gerade meine AlarmSau in Assmbler, das 
sind derzeit etwa 120kb Quellcode, um die 4300 Befehle... da fängt's 
erst an, so richtig Spaß zu machen.

von Laie Jonas (Gast)


Lesenswert?

Ben B. schrieb:
> Finde ich völlig normal so.

danke

Ben B. schrieb:
> Ich programmiere gerade meine AlarmSau in Assmbler, das
> sind derzeit etwa 120kb Quellcode, um die 4300 Befehle...

Mit welchen uC?

von MerryXmas (Gast)


Lesenswert?

>Wahnsinn, auch hier wird bei mir im AVR Simulator nicht in die Int.
>Vektor Tabelle gesprungen.
>Die Endlosschleife läuft einfach weiter.

Hm... very komische Sache.

Stimmt die Controller-Einstellung im Simulator? Nicht, dass von Dir 
unbemerkt ein ATmega48 simuliert wird oder so (alles schon dagewesen...)
Menüpunkt Debug, Untermenü "Check platform and device"

Normalerweise müsste im Simulator sofort (einen Maschinentakt später) 
das Bit INTF0 im EIFR gesetzt werden, wenn Du PIND2 von 0 auf 1 änderst. 
Passiert das?

Und was ist, wenn Du PIND in Ruhe lässt, aber INTF0 von Hand setzt? Wird 
dann der Interruptvektor int_0 angesprungen?

Kannst Du beides noch testen, bitte?

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Angehängte Dateien:

Lesenswert?

>> Ich programmiere gerade meine AlarmSau in Assmbler
> Mit welchen uC?

ATMega1284P. (und ATMega88 für's Terminal).

von Laie Jonas (Gast)


Lesenswert?

MerryXmas schrieb:
> Stimmt die Controller-Einstellung im Simulator? Nicht, dass von Dir
> unbemerkt ein ATmega48 simuliert wird oder so (alles schon dagewesen...)
> Menüpunkt Debug, Untermenü "Check platform and device"
>
> Normalerweise müsste im Simulator sofort (einen Maschinentakt später)
> das Bit INTF0 im EIFR gesetzt werden, wenn Du PIND2 von 0 auf 1 änderst.
> Passiert das?
>
> Und was ist, wenn Du PIND in Ruhe lässt, aber INTF0 von Hand setzt? Wird
> dann der Interruptvektor int_0 angesprungen?

Hatte ich bereits alles getestet und der das Bit INTF0 im EIFR wird auch 
richtig gesetzt, wenn es zum Interrupt kommt.
Aber angesprungen wird die Int. Tabelle dennoch nicht :/

Ben B. schrieb:
>>> Ich programmiere gerade meine AlarmSau in Assmbler
>> Mit welchen uC?
>
> ATMega1284P. (und ATMega88 für's Terminal).

Sieht sehr interessant aus.
Wusste gar nicht, dass es so große Elkos gibt :D
Hab auch deinen Beitrag dazu entdeckt: 
Beitrag "ambitioniertestes Lochraster-Projekt (und meine AlarmSau)"

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Gibt noch viel größere Elkos... :) Der größte den ich hier habe, hat 
6800µF bei 400 oder 450V, der passt aber nicht so gut auf die Platine. 
Gibt auch welche im Stahlblechgehäuse für industrielle Anwendungen, da 
sind der Größe keine Grenzen gesetzt.

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.