Anfängerfrage zu Arduino UNO mit Interrupt

Mein erstes "Projekt" - Arduino Uno mit RTC-Shield und interruptgesteuerter Ausgabe auf den seriellen Monitor.

Bezüglich Arduino bin ich Neuling. Ansonsten war ich ehemals Servicetechniker im Bereich Elektronik und EDV. Also habe schon ein bischen Ahnung.

Wozu Interrupt? Ganz einfach - der Arduino bleibt zwischen den einzelnen Augaben der Zeitaktualisierungen für andere Zwecke frei. Und die sind auch geplant. Aber vorab erst mal die Basis. Als Interruptgeber verwende ich den Squarewaveausgang des RTC. Dieser kann per Software aktiviert und auf 1 Hertz Frequenz programmiert werden. Es gibt also pro Sekunde einen Interrupt, welcher zur Auslösung der Aktualisierung der Anzeige verwendet wird. Später kommt ein Display dazu. Zur Schaltung: Als nötigen Pull-Up-Widerstand am SQW-Ausgang habe ich 2k2 genommen. Das SQW-Signal geht an den hier nicht bestückten Jumper-Pin der LED L1 und an den Datenpin 2 des Arduino.

Frage: In meinem Sketch habe ich die Zeitausgabe ausserhalb der Interruprbearbeitung in der Hauptschleife plaziert. Das geht einwandfrei. Gefällt mir aber nicht. Wenn ich nun die ganze Uhrabfrage und Ausgabe direkt in die Interruptroutine hänge, blockiert die Ausgabe nach ein paar Zeichen. Hier die Sketche. Der "ds1307.ino" geht, der "ds1307x" blockiert

http://www.gerud.de/Arduino/RTCx/Arduinoclock1.jpg
http://www.gerud.de/Arduino/RTCx/ds1307.ino
http://www.gerud.de/Arduino/RTCx/ds1307x.ino

ds1307.ino (1.98 KB)

ds1307x.ino (1.92 KB)

Halte ISRs schlank.

Stopfe nichts in ISRs, was selber Interrupts benötigt.
z.B.
Seriellgedöns
delay()
millis()
und vieles mehr.

Auch viele Libs arbeiten intern mit Interrupts und Verzögerungen.
z.B.
Wire (I2C)
usw.

der Arduino bleibt zwischen den einzelnen Augaben der Zeitaktualisierungen für andere Zwecke frei.

Das bleibt er, wenn du auf blockierenden Code verzichtest.
Dazu braucht es keine Interrupts.

Nichts gegen deinen RTC 1S Ticker, der kann Sinn machen.
Aber eben nicht überladen.

Nachtrag:
Warum hast du die IRQ Leitung auf 11 und 2 angeschlossen? eins von beiden sollte doch reichen!
Mit 11 machst du dir SPI kaputt.
Und du hast doch da einen SD Kartenslot.

Das delay(10); MUß aus der Interruptfunktion verschwinden!!
Es gibt keine Notwendigkeit einer Pause.
Grüße Uwe

Lupus52:
Frage: In meinem Sketch habe ich die Zeitausgabe ausserhalb der Interruprbearbeitung in der Hauptschleife plaziert. Das geht einwandfrei. Gefällt mir aber nicht.

Was gefällt dir nicht daran?

Wenn ich nun die ganze Uhrabfrage und Ausgabe direkt in die Interruptroutine hänge, blockiert die Ausgabe nach ein paar Zeichen. Hier die Sketche. Der "ds1307.ino" geht, der "ds1307x" blockiert

Das Blockieren liegt vermutlich an den delays.

Wozu Interrupt? Ganz einfach - der Arduino bleibt zwischen den einzelnen Augaben der Zeitaktualisierungen für andere Zwecke frei. Und die sind auch geplant. Aber vorab erst mal die Basis. Als Interruptgeber verwende ich den Squarewaveausgang des RTC. Dieser kann per Software aktiviert und auf 1 Hertz Frequenz programmiert werden. Es gibt also pro Sekunde einen Interrupt, welcher zur Auslösung der Aktualisierung der Anzeige verwendet wird. Später kommt ein Display dazu. Zur Schaltung: Als nötigen Pull-Up-Widerstand am SQW-Ausgang habe ich 2k2 genommen. Das SQW-Signal geht an den hier nicht bestückten Jumper-Pin der LED L1 und an den Datenpin 2 des Arduino.

Für die Anzeige der Uhr benötigt man normalerweise keinen Interrupt. Lass die Anzeige in der Loop und steuere andere Aufgaben evtl. durch den Interrupt.

Bei deiner Konstruktion sehe ich ein Problem, wenn der UNO eine Programmroutine außerhalb des Interrupt abarbeitet, (z.B. eine Motorsteuerung o.ä.) und der Interrupt zur Zeitanzeige wird alle Sekunden aktiv, fängt der Motor an zu stottern. Ich finde diese Lösung unpraktikabel.

Und so ganz nebenbei, :wink: du verwendest eine RTC die sehr ungenau ist. Die DS3132 ist deutlich genauer, da diese eine eingebaute Temperaturkompension hat. Bei der 1307 merkst du schon nach Stunden, dass diese um einige Sekunden falsch geht.

combie:
Halte ISRs schlank.

Stopfe nichts in ISRs, was selber Interrupts benötigt.
z.B.
Seriellgedöns
delay()
millis()
und vieles mehr.

Auch viele Libs arbeiten intern mit Interrupts und Verzögerungen.
z.B.
Wire (I2C)
usw.

....

Das bleibt er, wenn du auf blockierenden Code verzichtest.
Dazu braucht es keine Interrupts.

Das ist Ansichtssache. Ich arbeite bei so einem "Zeitticker" nicht gerne mit Zeitschleifen oder ähnlichem ungenauen Softwaregedöns wie interne Zähler auslesen und abfragen.

Nichts gegen deinen RTC 1S Ticker, der kann Sinn machen.
Aber eben nicht überladen.

Danke - ich hatte gedacht, dass die Firmware des Arduino sauber arbeitet und sich verschiedene(!) Interrupts nicht in die Quere kommen. Für mich als "Alter" Hardwareprogrammierauf Assemblerebene ist es absolut unlogssch, wenn sich die IR-Routinen in die Quere kommen. Das ist eine Frage der Prioritäten. Wenn es der Arduino nicht verträgt, dann mache ich es eben so, daß ich bei einem RTC-SQW-IRQ nur ein Flag setze und die Reaktion dann an anderer Stelle kommt. Geht ja - gefällt mir nur nicht so gut. Aber egal.

Nachtrag:
Warum hast du die IRQ Leitung auf 11 und 2 angeschlossen? eins von beiden sollte doch reichen!
Mit 11 machst du dir SPI kaputt.
Und du hast doch da einen SD Kartenslot.

Mir ist nicht bekannt wo und wie ich den IRQ an 11 angeschlossen haben soll.

uwefed:
Das delay(10); MUß aus der Interruptfunktion verschwinden!!
Es gibt keine Notwendigkeit einer Pause.
Grüße Uwe

Hallo, kanst du mir bitte erklären warum es dort verschwinden muss?

Es stimmt zwar, dass es momentan keine Notwendigkeit mehr gibt wenn ich die Behandlung des Interrupts (Zeitanzeige) so mache wie in dem funktionierenden Beispiel.

An früherer Stelle war das Delay mal nötig und der Code wurde eben so übernommen. Ich habe es jetzt rausgenommen.

Danke.

Hallo, kanst du mir bitte erklären warum es dort verschwinden muss?

Am Anfang deiner ISR werden die Interrupts global gesperrt.
Delay basiert auf Interrupts.
Wird also bei gesperrten Interrupts versagen!
Genau so wie Serial I2C usw...

Mir ist nicht bekannt wo und wie ich den IRQ an 11 angeschlossen haben soll.

Die obere gelbe Leitung geht von SQ zu Pin 11 und dann zu Pin 2.
Oder?

HotSystems:
Was gefällt dir nicht daran?

Ordnungssinn aus alten Assemblerzeiten

Das Blockieren liegt vermutlich an den delays.

Vermutlich nicht - denn die sind immer noch drin gewesen und es geht fehlerfrei wenn das Aufbereiten der Zeitausgabe ausserhalb der ISR liegt. Aber egal - das Delay ist nun weg, Es war ja nicht (mehr) nötig

Für die Anzeige der Uhr benötigt man normalerweise keinen Interrupt. Lass die Anzeige in der Loop und steuere andere Aufgaben evtl. durch den Interrupt.

Sorry, dass ich widerspreche. Gerade die laufende Anzeigeaktualisierung soll hier absolut zeitsynchron erfolgen und nicht irgendwann, wenn die Loop gerade mal Zeit hat. In Zukunft wird mit dem Takt per IRQ noch mehr ausgelöst. Und das mache ich nicht mit Zeitscheifen oder Zählern etc. Dazu nehme ich wie üblich einen Interrupt.

Bei deiner Konstruktion sehe ich ein Problem, wenn der UNO eine Programmroutine außerhalb des Interrupt abarbeitet, (z.B. eine Motorsteuerung o.ä.) und der Interrupt zur Zeitanzeige wird alle Sekunden aktiv, fängt der Motor an zu stottern. Ich finde diese Lösung unpraktikabel.

Bei meiner zukünftigen Aufgabensteuerung ist es eben gerade andersrum.

Und so ganz nebenbei, :wink: du verwendest eine RTC die sehr ungenau ist. Die DS3132 ist deutlich genauer, da diese eine eingebaute Temperaturkompension hat. Bei der 1307 merkst du schon nach Stunden, dass diese um einige Sekunden falsch geht.

Ich nehme eben das, was mir für meine Aufgabe von anderen Experten empfohlen wurde. Eben das verwendete RTC/SD-Shield. Da ich bezüglich Arduino absoluter Laie bin vertrau(t)e ich eben den entsprechenden Forentips.

Die absolute Genauigkeit spielt hier auch keine Rolle. In späterer Ausbaustufe läuft das Bord per NNTP-Sync. Die eingebaute "Uhr" soll nur Netz- oder Spannungsausfälle überbrücken.

Danke aber trotzdem für den Hinweis. Ich plane noch eine andere Uhrenvariante mit kleinerem separaten Bord. (Nur Uhr ohne SD-SLOT)

Vielleicht packe ich auch einen Heizwiderstand und einen Temperaturfühler auf die Uhr Dann kann sich der Ardu seinen Uhr selber heizen um sie stabil zu bekommen.

Ok...
Ich sehe schon...
Du magst unsere Vorschläge nicht.

Dann musst du wohl alleine durch das bittere Tal der Erfahrungen gehen.

Ich nehme eben das, was mir für meine Aufgabe von anderen Experten empfohlen wurde.

Super...

. Gerade die laufende Anzeigeaktualisierung soll hier absolut zeitsynchron erfolgen und nicht irgendwann, wenn die Loop gerade mal Zeit hat.

Soll eine Stubenfliege die Zeit lesen, oder ein Mensch?

combie:
Am Anfang deiner ISR werden die Interrupts global gesperrt.
Delay basiert auf Interrupts.
Wird also bei gesperrten Interrupts versagen!
Genau so wie Serial I2C usw...

Ok - das leuchtet soweit ein. D. h. Die Firmware blockiert automatisch alle anderen Interrupts während bzw. solange die dem IRQ zugewiesene Funktion ( hier "Takt" ) ausgeführt wird.

Die obere gelbe Leitung geht von SQ zu Pin 11 und dann zu Pin 2.
Oder?

Das täuscht wohl. Die gelbe lange Leitung geht vom SQ-Ausgang, wo auch der Pull-Up dran ist, nach rechts oben auf den mittleren PIN des 3er Jumperfelds vor den Datenpins. Von dort bordintern an die LED L1 links oben neben Reset und per 5mm "yellowwire" auch an Datenpin 2

OK, verlesen L1/11

D. h. Die Firmware blockiert automatisch alle anderen Interrupts

Nein, nicht die Firmware!
Die schreibst du selber.
Die Hardware tut das.
Das kann man auch im Datenblatt nachlesen.

combie:
Ok...
Ich sehe schon...
Du magst unsere Vorschläge nicht.

Dann musst du wohl alleine durch das bittere Tal der Erfahrungen gehen.
Super...

Soll eine Stubenfliege die Zeit lesen, oder ein Mensch?

Spar die bitte solche unqualifizierten Antworten!

Lupus52:
Vielleicht packe ich auch einen Heizwiderstand und einen Temperaturfühler auf die Uhr Dann kann sich der Ardu seinen Uhr selber heizen um sie stabil zu bekommen.

Dann viel Erfolg dabei.

Ich wundere mich allerdings darüber, wenn du eh schon alles weißt, warum du hier Fragen stellst und die Antworten dann in den Wind schlägst.

HotSystems:
Dann viel Erfolg dabei.

Ich wundere mich allerdings darüber, wenn du eh schon alles weißt, warum du hier Fragen stellst und die Antworten dann in den Wind schlägst.

Ich habe nie behauptet, dass ich alles weiß. Im Gegenteil - ich habe klipp und klar gesagt dass ich bezüglich Arduino ein Anfänger bin.

Ich habe auch keine Antworten in den Wind geschlagen! Im Gegenteil.

Was ich aber nicht leiden kann ist besserwisserisches, dummes und unqualifizierte s Geschwätz als Antworten auf sachliche Fragen.

Und dass ich andere Nutzungsvorstellungen habe als andere ist schlicht meine Sache. Das darf ich wohl noch sagen!?!

Oder dass ich eine andere RTC verwende als andere für gut befinden ist auch meine Sache. Ich habe mich für den Tip bezüglich des anderen möglichen besseren Chips bedankt. Aber ich brauche keine Luxusuhr wenn mir der normale Chip reicht.

Das ist keine Ablehnung eines Tips oder "in den Wind schlagen" wie du es nennst.

Also komm wieder runter und rede normal mit mir. Ohne unnötige Besserwisserei, Beschuldigungen oder Unterstellungen.

Bist Du sicher daß Du nach einer solchen Antwort noch Antworten von uns erwartest?

Grüße Uwe

Lupus52:
Für mich als "Alter" Hardwareprogrammierauf Assemblerebene ist es absolut unlogssch, wenn sich die IR-Routinen in die Quere kommen. Das ist eine Frage der Prioritäten.

Für Dich als "Alter" Hardwareprogrammierauf Assemblerebene mit sogar einer einschlägigen Fachausbildung ist es wahrscheinlich unter Deiner Würde, mal einen Blick ins Datenblatt des Atmega328 Controllers zu werfen. Es gibt bei keinem einzigen 8-bit Atmega-Controller Interrupt-Prioritäten, also auch beim Atmega328 nicht. Alle Interrupts haben dieselbe Priorität. Interrupts werden stets reihum abgearbeitet, immer ein Interrupt-Handler nach dem anderen. Und standardmäßig ist das Interrupthandler-Framework so aufgebaut, dass alle anderen Interrupts gesperrt sind, während ein anderer Interupthandler bereits läuft.

Lupus52:
Wenn es der Arduino nicht verträgt, dann mache ich es eben so, daß ich bei einem RTC-SQW-IRQ nur ein Flag setze und die Reaktion dann an anderer Stelle kommt. Geht ja - gefällt mir nur nicht so gut.

Aha, Du weißt also durchaus, wie man so eine Mikrocontroller-Plattform programmiert.
Aber das "gefällt Dir nicht so gut".

Wenn es Dir besser gefällt, völligen Schrott zusammen zu programmieren und auf den Controller zu laden: Dann mach mal!

Es gibt ja sowieso immer mindestens vier verschiedene Arten, auf die man etwas programmieren kann:

  • auf die richtige Art
  • auf die falsche Art
  • auf die übliche Art
  • und auf meine eigene Art
    Meistens gibt es sogar noch mehr Möglichkeiten, es auf andere Art zu programmieren.
    Und welche Art etwas zu programmieren die von Dir bevorzugte ist, entscheidest Du selbst.

Lupus52:
Also komm wieder runter und rede normal mit mir. Ohne unnötige Besserwisserei, Beschuldigungen oder Unterstellungen.

Wenn ich mir deine Beiträge nochmals in ruhe durchlese, stellt sich mir die Frage, wer hier wieder runter kommen sollte.

Vielen Dank.

Danke für die "freundlichen" Kommentare. Die haben einen immensen Wert für alle.

jurs:
Es gibt bei keinem einzigen 8-bit Atmega-Controller Interrupt-Prioritäten, also auch beim Atmega328 nicht. Alle Interrupts haben dieselbe Priorität. Interrupts werden stets reihum abgearbeitet, immer ein Interrupt-Handler nach dem anderen.

Das ist nicht richtig so.

A flexible interrupt module has its control registers in the I/O space with an additional Global Interrupt Enable bit
in the Status Register. All interrupts have a separate Interrupt Vector in the Interrupt Vector table. The interrupts
have priority in accordance with their Interrupt Vector position. The lower the Interrupt Vector address, the
higher the priority.

Ende 7.1 Seite 10 in meinem Datasheet.

jurs:
Alle Interrupts haben dieselbe Priorität.

Es gibt schon Prioritäten. Aber die sind in Hardware festgelegt. Anders als z.B. beim 805x kann man sie nicht in Software ändern. Wenn wirklich zwei Interrupts gleichzeitig auftreten wird der Vektor mit einer niedrigeren Adresse zuerst aufgerufen