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.
Du wirst irgendetwas wie attachInterrupt(PB1,buttonPressed,BOTH_EDGES) machen muessen und im Interrupt die beiden Faelle getrennt behandeln muessen.
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.
W.S. schrieb: > also dürfen wir hier davon ausgehen, daß > die ISR (und zwar ALLE ISR) ab Programmierung des Chips festgelegt sind Die Vektortabelle kann man ins RAM kopieren und dann von dort aus nutzen. Das wird hier allerdings soweit ich weiß nicht genutzt. Bei Arduino besteht die ISR aus einem Stück Arduino code welcher auf die genannte Funktion verzweigt. Siehe https://github.com/stm32duino/Arduino_Core_STM32/blob/01a1aa3ff3c1eb768389fb0b3f4b97b154e63c99/libraries/SrcWrapper/src/stm32/interrupt.cpp Zeile 186
Thomas G. schrieb: > attachInterrupt(PB1,buttonPressed,FALLING); soll ersetzt werden durch: > attachInterrupt(PB1,buttonPressed2,FALLING) gleicher PB, gleiche Flanke, andere Funktion. Das geht mit attach weil dann einfach der Funktionszeiger neu gesetzt wird. Es gibt auch eine Doku zu den Funktionen, das der Zeiger überschrieben wird steht leider nur in älterer. Die ISR ist nur ein Sprungverlängerer auf den gesetzten Funktionszeiger und fertig. Arduino nagelt das statisch fest und reserviert die ISR damit für sich. Es gibt viele Arduino Cores und theoretisch könnten die sich unterschiedlich verhalten. Für STM32 dürfte der STM32DUINO aber der meistgenutzte sein und da ist es so. https://github.com/stm32duino/Arduino_Core_STM32/blob/6dec3b655fda17ba0f33cf12cef16b64d0333abd/cores/arduino/WInterrupts.cpp#L64-L73 https://github.com/stm32duino/Arduino_Core_STM32/blob/01a1aa3ff3c1eb768389fb0b3f4b97b154e63c99/libraries/SrcWrapper/src/stm32/interrupt.cpp#L186 https://github.com/stm32duino/Arduino_Core_STM32/blob/01a1aa3ff3c1eb768389fb0b3f4b97b154e63c99/libraries/SrcWrapper/src/stm32/interrupt.cpp#L239 alles kein Hexenwerk und nicht nötig zu philosophieren.
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. :)
Johannes S. schrieb: > Aber sicher gibt es OS die das eleganter lösen, ratet > mal welches z.B. :) Man braucht kein OS, das weisst du selber.
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:
1 | menu1() |
2 | {
|
3 | if (get_key_press(mSOFTKEY_1)) |
4 | mache_was(); |
5 | }
|
6 | menu2() |
7 | {
|
8 | if (get_key_press(mSOFTKEY_1)) |
9 | mache_was_anderes(); |
10 | }
|
Oder auch
1 | menu3() |
2 | {
|
3 | if (get_key_short(mSOFTKEY_1)) |
4 | mache_dies(); |
5 | if (get_key_long(mSOFTKEY_1)) |
6 | mache_das(); |
7 | }
|
Oder
1 | menu() |
2 | {
|
3 | if (get_key_press(mSOFTKEY_1)) |
4 | switch ( state ) |
5 | {
|
6 | case MENU1: mache_was(); break; |
7 | case MENU2: mache_dies(); break; |
8 | case MENU3: mache_das(); break; |
9 | }
|
10 | }
|
Der Flexibilität sind da keine Grenzen gesetzt.
:
Bearbeitet durch User
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:
1 | if (Event_Available()) |
2 | { CurrEvent = Get_Event(); |
3 | switch (CurrEvent) |
4 | { case Taster_Event: Werte_Taster_Ereignis_aus(); break; |
5 | case ... |
6 | ...usw. |
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.
W.S. schrieb: > Das sieht dann so etwa so aus: und ich schreibe
1 | event_queue.call(do_something()); |
und erspare mir elend lange dispatcher.
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: > Und was er tun soll habe ich ja schon in queue.call() gesagt. Und das sieht dann wie aus?
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 :)
Johannes S. schrieb: > Thomas G. schrieb: > > Und auch sorry für die OT Diskussionen :) Danke, man lernt auch nie aus, irgendwas bleibt immer hängen
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.