Forum: Mikrocontroller und Digitale Elektronik Interrupt beim STM32 F103


von Thomas G. (Firma: Frickelhauptquartier) (taximan)


Lesenswert?

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.

von Chris K (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Du wirst irgendetwas wie attachInterrupt(PB1,buttonPressed,BOTH_EDGES) 
machen muessen und im Interrupt die beiden Faelle getrennt behandeln 
muessen.

von W.S. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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

von Johannes S. (Gast)


Lesenswert?

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.

von immer das Gleiche (Gast)


Lesenswert?

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)

von Johannes S. (Gast)


Lesenswert?

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. 
:)

von immer das Gleiche (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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

von immer das Gleiche (Gast)


Lesenswert?

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 ...

von Johannes S. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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?

von immer das Gleiche (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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?

von W.S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Schwanzus Kurzus (Gast)


Lesenswert?

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.

von Schwanzus Kurzus (Gast)


Lesenswert?

O.K., hat sich gerade geklärt.

von Peter D. (peda)


Lesenswert?

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
von W.S. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Johannes S. schrieb:
> Und was er tun soll habe ich ja schon in queue.call() gesagt.

Und das sieht dann wie aus?

von W.S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Thomas G. (Firma: Frickelhauptquartier) (taximan)


Lesenswert?

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?

von Johannes S. (Gast)


Lesenswert?

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 :)

von Thomas G. (Firma: Frickelhauptquartier) (taximan)


Lesenswert?

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

von dummschwaetzer (Gast)


Lesenswert?

cube mx?

von Stefan F. (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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?

von Johannes S. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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?

von W.S. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von .. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von .. (Gast)


Lesenswert?

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!

von Thomas G. (Firma: Frickelhauptquartier) (taximan)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Johannes S. (Gast)


Lesenswert?

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.

von Jimi H. (jimih)


Lesenswert?

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
von W.S. (Gast)


Lesenswert?

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.

von Jimi H. (jimih)


Lesenswert?

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
Noch kein Account? Hier anmelden.