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.
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.
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.
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...
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
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
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.
Merkwürdiger Ansatz! Warum pollst Du nicht einfach das Interrupt-Flag durch main()?
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)
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.
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.
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.
Nö, pragmatisch.
Du hast verstanden, dass es keine generellen Regeln für so etwas gibt. Dass man vielmehr die Software an die jeweilige Aufgabenstellung anpassen muss.
Da wundert man sich dann auch nicht, wenn ein AVR Sourcecode in 9615,385 Zeitschleifen pro Sekunde läuft. Einfach weil's zur Aufgabe passt.
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
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.
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...
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
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.