ATMega 48, Pinchange Interrupt, ASM

OP #8101112
Lesenswert?
• ▲
▼

Hallo,

ich habe mal wieder ein Problem bei dem ich nicht weiterkomme. Ich versuche bei einem ATMega48 den Pinchange Interrupt mit einer ganz einfachen Schaltung zu testen. Am Pin PC5 hängt eine LED, die durch einen Interrupt an PB2 geschaltet werden soll.

1
.cseg                    
2
.org 0  
3
    rjmp  start                
4
.org PCI0addr
5
    rjmp  PCI0_handler      ; Interrupt Handler
6

7
;**********************************************************************************
8
PCI0_handler:
9
  clr    count
10
loop:
11
  sbi    PORTC, 5    ;Portbit setzen
12
  rcall  wait
13
  cbi    PORTC, 5    ;Portbit löschen
14
  rcall  wait
15
  inc    count
16
  cpi    count, 5
17
  breq  exit
18
rjmp  loop          ;Programmschleife neu beginnen
19

20
exit:
21
reti            ;rückkehr zur normalsituation
22

23
;***********************************************************************************
24
start:
25
  ldi    temp, low(ramend)
26
  out    spl, temp    
27
  ldi    temp, high(ramend)
28
  out    sph, temp      
29
  
30
;PortB; B2 = Interruptpin; PortC; C5 = LED
31
  ldi    temp, 0x00    ;PortB auf Eingang
32
  out    DDRB, temp    ;setzen
33
  ldi    temp, 0xFF    ;PortC auf Ausgang
34
  out    DDRC, temp    ;setzen
35

36
  ldi    temp, 1<<PCIE0    ;Pin Change Interrupt Enable 0
37
  sts    PCICR, temp
38
  ldi    temp, 1<<PCINT2    ;Pin Change Mask Register 0
39
  sts    PCMSK0, temp    ;PCINT2 wird gesetzt
40
        
41
  sei
42

43
warten:
44
rjmp  warten

Ohne Interrupt funktioniert alles wie erwartet. Füge ich die Interruptroutinen ein, passiert nach dem Einschalten erst nichts (es gibt ja noch keinen Interrupt) aber nach wenigen Sekunden fängt die LED an ununterbrochen zu blinken, ohne daß ein Interrupt ausgelöst wurde.

#8101185
Lesenswert?
• ▲
▼

Bruno M. schrieb:

Eigentlich ist er offen, da der Interrupt Spannung hat.

...mit "Interrupt" ist im allgemeinen die/eine Unterbrechung gemeint - die kann sowieso keine "Spannung" haben...und wenn schon Spannung, dann bitte mal anschauen welche Spannungen im gültigen Toleranzbereich der Pegel "high" und "low" liegen da es ja gerade bei dieser Sache um definierte Zustände und den Wechsel zwischen diesen geht.

https://de.wikipedia.org/wiki/Logikpegel

https://www.google.com/search?q=avr+logikpegel+definition

https://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen

Wenn du mit Interrupt in dem Zusammenhang den Pin change Interrupt meintest - woher sollte der zugehörige Pin ohne Beschaltung eine "Spannung" und damit einen definierten festen Zustand/Pegel bekommen, wenn die internen Pullups aus sind?

Bitte auch mit bedenken, in den meisten Fällen ist es völlig "übertrieben gar falsch" einen Interrupt zu nutzen. Das macht man nur wenn es um absolut zeitkritische Reaktionen im kleinsten Zeitbruchteil geht - da man sich damit eventuelle Störungen direkt in den Prozessor holt... Also erstmal aufführen worum es überhaupt geht - in den meisten Fällen reicht es den Pin im ms Bereich zu pollen und ggf. sogar mit einer Entprellung auf ein Ereignis zu triggern...

: Bearbeitet durch User
#8101267
Lesenswert?
• ▲
▼

Moin Na ja, kann man machen, ist aber Unsinn. Eine Schleife in einer Interrupt Service Routine und da auch noch einen "Wait" Aufruf, das gibt nur Probleme. Auch fehlt das "Retten" von Registern. Auch wenn es hier keine Bedeutung hat, aber irgendwann übersieht man diese "kleine" Eigenheit, das ein Interrupt ein Programm an einer unbekannten Stelle einfach unterbricht und eine ISR einfach alles überschreiben kann, was ihr so verfügbar ist. Das betrifft auch die Flag-Register. Angenommen, ein Programm hat eine Laufzeit von 1ms und das ist noch hoch gegriffen, dann braucht es keine ISR, um einen Eingang abzufragen und den auch noch zu entprellen. Eine ISR macht Sinn, wenn ich ein Signal erfassen will, was kürzer wie die Programmlaufzeit ist und durch polling möglicherweise nicht erfasst wird. Von einer Lichtschranke möglicherweise. Die hat auch in der Regel kein "Prellen" im Signal. Oder wenn ein Signal zu einer definierten Zeit gesetzt und rückgesetzt werden soll. Auch beim Multiplexen kann eine ISR unschönes Flackern unterbinden. Grad bei Assembler macht es Sinn, sich an EVA zu halten. Die Programmschleife enthält in der Reihenfolge Eingabe, Verarbeitung und Ausgabe. Man sollte bedenken, bei einer Taktfrequenz von 1 MHz ist die Dauer eines Taktes 1/1000000Hz = 1µs. Wenn ein Befehl 2 Takte braucht sind in 1ms 500 Befehle verarbeitet. Zugegeben, 500 Befehle scheinen nicht viel, aber nicht alle Befehle in einem Programm werden auch bearbeitet. So ist das Einlesen von Signalen mit Entprellen und Ablegen zur Verarbeitung pro Port mit ca.10 bis 15 Befehlen erledigt. Ausgabe pro Port mit ca. 4 bis 6. Bei Assembler lässt sich so eine Laufzeit ganz gut berechnen. Fazit: ISR in der Eingabe ja, wo Ereignisse nicht vom Programm sicher erfasst werden, ansonsten am Anfang einer Programmschleife den Eingang über den Port einlesen. Keine Warteroutine in der Progammschleife. Entprellen über Zustandsänderung und Zählvorgang bei unverändertem Eingang. So kann das Programm ohne Verzögerung alle Teile abarbeiten. Gruß oldmax

: Bearbeitet durch User
#8101272
Lesenswert?
• ▲
▼

Ist zwar etwas offtopic, aber mit Interrupts hatte ich letztens auch Probleme. Es wird empfohlen, den Interrupthandler so kurz und knapp wie möglich zu gestalten, evtl. lediglich ein Flagbit zu setzen, das in der Main-Routine dann abgefragt und resettet wird. Dort hinein wird dann das, was eigentlich in der ISR stehen würde, geschrieben. Bei deinem Programm in die "warten"-loop. Gerade Timeranwendungen kommen sich gerne in die Quere. So TWI und Timer-Overflow zur Tastenabfrage. Das nur nebenbei.
/offtopic

ciao
gustav

Angehängte Dateien:
: Bearbeitet durch User
#8101385
Lesenswert?
• ▲
▼

Martin V. schrieb:

Auch fehlt das "Retten" von Registern

...dafür habe ich, zu meinen PIC ASM Zeiten - etwa vor 25 Jahren, zwei Makros gehabt. PUSH und POP.

Karl B. schrieb:

Gerade Timeranwendungen kommen sich gerne in die Quere.

Ich hatte mal Fujitsu MC (MB90F352) programmiert, dort gab es einen großen ISR Bereich in der sogar Interrupt Prios. bekommen konnten...meine ich mich zu erinnern (war 2006)

https://datasheet4u.com/pdf/547610/MB90F352.pdf

#8101433
Lesenswert?
• ▲
▼

Moin, ein Beispiel, um Register in der ISR zu retten:

1
push R16 
2
in R16,SREG 
3
push R16   
4
;push R17 
5

6
;Dein Programm kann das SREG, R16 (und R17) ändern.
7

8
;z.B. mit
9
;ldi R16, 5
10
;sts Marke, R16 kannst Du einen einen „Merker“ setzen,
11
;den Du im Hauptprogramm abarbeitest.
12

13
;Pop R17 
14
pop R16 
15
out SREG,R16 
16
pop R16 
17
reti

Gruß Carsten

: Bearbeitet durch Moderator
Beitrag #8101435 wurde von einem Moderator gelöscht.
#8101501
Lesenswert?
• ▲
▼

Thorsten S. schrieb:

Bitte auch mit bedenken, in den meisten Fällen ist es völlig "übertrieben gar falsch" einen Interrupt zu nutzen. Das macht man nur wenn es um absolut zeitkritische Reaktionen im kleinsten Zeitbruchteil geht - da man sich damit eventuelle Störungen direkt in den Prozessor holt... Also erstmal aufführen worum es überhaupt geht - in den meisten Fällen reicht es den Pin im ms Bereich zu pollen und ggf. sogar mit einer Entprellung auf ein Ereignis zu triggern...

Polling im Bereich von ms... Jetzt weiß ich wieder, warum diese kleinen Mikrocontroller viel zu wenig Ressourcen in der heutigen Maker-Welt haben. Und dieser irre Stromverbrauch. Ohne Drehstromanschluß braucht man gar nicht erst anfangen, etwas zu entwickeln.

#8101515
Lesenswert?
• ▲
▼

Wenn ich jetzt damit rausrücke, dass es ein Vorschlag von KI war, dann hat das auch wieder einen direkten Bezug zum Ursprungsthema. Mir kam es auch etwas komisch vor, aber der Funktionstest beweist, dass es funktioniert. Habe das Programm nochmal für Compare Match Timer umgeschrieben, nicht den Overflow-Interrupt wie ursprünglich. Und da fällt auf, dass die Nullen bei Aufruf von bin2dec nur so sprudeln. Ja, die Entprellroutine könnte im simpelsten Falle aus einer einzigen Zeitschleife bestehen. Ändere ich das Timer Interrupt Intervall von statt 10ms etwa auf 100ms, sieht man das deutlich. Nur wenn ich die Taste bewusst länger drücke, sprudeln die Nullen. Bei den anderen Tasten werden ja in den Texttabellenaufrufen mehrere Zeitschleifen hintereinander ausgeführt, so dass diese nicht noch extra hinzugefügt werden müssen. Da kommt dann der entsprechende Text nur einmal, auch weil er so wie so bei Wiederholung auf dieselbe Stelle geschrieben wüde. Eine Entprellroutine, die sauber einmal eine fallende und dann eine steigende Flanke produziert, egal, wie zittrig der Finger ist, ist hier zunächst nicht gefordert. Damit werde ich aber demnächst auch experimentieren. Es muss ja nicht wieder so bombastisch werden wie von @PeDa ausgefeilt.

Und ja, der Kommentar ist stellenweise fehlerbehaftet. Auch hier hat mir KI gezeigt, wo es lang geht. Zum Beispiel die Pointer-Geschichte. Ich hatte formuliert, dass das SRAM ausgelesen würde, dabei ist "lpm" bereits im "normalen" Programmflash-Bereich.

ciao
gustav

Angehängte Dateien:
: Bearbeitet durch User
#8101533
Lesenswert?
• ▲
▼

Karl B. schrieb:

Ist zwar etwas offtopic, aber mit Interrupts hatte ich letztens auch Probleme. Es wird empfohlen, den Interrupthandler so kurz und knapp wie möglich zu gestalten, evtl. lediglich ein Flagbit zu setzen, das in der Main-Routine dann abgefragt und resettet wird.

Teilweise machen meine Programme in 'main()' nur die Initialisierung des Controllers und hängen dann in einer 'Schlafschleife' fest.
Die Interruptroutine erledigt alles und ist daher sehr lang.

Ich bin eben böse ;-)

#8101620
Lesenswert?
• ▲
▼

Hi Mi N. schrieb im Beitrag #8101533:

Die Interruptroutine erledigt alles und ist daher sehr lang.

Macht unglaublich viel Sinn. Da dürfen Tastersignale (langes Signal) und Lichtblitze auf Fotozellen (wahnsinnig schnelles Signal) gleichberechtigt sicher erfasst und auch zugeordnet werden. Ganz große Klasse. Ich bewundere den Mut, den manch Programmierer scheinbar aufbringt und Software entwickelt, die immer zu 100% funktionieren. Aber bitte, gebt euer erstklassiges Fachwissen nicht an noch Lernende und wissbegierige weiter. Sie könnten auf die Idee kommen, eure hochqualifizierte Programmierung zu übernehmen. Ist ja auch völlig langweilig, in einem Programm einen Ablauf abzuarbeiten und auf Ereignisse in der Schleife zu reagieren. Hab da auch ein kleines einfaches Beispiel: Um einen Zeitstempel im ms Bereich zu erfassen macht ein Interrupt Sinn. Es wird die Zeit erfasst und gespeichert und ein Flag gesetzt. Mehr braucht es nicht in einer ISR. Die Programmschleife erfasst das Ereignisbit und ordnet den Zeitstempel in einer kleinen Soutine zu. Gruß oldmax

(Firma: 1984now) #8101661
Lesenswert?
• ▲
▼

Martin V. schrieb:

Mi N. schrieb:

Die Interruptroutine erledigt alles und ist daher sehr lang.

Macht unglaublich viel Sinn. Da dürfen Tastersignale (langes Signal) und Lichtblitze auf Fotozellen (wahnsinnig schnelles Signal) gleichberechtigt sicher erfasst und auch zugeordnet werden.

Wer spricht denn von "Gleichberechtigung"? Neuere AVR8 bieten Interruptpriorisierung in Hardware (wobei das auch schon etliche ältere können, nämlich die XMega, von denen die neueren halt wesentliche Teile der Architektur geerbt haben), bei älteren kann man sie in Software bauen. In beiden Fällen ergeben sich letztlich durch Interrupts unterbrechbare ISRs.

Man muss es bloß richtig machen und ist dann tatsächlich schnell bei einem Programm, dessen Hauptschleife nur noch aus dem Mechanismus zum Einschlafen besteht.

Ja, man muss natürlich ein grundlegendes Verständnis für (quasi-)parallele Programmabläufe haben und auch für die dafür meist nötigen Synchronisierungsmechanismen. Die sind tatsächlich bei solch einer reinen Interrupt-Architektur deutlich anspruchsvoller als z.B. bei Multi-Threading, wie man es von neuzeitlichen OS kennt. Das liegt daran, dass "Warten" in ISRs natürlich ziemlich tödlich ist. Das sollte am besten gar nicht, maximal aber bei einer ISR der niedrigsten Priorität verwendet werden und das auch nur dann, wenn sie die einzige mit dieser Priorität ist.

So eine Interruptarchitektur kann also durchaus zuverlässig laufen. Wenn man es richtig macht. Der Vorteil ist, dass es damit relativ einfach ist, Echtzeitanforderungen umzusetzen. Genau dafür sind Interrupts nämlich auch gedacht.

Der Nachteil ist, dass der Gesamtdurchsatz geringer ist, als wenn nur in der Hauptschleife gepollt würde. Die Interrupts haben halt zwingend einen Overhead, der von der nutzbaren Rechenzeit abgeht.

Fazit: es geht beides und es gehen auch Mischformen. Was am sinnvollsten ist, hängt von der konkreten Anwendung ab. Man muß einfach wissen, was man tut.

#8101664
Lesenswert?
• ▲
▼

Ob S. schrieb:

deutlich anspruchsvoller als z.B. bei Multi-Threading,

hm... da hat man halt Semaphoren, aber auch dort muss man sich genau darum kümmern dass Daten und Zustände nach Rückkehr da sind - und das sich nichts ins Gehege kommt...

Ob S. schrieb:

eine Interruptarchitektur kann also durchaus zuverlässig laufen. Wenn man es richtig macht

Was läuft denn nicht unzuverlässig, wenn man es falsch macht? :-) oder Was läuft denn zuverlässig, wenn man es nicht richtig macht? :-)

Ob S. schrieb:

Man muß einfach wissen, was man tut.

Das ist auch beim Autofahren, Essen oder einer Nervenoperation so.

#8101850
Lesenswert?
• ▲
▼

Hi Ob S. schrieb im Beitrag #8101661:

So eine Interruptarchitektur kann also durchaus zuverlässig laufen. Wenn man es richtig macht. Der Vorteil ist, dass es damit relativ einfach ist, Echtzeitanforderungen umzusetzen. Genau dafür sind Interrupts nämlich auch gedacht.

Ich bin zwar schon über 70, aber lerne gern etwas dazu. Im Moment erschließt sich mir nicht der Sinn, warum ein Controller, der ein Hauptprogramm hat, welches mit einem einzigen Befehl, den Rücksprung, arbeitet und die Aufgabe aufgrund eines Interrupts erledigt eher auf Echtzeitanforderung reagiert wie ein Programm, welches in einer Programmschleife Ereignisse abarbeitet und ein Interrupt lediglich die erforderliche Echtzeitbedingung erfüllt und das zeitlich unwichtige der Hauptschleife lediglich mit einem Ereignisbit zur weiteren Bearbeitung signalisiert. Siehe das kleine Beispiel mit dem Zeitstempel. Die Zeit genau zu erfassen ist Aufgabe der ISR, Aufgabe, diese Zeit an andere Systeme zu senden dürfen gern ein paar ms später erfolgen. Gruß oldmax

#8101890
Lesenswert?
• ▲
▼

Noch einmal zurück:
Die TWI-Routine und Timer-Interrupt zum Tastenabfrage Polling kommen sich in die Quere. So dass das Programm nicht funktioniert.
KI schlägt Flag-Lösung vor. Und die sieht zwar recht komisch aus, bringt das Programm aber zum Laufen. Und das war ja erst einmal ein Lösungsansatz. Kommt auch darauf an, in welcher Zeit die ISR abgearbeitet wird.
Von Pauschallösung eben entfernt. Evtl. muss sogar noch ein Watchdog mit gezielt gesetzen WDRs vorgesehen werden.

ciao
gustav

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren