Moin,
ich habe im SETUP eines Sketches einen IRQ definiert:
'attachInterrupt(PB1,buttonPressed,FALLING); '
dieses funktioniert in der LOOP soweit problemlos; die Routine
'buttonPressed' wird angesprungen, alles gut.
Jetzt brauche ich aber eine andere Routine für einen IRQ an diesem Pin.
Ich dachte mir: 'detachInterrupt(PB1);' in der 1. IRQ-Routine und später
in einer anderen Funktion 'attachInterrupt(PB1,buttonPressed2,FALLING);
' definieren. Dieses scheint aber nicht zu funktionieren. Oder mache ich
etwas falsch? Meine Vermutung wäre, ich kann den IRQ einmal definieren
(im SETUP) und hinterher nur noch ändern.
Hmm ohne es genauer zu wissen. Ich könnte mir vorstellen, dass es ein
Problem ist den IRQ während eines Interrupt zu ändern. Hast du mal
versucht im IRQ nur ein Flag zu setzen und den Interrupt dann in der
Hauptroutine zu ändern?
Thomas G. schrieb:> Dieses scheint aber nicht zu funktionieren.
Das wird wohl eher an einem undurchdachten Programmablaufplan liegen.
Typisch bleibt ja ein Pin immer mit der gleichen Taste verbunden und die
Schaltung verdrahtet sich nicht auf magische Weise um. Es gibt also
keinen Grund, den Handler zu ändern. Abgesehen davon entprellt man
Taster einfacher und komfortabler mit einem Timerinterrupt.
es gibt auch sowas wie bedingte Verzweigung in C/C++. Da kann man
abhängig von einer Bedingung mal das eine oder das andere ausführen,
auch in einer ISR.
Johannes S. schrieb:> es gibt auch sowas wie bedingte Verzweigung in C/C++. Da kann man> abhängig von einer Bedingung mal das eine oder das andere ausführen,> auch in einer ISR.
Kann man, macht aber den Ablauf extrem unübersichtlich und
fehleranfällig. Man muß bedenken, daß Interrupts immer asynchron zum
Main ablaufen.
Man läßt den Interrupt daher besser nur die Low-Level Aktionen
ausführen, z.B. Erkennen der Flanke, Taste wurde gedrückt.
In der Mainloop kann man dann bequem die Funktion zum Auswerten des
gedrückt-Flags in beliebigen Menüpunkten aufrufen.
Peter D. schrieb:> Kann man,...
Vergebliche Liebesmüh...
Ach Peter, bedenke mal, daß der TO hier überhaupt nichts mit den
eigentlichen ISR zu tun hat, sondern mit irgendwelchen
Bibliotheksfunktionen, die er mittels
1
attachInterrupt(PB1,buttonPressed,FALLING);
in irgend eine bibliotheksinterne Liste eintragen läßt. Insofern sind
alle Überlegungen zum eigentlichen Interrupt-Geschehen an dieser Stelle
zwecklos, stattdessen müßte der TO eher in die (hoffentlich
vorliegenden) Quellen der entspr. Bibliothek schauen, um herauszufinden,
was wie geht bzw. was eben nicht geht.
W.S.
W.S. schrieb:> in irgend eine bibliotheksinterne Liste eintragen läßt
es gibt keine Listen, dann müsste detachInterrupt() ja auch eine
Funktion als Argument haben um diese wieder zu entfernen.
Der letzte gewinnt, ein erneutes attachInterrupt überschreibt die
vorherige Funktion. Gefährlich und unnötig ist detach in der ISR selber.
Johannes S. schrieb:> es gibt keine Listen...
Also dann mal etwas Grundsätzliches zur Cortex-M Struktur:
Es gibt eine Vektortafel im Flash bzw. ROM ab Adresse 0, wo nicht nur
die Startadresse des Kaltstartprogramms und der Initialwert für den
Stackpointer drinsteht, sondern auch all die Adressen von diversen
Exceptions und von den Interrupt-Service-Routinen. Das alles steht im
Flash bzw. im ROM. Nun kann man zwar bei Cortex-M so ab M3 (wimre) die
Vektortafel verlegen, aber so etwas hat der TO mit hoher
Wahrscheinlichkeit nicht getan, also dürfen wir hier davon ausgehen, daß
die ISR (und zwar ALLE ISR) ab Programmierung des Chips festgelegt sind
und Funktionen a la "attachInterrupt(...);" eine reine
Software-Angelegenheit sind, die mit entsprechender Funktionalität
innerhalb von mitgelieferten Bibliotheken realisiert sind. Ob nun Listen
oder jeweils einzelne Pointer im RAM dort zum Merken der ladbaren
Prozeduren benutzt werden, ist mir im Moment egal - der TO müßte dazu in
die Bibliotheken schauen, um sich zu informieren.
Jede Erklärung zum eigentlichen Interrupt-Geschehen würde ein davon
verschiedenes Thema behandeln, was hier jedoch wenig Sinn ergibt.
W.S.
Johannes S. schrieb:> Arduino nagelt das statisch fest und reserviert die ISR> damit für sich.
Und die Moral von der Geschicht: Verwend' das Arduino Framework nicht.
(sondern: man lerne anständig Programmieren)
immer das Gleiche schrieb:> Verwend' das Arduino Framework nicht.
nee, Doku lesen und Code von github lesen.
Aber sicher gibt es OS die das eleganter lösen, ratet mal welches z.B.
:)
brauchen nicht, aber wenn man es verstanden hat, dann macht es das Leben
angenehmer.
aber auch der Arduino Core unterstützt so einige Boards, man schaue sich
mal an wieviele grüne Herzchen da stehen und die alle mit dem gleichen
Code laufen, ohne sich um die verschiedenen Vektortafeln kümmern zu
müssen:
https://github.com/stm32duino/Arduino_Core_STM32
Johannes S. schrieb:> aber auch der Arduino Core unterstützt so einige Boards
Ich habe so einige Ansätze verfolgt AVRs unter dem Arduino-
Framework zu programmieren und habe jedes Mal mit der
Erkenntnis aufgeben müssen dass das was ich machen wollte
nur mit Kopfständen dort zu realisieren war. Dann lieber
gleich alles "from scratch" in normaler C-Programmierung.
Das Schlimmste was ich immer wieder fand ist die
Funkionalität der Serial-Klasse und die Print-Implementierung.
Aber wenn man sieht wie hier die Leute aufschlagen und über
die Schikanen des Frameworks stolpern gibt es sicher genug
andere Beispiele ... Timer0 zum Beispiel ...
immer das Gleiche schrieb:> Serial-Klasse und die Print
jetzt wird es OT, aber diese Klassen sind ja da um sich den Overhead
eines printf() zu sparen. Das kann man aber durchaus verwenden wenn man
genügend Speicher hat oder das OS selber abgespeckte printf Varianten
anbietet. Auch andere C/C++ Funktionen/Librarys kann man unter Arduino
verwenden.
Timer und andere HW Resourcen werden nicht alle von Arduino oder anderen
OS abgedeckt, dafür gibt es zuviel verschiedene Hardware. Aber dafür
gibt es für Arduino zumindest für das allermeiste wiederum Libs. Wie gut
die sind ist natürlich eine andere Frage. Aber auch da hilft es eben
Doku und Code zu lesen.
immer das Gleiche schrieb:> Und die Moral von der Geschicht: Verwend' das Arduino Framework nicht.
Ich frage mich, ob du die Sachlage verstanden hast. Im Gegensatz zu den
Einschränkungen die sich aus dem Prinzip "Programm im ROM" ergeben,
setzt das Arduino Framework eine HW unabhängige Lösung oben drauf, mit
der man Interrupt-Handler zur Laufzeit flexibel den Interrupts zuweisen
kann.
Was ist daran so schlecht, dass du zu deiner "Moral" kommst?
Stefan ⛄ F. schrieb:> mit der man Interrupt-Handler zur Laufzeit flexibel den> Interrupts zuweisen kann.
So so, du meinst also das kann man nur mit dem Arduino Framework
machen. Das würde ich als Verdummung des nicht so fachkundigen
Publikums bezeichnen.
immer das Gleiche schrieb:> So so, du meinst also das kann man nur mit dem Arduino Framework> machen.
Nein, das habe ich weder gemeint noch geschrieben. Ich habe nicht
ausgeschlossen, dass andere Frameworks ähnliches anbieten.
Daher wiederhole ich nochmal meine unbeantwortete Frage: Warum hat diese
Funktion von Arduino dazu geführt, dass du von Arduino abgeraten hast?
Stefan ⛄ F. schrieb:> Daher wiederhole ich nochmal meine unbeantwortete Frage: Warum hat diese> Funktion von Arduino dazu geführt, dass du von Arduino abgeraten hast?
Du scheinst der König der Wiederholungen zu sein, mein Lieber. Bereits
weiter oben hast du mich wiederholt um auch irgendwas zum Thread
beizutragen.
Aber mal zu deiner jetzigen Wiederholung:
Normalerweise werden die Pin-Funktionen ganz am Anfang eingerichtet,
weil sie eben ein Teil des Systementwurfes sind, der vor dem Schreiben
der Quellen bereits erfolgte. Dazu gehört auch das Einrichten der
Interrupt-Behandlung, die eben ein Teil des Aufsetzens der ganzen
Low-Level-Funktionalität sind. So etwas wird nicht in main()
abgehandelt.
Folglich steht der zuständige Interrupt-Handler bereits beim Übersetzen
der Firmware fest. Neulinge kennen so etwas oft genug nicht und
versuchen zunächst, sowas in der Reihenfolge zu machen, wie es ihnen
gerade in den Sinn kommt. Und da scheint es mir, daß selbiges planloses
Vorgehen von solchen Produkten wie Arduino befördert wird, anstatt daß
die Anfänger auf einen besseren Weg gebracht werden.
Darum ist Arduino zwar gut, um fertig vorgekaute Dinge selbst auch auf
die schnelle Art hinzukriegen, aber man gewöhnt sich oft genug einen
schlimmen Stil an oder verwechselt die Dinge. Siehe die Ansicht, daß man
eine Callback-Funktion für eine ISR hält usw.
W.S.
W.S. schrieb:> Normalerweise werden die Pin-Funktionen ganz am Anfang eingerichtet,
kann man so machen, ist aber kein Gesetz.
Bei den Cortex-M wird ja meist das weak Binding benutzt, was selber
blöde Fehlermöglichkeiten bietet.
Die ISR zur Laufzeit zu Setzen hat Vorteile z.B. bei
Komponentenbasierter Software. Ich kann eine 'Pushbutton' Klasse bauen
und die braucht nur den Pin für den Button + evtl. die Callbacks für die
Funktion die ausgelöst werden soll oder man setzt virtuelle Funktionen
ein. Wenn das Interruptbasiert arbeiten soll, dann kann diese Komponente
selber auch die nötige ISR mitbringen. NVIC_SetVector() unterstützt das,
das ist Teil der CMSIS, aber Arduino hat ja mit AVR angefangen und
musste das anders lösen.
So ist alles in einer Komponente und nicht an x Stellen im Code
verstreut, bei C++ ist dazu mit einer Zeile Instanz erzeugen alles
erledigt. Das kann auch global erfolgen, dann ist das vor main() aktiv.
Die ISR zur Compilezeit zu setzen, hat den entscheidenden Vorteil, daß
man erst gar nicht auf bescheuerte Ideen kommt, zur Laufzeit Interrupts
in den Wald zeigen zu lassen, Interrupts zu verlieren oder sich durch
Callbacks den Mainkontext zerschießen zu lassen. Wer externe Interrupts
für beliebige Arten mechanischer Signale nimmt, der hat den Schuß noch
nicht gehört.
Externe Signale möchte man nur an ganz bestimmten Stellen im Kontext
auswerten und nicht asynchron, z.B. mittendrin eine Displayausgabe
zerschießen.
Nebenbei muß der Compiler nicht unnütz alle Scratch-Register sichern,
sondern nur die vom Interrupt benutzten. Das kann durchaus merkbare
Laufzeitvorteile bewirken.
Ich konnte auch nirgends eine gescheite Doku finden, was detachInterrupt
und attachInterrupt genau machen. Was passiert z.B. mit bereits
gesetzten Pending-Flags, werden die unter den Tisch gekehrt oder wie.
Statt einer Blackbox, will ich selber ganz genau bestimmen, wie etwas
ablaufen soll. Gerade bei Interrupts kommt es oft auf die genaue
Reihenfolge an. Ein falscher Interrupt ist ebenso störend, wie ein
verlorener.
Peter D. schrieb:> Das wird wohl eher an einem undurchdachten Programmablaufplan liegen.> Typisch bleibt ja ein Pin immer mit der gleichen Taste verbunden und die> Schaltung verdrahtet sich nicht auf magische Weise um.
Wie lôst man denn Folgendes am Besten: Hardwaretaster hat je nach
Betriebszustand eine andere Funktion (Softkey). Ich hätte jetzt spontan
auch einfach versucht, die Callbackfunktion in der ISR zu ändern.
Schwanzus Kurzus schrieb:> Wie lôst man denn Folgendes am Besten: Hardwaretaster hat je nach> Betriebszustand eine andere Funktion (Softkey).
Ganz einfach:
Johannes S. schrieb:> Bei den Cortex-M wird ja meist das weak Binding benutzt, was selber> blöde Fehlermöglichkeiten bietet.
Da hast du das Prinzip dahinter noch nicht verstanden. Normalerweise muß
eine Tafel mit Prozeduradressen im ROM/Flash wenigstens vom Linker
komplett besetzt werden, folglich müssen zur Linkzeit alle Adressen
bekannt sein. Da nun aber nicht erwartet wird, daß ein
Firmware-Programmierer alle Interrupts und Exceptions benutzt, werden
die Adressen in der Tafel zunächst erst einmal mit Platzhaltern (mit
"WEAK" gekenzeichnete Default-Prozeduren) gefüllt. Diese Adressen werden
dann beim Linken mit den Adressen der echten ISR überschrieben - aber
nur die jenigen, wo der Programmierer echte ISR (exakt gleichnamige!)
geschrieben hat. Alle anderen Default-Adressen bleiben so wie sie in der
Tafel stehen.
Kurz gesagt: Das Ganze ist eine Linker-Angelegenheit und wird nicht nur
"meist", sonden gezwungenermaßen immer benutzt. Und es bietet nur dann
Fehlermöglichkeiten, wenn man das Ganze noicht versteht und den Zweck
nicht begriffen hat. Sonst nicht.
Nach neiner Meinung hätte das Ganze niemals Eingang in den
Sprachgebrauch von C finden dürfen, sondern hätte im Assembler-Niveau
bleiben müssen - aber da gibt es einige sich besonders schlau dünkende
Leute, die sogar noch stolz darauf sind, daß man den Startup-Code beim
GCC auch in C verfassen kann. Nach meiner Ansicht eine geradezu
grandiose Dümmlichkeit, derartige LL-Dinge in die Gefilde einer
eigentlich maschinenunabhängig sein sollenden Programmiesprache zu
verschieben.
W.S.
Peter D. schrieb:> Ganz einfach:
Ich betreibe an so einer Stelle die Firmware ereignisgesteuert. Das
sieht dann so aus, daß eine ISR (oder irgend eine andere Stelle in der
Firmware) ein "Ereignis" (d.h. eine Kennzahl) in einen "Ereignis"-Fifo
schreibt, von wo selbiges bei passender Gelegenheit von der
Grundschleife in main() gelesen und behandelt werden kann.
Das sieht dann so etwa so aus:
Die Unterscheidung zwischen dem, was auf den ersten Tastendruck gemacht
werden soll und dem was auf den nächsten Tastendruck gemacht werden
soll, wird in dem Programmteil "Werte_Taster_Ereignis_aus()" gemacht.
Schließlich hat das mit dem eigentlichen Ereignis "Taster wurde
gedrückt" nichts zu tun.
W.S.
W.S. schrieb:> Da hast du das Prinzip dahinter noch nicht verstanden.
doch, habe ich. Weak hat ein Problem wenn man in einer C++ unit das
'extern "C' vergisst, dann hat die ISR durch das C++ name mangeling
nicht den Namen der im Quelltext steht. Der Linker kann keinen Fehler
melden weil das ja ein x-beliebiges anderes Symbol für ihn ist. Dieser
Fehler ist hier schon einigen passiert. Mir auch.
Dann kann das Symbol mehrfach definiert sein, hier bin ich mir nicht
sicher ob es einen Linkerfehler/warnung gibt.
Johannes S. schrieb:> und erspare mir elend lange dispatcher
Naja, irgendwo muß irgendwer so ein Ereignis auswerten und je nachdem,
welches es war, zu verschiedenen Aktionen bzw. Prozeduren verzweigen.
Und wenn du sowas nicht dort hast, wo es bei mir steht, dann muß das bei
dir eben woanders stehen. Aber irgenwo stehen muß es immer - und zuvor
hingeschrieben sein.
W.S.
Johannes S. schrieb:> Weak hat ein Problem wenn man in einer C++ unit das> 'extern "C' vergisst, dann hat die ISR durch das C++ name mangeling> nicht den Namen der im Quelltext steht.
Tja, wenn man halt C++ verwenden will, dann muß man das eben auch
beachten. Ob man sich damit so insgesamt das Schreiben der Firmware nun
leichter macht oder eher nicht, ist diskutabel. Ich finde, daß C++ bei
Mikrocontrollern insgesamt gesehen nicht wirklich besser ist als blankes
C.
W.S.
W.S. schrieb:> Naja, irgendwo muß irgendwer so ein Ereignis auswerten und je nachdem,> welches es war, zu verschiedenen Aktionen bzw. Prozeduren verzweigen.
Nö, mein dispatcher macht:
[/c]
event_queue.dispatch_forever();
[/c]
Und was er tun soll habe ich ja schon in queue.call() gesagt.
Johannes S. schrieb:> Nö, mein dispatcher macht:> [/c]> event_queue.dispatch_forever();> [/c]> Und was er tun soll habe ich ja schon in queue.call() gesagt.
Nö. Haste nicht. Du hast lediglich eine Methode ohne Parameter
aufgerufen.
Also:
Der Sinn von ereignisgesteuerter Programmierung besteht darin, daß die
Firmware (bzw. ganz allgemein das Programm) verschiedene Nachrichten
bekommen kann und folglich darauf auch je nach Botschaft verschieden
reagiert - und manchmal unterschiedlich auf 2x dieselbe Botschaft, siehe
Licht an und wieder aus bei zweimaligem Drücken derselben Taste. Dazu
muß die Firmware unterscheiden können, was da grad an Botschaft
hereingetrudelt ist. Folglich braucht es irgendwo ein Stück Programm,
was diese Unterscheidungen tut und die jeweilige Reaktion veranlaßt. Mit
sowas wie "queue.call()" ist es nicht im Mindesten getan.
W.S.
W.S. schrieb:> Johannes S. schrieb:>> Weak hat ein Problem wenn man in einer C++ unit das>> 'extern "C' vergisst, dann hat die ISR durch das C++ name mangeling>> nicht den Namen der im Quelltext steht.>> Tja, wenn man halt C++ verwenden will, dann muß man das eben auch> beachten.
das Problem hat man bei C auch, einfach mal einen Buchstaben des ISR
Namen falsch schreiben, Groß/Klein verwechselt, eine ISR von ähnlichem
µC kopiert der aber einen anderen Namen für diese ISR hat. Keiner
meckert, weder Compiler, noch Linker.
W.S. schrieb:> Nö. Haste nicht. Du hast lediglich eine Methode ohne Parameter> aufgerufen.
ja, kompatibel zu deinem Beispiel mit
Werte_Taster_Ereignis_aus()
Also die Mbed Entwickler bei ARM haben definitiv was drauf, und C++
bietet schon einen Tick mehr.
1
// printf kann in die queue geworfen werden weil die Signatur (fn(), vargs) unterstützt wird
2
queue.call(printf,"rise_handler in context %p\n",ThisThread::get_id());
3
queue.call_every(1000ms,printf,"called every 1 seconds\n");
4
5
// Methode mit Argument in Q werfen
6
queue.call(&handler_cb,&EventHandler::handler,2);
mal so als funktionierende Beispiele. Das Event/EventQueue API ist lange
gewachsen und bietet noch einiges mehr, z.B. put/get mit Timeouts.
Einiges ist dynamisch, als Lösung gibt es noch statische
UserAllocatedEvent.
Kein einfacher Stoff, etwas mehr als nur eine Q mit Funktionen.
Und es ist kein Arduino Feature, ausser man nutzt den IoT core wie er
bei Portenta oder Nano 33 BLE verwendet wird. Da steckt dann auch Mbed
unter der Haube.
Hallo, ich danke euch für eure Antworten.
Fehlerursache war tatsächlich eine falsch gesetzte Klammer, jetzt läuft
es auch ohne IRQ.
Vermutlich OT:
Nachdem ich nun dabei bin, auch mal größere (nun ja) Programme zu
schreiben, fällt mir zunehmend auf, dass die Arduino-IDE doch irgendwann
mal unübersichtlich wird. Direkt Bitschieberei auf C-Ebene wollte ich
eigentlich vermeiden, auch wenn es sehr effektiv ist. Was können die
Fachleute da empfehlen?
Thomas G. schrieb:> as können die> Fachleute da empfehlen?
Bin kein Arduino Fachmann, aber:
https://www.arduino.cc/reference/de/
Unter 'Bits und Bytes' sind die Arduino Hilfsfunktionen fürs
Bitschubsen.
Arduino IDE 2.0 (Beta) ist schon besser als die alte, es gibt aber auch
VSCode + Arduino Extensions, PlatformIO und weitere Alternativen.
Und auch sorry für die OT Diskussionen :)
Thomas G. schrieb:> Direkt Bitschieberei auf C-Ebene wollte ich> eigentlich vermeiden, auch wenn es sehr effektiv ist. Was können die> Fachleute da empfehlen?
Ich empfehle Direkte Bitschieberei. Auf Mikrocontroller-Anwednungen
führt kein Weg drum herum. Natürlich kannst du dir gewisse Operationen
in Funktionen verpacken, aber das ändert nichts daran, dass du dich mit
einzelnen Bits befassen musst, weil das Ding halt mit einzelnen bits
funktioniert.
Ich habe hier eine Beschreibung, wie du Vidual Studio Code mit dem
Arduino Plugin verwenden kannst. Das ist zwar für den ESP8266 aber es
funktioniert mit dem STM32 prinzipiell gleich.
http://stefanfrings.de/esp8266/index.html#vscode
Johannes S. schrieb:> Also die Mbed Entwickler bei ARM haben definitiv was drauf, und C++> bietet schon einen Tick mehr.// printf kann in die queue geworfen werden> weil die Signatur (fn(), vargs) unterstützt wird> queue.call(printf, "rise_handler in context %p\n",> ThisThread::get_id());> queue.call_every(1000ms, printf, "called every 1 seconds\n");> // Methode mit Argument in Q werfen> queue.call(&handler_cb, &EventHandler::handler, 2);>> mal so als funktionierende Beispiele.
Das ist aber völlig am Thema vorbei. Ich sehe da nirgends was von
Tastenabfrage und auch nicht, wie auf eine Taste reagiert wird.
Hast Du versehentlich im falschen Thread gepostet?
Peter D. schrieb:> Das ist aber völlig am Thema vorbei.
Die Tastenabfrage war die Interruptauswertung durch attachInterrupt().
Da dies im Interruptkontext läuft, sollte der Code hier kurz sein und
hat Einschränkungen, das ist auch in der Arduino Doku ausführlich (durch
den weiterführenden Link) beschrieben.
In der Routine die am Interrupt hängt kann dann ein Event gefeuert
werden, darum ging es mittlerweile. Ardunio hat dafür nichts eingebaut,
ich habe gezeigt was andere OS können.
Johannes S. schrieb:> Ardunio hat dafür nichts eingebaut,> ich habe gezeigt was andere OS können.
Arduino ist kein OS, daher kann man es nicht mit einem OS vergleichen.
Arduino hat einige Libs eingebaut (z.B. Timerinterrupt mit ms Zählung,
Portzugriffe über Pinnummer), das wars aber auch schon.
Johannes S. schrieb:> queue.call(printf, "rise_handler in context %p\n",> ThisThread::get_id());
Deine OS-Beispiele sind nur dafür gut, um zu zeigen, daß man damit Code
schreiben kann, mit dem viele nichts anfangen können.
Was macht man damit auf einem MC, wohin geht das printf, warum und wann
erfolgt es?
Johannes S. schrieb:> Die Tastenabfrage war die Interruptauswertung durch attachInterrupt()
Grrppf...
Also, man tut sich selbst keinen Gefallen, wenn man Dinge verschiedener
Ebenen kreuz und quer durcheinander wirft. Die Tastenabfrage als solche
ist eine andere Ebene als das Auslösen einer Reaktion (schalte Licht aus
oder an). Das sollte man tunlichst auseinander halten, sonst verheddert
man sich irgendwann einmal im eigenen Quellcode.
Und dieses ominöse Attach_Interrupt() scheint mit etwas
Arduino-Spezifisches zu sein, wo die Erfinder es für zu kompliziert
erachteten, als daß man den anwendenden Hobby-Programmierern zumuten
könnte, das eigentliche Interrupt-Handling zu vestehen. Ich halte so
etwas hingegen für einen wesentlichen Teil dessen, was man zum Einsetzen
von Mikrocontrollern in eigene Projekte zuvor erlernen sollte.
Johannes S. schrieb:> ja, kompatibel zu deinem Beispiel mit> Werte_Taster_Ereignis_aus()
Nein, eben NICHT. Du hast ganz vergessen, daß bei dem von mir gezeigten
Quellcode-Schnipsel die Unterscheidung zwischen den verschiedenen
Botschaften bereits zuvor erfolgte, was du mit
Johannes S. schrieb:> und ich schreibe event_queue.call(do_something());> und erspare mir elend lange dispatcher.
abgetan hast. Also an welcher Stelle ist bei dir die Unterscheidung
zwischen den verschiedenen Botschaften?
Mal ganz ruhig erklärt: Die ganze Sache mit den von einer ISR
eingetragenen Events in eine Event-Warteschlange dient dazu, all die
Dinge, die in einer ISR nicht sofort behandelt werden müssen, in eine
entspanntere Umgebung zu transportieren. Hier eben die Grundschleife in
main(), wo das in aller Ruhe abgehandelt werden kann. Schließlich ist
das An- bzw. Ausschalten des Lichtes nicht wirklich zeitkritisch und
darf deswegen ein paar ms später erledigt werden.
Andere Aspekte ereignisgetriebener Programmierung will ich hier nicht
auswalzen, das würde zu weit führen.
Also, deine Ausführungen sind mir ein wenig konfus, weil du letztlich
jedesmal die eigentliche Arbeit des Auseinanderfuddelns verschiedener
Botschaften abtust bzw. heraushältst und das mit einem "und erspare mir
elend lange dispatcher" begründest. Aber irgendwo muß irgendwer diese
Arbeit erledigen. Da kommt man nicht drum herum.
W.S.
ich habe hier schon Mbed als Alternatie zu Arduino erwähnt, das läuft
auf dem F103 und ist für Bluepill oder Nucleo F103RB z.B. fertig
konfiguriert. Es ist komplexer/komplizierter, das gebe ich zu, aber
definitiv gut nutzbar z.B. über das CLI (Kommandozeilen interface) oder
Mbed Studio IDE. Und in einigen Arduinos ist es ja wie genannt auch drin
und das Mbed API steht afaik auch zur Verfügung.
Das printf war nur ein Beispiel dafür, das die Events auch Argumente
haben können, sogar ein printf mit variabler Argumentenliste (...).
Das printf in Mbed ist per default vorhanden, mittlerweile in einer
eigenen, reduzierten Form. Es leitet auf einen UART um, bei den Nucleos
z.B. auf den per USB verfügbaren. Das ist aber konfigurierbar und kann
auf andere UART umgeleitet werden.
Ausgeführt wird das im Q Dispatcher, der läuft im main wenn man keine
Threads verwendet, kann aber auch in Threads ausgelagert werden. Es sind
natürlich auch mehrere Qs möglich und damit verschiedene priorisierte
Aufgaben möglich.
Ich kann mal ein konkretes Musterprojekt bauen, im Moment versuche ich
nur das neue Buildsystem mit cmake zu verstehen.
Den Luxus in Arduino bekommt man durch externe Libs, für
Tastenauswertung z.B. OneButton. Das arbeitet mit Polling, da wären die
Interrupts nicht nötig. Ich kenne die elenden Diskussionen Int vs.
Polling hier... Trotzdem habe ich persönlich keine Angst vor Interrupts,
kommt halt drauf an. Mbed nutzt per default den sleep Mode der MCU, ein
wartender Dispatcher kann also im WFI verweilen und automatisch Strom
sparen.
W.S. schrieb:> Aber irgendwo muß irgendwer diese> Arbeit erledigen. Da kommt man nicht drum herum.
da haben sich die Antworten überschnitten. Wie geschrieben, für den oder
die Dispatcher bei mehreren Qs gibt es mehrere Möglichkeiten. Und ich
sehe schon, ohne konkreteres Beispiel kommt es nicht an.
Und ein q.call( buttonPressed(START) ); ist möglich und eine
buttonPressed(int) Funktion kann verschiedene Buttons verarbeiten. Dann
gibt es vielleicht Endschalter oder irgendws anderes, das kann mit
q.call( limitSwitch(X) ); als Funktion in die q geworfen werden. Der
dispatcher q.dispatch_forever(); wird dann entweder buttonPressed(START)
oder limitSwitch(X); aufrufen, ohne das ich ein switch-case in den
dispatcher einbauen muss. Das Event ist ja schon die Funktion.
W.S. redet sich wieder ahnungslos um Kopf und Kragen?
Dem jojos kann ich da einfach nur zustimmen.
Johannes S. schrieb:> Und ich sehe schon, ohne konkreteres Beispiel kommt es nicht an.
Bei W.S. kommt es auch konkret nicht an.
Du weist doch er will es nicht verstehen.
ich bin ja geduldig. Und die Events habe ich auch nicht sofort
verstanden, das ist mit C++ schon etwas magisch. Der Code für die
Callback Klasse ist hardcore...
Und glaubt mir, ich verstehe die Diskussion, ein bisschen
Programmiererfahrung habe ich, vor allem mit Dingern die 24*7 laufen
müssen.
W.S. schrieb:> Ich halte so etwas hingegen für einen wesentlichen Teil> dessen, was man zum Einsetzen von Mikrocontrollern in> eigene Projekte zuvor erlernen sollte.
Ich verstehe Arduino eher als Quick&Dirty Entwicklungsplattform, zum
ernsthaften Lernen benutzt man besser etwas anderes.
Stefan ⛄ F. schrieb:> Ich verstehe Arduino eher als Quick&Dirty Entwicklungsplattform
Nun ja, das ist eine Bewertung des Arduino, hat aber mit dem Kern dieser
inzwischen abgedrifteten Diskussion nur wenig gemeinsam.
Ich erinnere mich, daß Arduino damals angepriesen wurde als Software, um
das Verwenden von Mikrocontrollern durch Leute, die mit Elektronik nix
am Hut haben, zu ermöglichen. Das erklärt so einiges, ist hier aber
weniger interessant.
W.S.
W.S. schrieb:> Ich erinnere mich, daß Arduino damals angepriesen wurde als Software, um> das Verwenden von Mikrocontrollern durch Leute, die mit Elektronik nix> am Hut haben, zu ermöglichen.
Also perfekt für dich!
Stefan ⛄ F. schrieb:> Ich verstehe Arduino eher als Quick&Dirty Entwicklungsplattform, zum> ernsthaften Lernen benutzt man besser etwas anderes.
Ich denke mal, Arduino wurde zur Welt gebracht, um dem engagiertem
Jugendlichen einen möglichst reibungslosen Einstieg in die MC-Welt zu
ermöglichen.
pinMode (PC13,OUTPUT);
digitalWrite(PC13,HIGH);
a=digitalRead(PC13);
zum Beispiel ist doch irgendwie etwas offensichtlicher als irgendwelche,
zumindest Anfangs, kryptischen Register, die außerdem bei jedem Chip
mehr oder weniger unterschiedlich sind.
BTW: PlatformIO; bunter ist es schonmal. Morgen mal näher ansehen.
Thomas G. schrieb:> Ich denke mal, Arduino wurde zur Welt gebracht, um dem engagiertem> Jugendlichen einen möglichst reibungslosen Einstieg in die MC-Welt zu> ermöglichen.
Lernen tut man am ehesten, wenn man sich fordert oder wenn andere bzw.
die Aufgabe einen fordern.
Die Absicht, den Weg zu ebnen, um möglichst reibungslos für jemanden den
"Einstieg" zu gestalten, mag an sich nett gedacht und auch ehrenvoll
sein. Es läuft aber auf "Vorkauen" hinaus.
Jedoch hat diese Absicht - wenn ausgeführt - nicht die beabsichtigte
Wirkung. Sondern sie gaukelt einem noch völlig Unerfahrenen vor, daß das
gesamte Thema nur aus zuvor geebneten Wegen bestünde und sie führt zu
Gedankenlosigkeit anstelle Nachdenken und Lernen. Als Folge müssen wir
sehen, daß da Träume von Großartigkeit draus erwachsen, denn die
Schwierigkeiten der technischen Realisierung sehen die Unerfahrenen eben
nicht (weil ihnen bislang alles vorgekaut wurde) - und so wagen sie sich
an größere Projekte ohne ausreichende Fachkenntnisse und ohne
ausreichende Projekt-Planung und schlagen dann hier auf mit dem
Gegreine: "Ich will mit meinem Arduino eine Mondrakete bauen, wo finde
ich die Funktion für's Starten?"
---
Ich sag's mal polemisch: Wenn alle Menschen Engel wären, dann wäre der
theoretisch existierende Sozialismus der Himmel aud Erden. Aber die
Leute sind eher Bengel als Engel und der Himmel ist langweilig, da rein
statisch.
Oder anders gesagt: Gut gedacht ist zumeist das Gegenteil von gut
gemacht.
W.S.
W.S. schrieb:> "Ich will mit meinem Arduino eine Mondrakete bauen, wo finde> ich die Funktion für's Starten?"
Bis zu dem Punkt stimme ich dir zu.
Allerdings eignen sich solche leichten Einstiege durchaus dafür, erstes
Interesse zu wecken. Du kannst einem 12 jährigen nicht sagen "lerne
erstmal 2 Jahre Grundlagen, dann gebe ich dir eine LED".
Auch für das Programmieren begeistert sich heute vermutlich niemand
mehr, indem er Zahlenreihen auf den Bildschirm "zaubert", während sein
Smartphone in der Gesäß-Tasche eine Furz-Analyse erstellt und per
WhatsApp teilt.
Wer ernsthaftes Interesse an dem Thema hat, kommt schon von alleine von
den vorgekauten Modulen weg. Das war schon damals bei den Baukästen von
Philips so. Ein paar kräftige Selbstüberschätzungen gehören einfach
dazu.
Stefan ⛄ F. schrieb:> Du kannst einem 12 jährigen nicht sagen "lerne> erstmal 2 Jahre Grundlagen, dann gebe ich dir eine LED".
Ähem... Nun, ich hatte als junger Bub damals eine Handskizze und eine
Dopeltriode (war wohl wimre eine ECC91) in die Hand gedrückt bekommen
und bei allem weiteren war ich damals auf mich selbst gestellt. Punkt,
aber nicht auch Ende, sondern Anfang meiner Interessen. Sowas wie die
damals für Anfänger obligatorischen Fünfergruppen für's Morsen lernen
war mir nicht so interessant. Heutzutage geht das anders.
Und Bücher und Fachzeitschriften lesen. Damals war die Funkschau noch
eine recht praxisorientierte Zeitschrift, sowas scheint mir heutzutage
eher ausgestorben zu sein.
W.S.
W.S. schrieb:> Ähem... Nun, ich hatte als junger Bub damals eine Handskizze und eine> Dopeltriode (war wohl wimre eine ECC91) in die Hand gedrückt bekommen> und bei allem weiteren war ich damals auf mich selbst gestellt.
Das glaube ich dir. Ich habe auch noch so in der Art gelernt. Aber heute
lernt kaum noch jemand so. Keiner hat Bock, sich tagelang mit einem
Einzigen Bauteil zu befassen um am Ende in der Präsentation sagen zu
können "schaut, es leitet Strom". Das viel zu lagweilig. Was denkst du,
warum Twitter mit seinen kurzen Texten so erfolgreich geworden ist?
Die Zeiten ändern sich.
Stefan ⛄ F. schrieb:> Die Zeiten ändern sich.
es gibt auch verschiedene Lerntypen (von vier verschiedenen sprechen die
Psychologen), der eine liest ein Buch und versteht es, andere brauchen
trial and error. Sicher muss man irgendwann mal Doku lesen, aber wenn zu
viele Teile im Puzzle fehlen, dann hat man einfach kein Bild.
Ich versuche ja gerade die Doku von cmake zu verstehen, ich komme mir
wieder vor wie ein blutiger Anfänger. Insofern gebe ich dir Recht,
gerade in der IT wird jeden Monat eine neue Sau durchs Dorf getrieben.
Entscheidend ist daß man weiß wofür man lernt.
Man kann sich auch tagelang mit nur einem einzigen Bauteil befassen.
Aber für sein Projekt und sicher nicht nur für eine Präsentation. Wie es
überhaupt die Erfahrung braucht daß für Großes viele kleine Schritte
nötig sind. Umso größer dann die Genugtuung wenn es vollbracht ist.
Stefan ⛄ F. schrieb:> Das glaube ich dir. Ich habe auch noch so in der Art gelernt. Aber heute> lernt kaum noch jemand so. Keiner hat Bock, sich tagelang mit einem> Einzigen Bauteil zu befassen um am Ende in der Präsentation sagen zu> können...
Also für mich liest sich das wie "heutzutage hat keiner mehr Lust.
tatsächlich selber etwas zu lernen, sondern er fordert von anderen, ihm
die Arbeit zu machen". Nun, das mag sein, ich sehe das als Folge des
vorhandenen Wohlstandes, der die Leute letztlich korrumpiert.
Aber das müßte nicht sein, denn ein Leben im Wohlstand ist
erstrebenswert und zugleich keineswegs ein Hindernis für die
Lernwilligkeit oder mal poetisch ausgedrückt "die innere Flamme".
Es ist wohl eher der innere Schweinehund, der bei allen Leuten, die
eigentlich mental nicht dazu berufen sind, die Bequemlichkeit fördert,
so daß sie an allen Stellen auf jeden Einwurf kontern: "Man muß das Rad
nicht 2x erfinden" - was sich übesetzt in "wozu etwas selber können,
wenn es andere bereits gekonnt haben und man deren Ergebnisse kopieren
kann, ohne es zu verstehen".
W.S.
W.S. schrieb:> Man muß das Rad nicht 2x erfinden" - was sich übesetzt in "wozu etwas> selber können, wenn es andere bereits gekonnt haben und man deren> Ergebnisse kopieren kann, ohne es zu verstehen".
Die Spanne das zu beurteilen reicht von legitim und sinnvoll bis
strunzfaul und bequem. Was funktioniert muß man nicht verstehen.
Verständnis kostet Zeit- und diese Zeit ist möglicherweise an vielen
anderen Stellen im Leben sinnvoller investiert.