Forum: Mikrocontroller und Digitale Elektronik Delay in Unterfunktion vermeiden


von Paul B. (paule201)


Lesenswert?

Hallo zusammen,

ich habe ein schnelles Hauptprogramm (durchlauf kleiner 5ms, passt für 
meinen Zweck). Ab und an rufe ich eine Funktion auf, die mir ein paar 
Daten per UART raushaut um ein Gerät fernzusteuern. Das Problem: Das 
Gerät ist langsam im verstehen, wenn ich zwei oder drei Befehle sende, 
muss dazwischen immer ein 500ms Delay.

Aktuell mach ich das so:
1
void PS_on(uint8_t status)
2
{
3
 EA_Init();
4
 HAL_Delay(500);
5
 EA_set_output(status);
6
}

Das ist natürlich doof für das Hauptprogramm, weil dann Eingaben liegen 
bleiben. Wie macht man sowas besser?
Die Funktion mit einer static variable versehen? Also alle 5ms aufrufen 
und den zweiten Teil im counter aufrufen? Was wenn ich mal 5 Befehle 
schicken will und 5 Delays ersetzen möchte? Das wird doch dann schnell 
unübersichtlich.
1
void PS_on(uint8_t status)
2
{
3
 EA_Init();
4
 static uint8_t count = 0;
5
 if(count == 100)
6
   {
7
   EA_set_output(status);
8
   count = 0;
9
   }
10
}

Danke!

Beitrag #7364923 wurde von einem Moderator gelöscht.
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Paul B. schrieb:
> Wie macht man sowas besser?
Nennt sich hochtrabend "Zustandsautomat".

In der Praxis heißt das: es gibt kein delay() im Programm. Die 
Hauptschleife wird schnellstmöglich durchlaufen und Zeiten werden durch 
Abfragen eines Timerticks (= ein ms-Zähler) und Berechnen von 
Zeitdifferenzen ausgewertet.

Etwa so:
1
int tiNow, tiLastset;
2
3
void main()
4
{
5
   EA_Init();
6
   for (;;) {  // Hauptschleife andauernd schnellstmöglich durchlaufen
7
      tiNow = get_timertick();
8
      if (tiNow-tiLastset > 500) {
9
         EA_set_output(status);
10
         tiLastset = tiNow;
11
      }
12
   }
13
}

Und dann ist es ganz einfach, noch 10 weitere Zeiten einzubauen:
1
int tiNow, tiLastset;
2
int tiL1, tiL2....
3
4
void main()
5
{
6
   EA_Init();
7
   for (;;) {  // Hauptschleife dauernd schnellstmöglich durchlaufen
8
      tiNow = get_timertick();
9
10
      if (tiNow-tiLastset > 500) {
11
         EA_set_output(status);
12
         tiLastset = tiNow;
13
      }
14
15
      if (tiNow-tiL1 > 333) {
16
         mach_was_alle_drittelsekunde();
17
         tiL1 = tiNow;
18
      }
19
20
      if (tiNow-tiL2 > ...) {
21
         ....();
22
         tiL2 = tiNow;
23
      }
24
25
   }
26
}

Und jetzt ist es ganz einfach, nboch weitere Funktionalität dazuzubauen: 
da kommt einfach ein weiterer if-Zweig dazu.
1
int tiNow, tiLastset;
2
int tiL1, tiL2....
3
4
void main()
5
{
6
   EA_Init();
7
   for (;;) {  // Hauptschleife dauernd schnellstmöglich durchlaufen
8
      tiNow = get_timertick();
9
10
      if (tiNow-tiLastset > 500) {
11
         EA_set_output(status);
12
         tiLastset = tiNow;
13
      }
14
15
      if (tiNow-tiL1 > 333) {
16
         mach_was_alle_drittelsekunde();
17
         tiL1 = tiNow;
18
      }
19
20
      if (tiNow-tiL2 > ...) {
21
         ....();
22
         tiL2 = tiNow;
23
      }
24
   
25
      if (eingang == aktiv) {
26
         reagiere_auf_eingang();
27
      }
28
29
      if (Zeichen_an_serieller_Schnittstelle_angekommen()) {
30
        zeichen = Hole_Zeichen_von_serieller_Schnittstelle_ab();
31
      }
32
      
33
      :
34
      :
35
      :
36
37
   }
38
}

: Bearbeitet durch Moderator
von MaWin O. (mawin_original)


Lesenswert?

Oder einfach eine vernünftige Programmiersprache verwenden, die 
asynchrone Programmierung beherrscht.

von Markus F. (mfro)


Lesenswert?

Fabian H. schrieb im Beitrag #7364923:
> Es gibt verschiedene Möglichkeiten, um dieses Problem zu lösen. Hier
> sind einige Vorschläge:

ChatGPT was here.

von Falk B. (falk)


Lesenswert?

Siehe Multitasking.

von Peter D. (peda)


Lesenswert?

Paul B. schrieb:
> Das Problem: Das
> Gerät ist langsam im verstehen, wenn ich zwei oder drei Befehle sende,
> muss dazwischen immer ein 500ms Delay.

Sowas gehört sich nicht. Derjenige, der das verzapft hat, muß ein 
blutiger Anfänger gewesen sein. Befehle werden direkt nach dem Empfang 
geparst. Benötigt die Befehlsausführung längere Zeit, dann kann der 
Master Statusabfragen senden, die mit "Busy" beantwortet werden.

Wie schon gesagt wurde, sendet man längere Sequenzen als 
Zustandsmaschine. Jeder Befehl ist dann ein Zustand. Die Befehle werden 
in den UART-FIFO gestellt, d.h. die Zustandsmaschine muß nicht bei jedem 
Byte warten.
Feste lange Wartezeiten kann man über einen Sheduler ablaufen lassen 
bzw. über einen durchlaufenden Timer. Sinnvoller ist allerdings, wenn 
der Slave abgefragt werden kann, ob er wieder bereit ist. Feste lange 
Wartezeiten sind immer nur eine Notlösung, wenn das Protokoll schon 
vergurkt ist.

von MaWin O. (mawin_original)


Lesenswert?

Peter D. schrieb:
>> Das Problem: Das
>> Gerät ist langsam im verstehen, wenn ich zwei oder drei Befehle sende,
>> muss dazwischen immer ein 500ms Delay.
>
> Sowas gehört sich nicht. Derjenige, der das verzapft hat, muß ein
> blutiger Anfänger gewesen sein.

Es wird dich vielleicht überraschen, aber es muss immer eine maximale 
Geschwindigkeit bzw minimale Periodendauer geben.
Ob die jetzt 500ms, 500µs oder 500ns ist, ist erst einmal unerheblich 
und sagt keineswegs etwas über die Erfahrung des Entwicklers aus.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

MaWin O. schrieb:
> aber es muss immer eine maximale Geschwindigkeit bzw minimale
> Periodendauer geben.
> Ob die jetzt 500ms, 500µs oder 500ns ist, ist erst einmal unerheblich
> und sagt keineswegs etwas über die Erfahrung des Entwicklers aus.
Aber wie der dann die diese Aufgabe mit der langsamen Hardware löst, das 
sagt durchaus was aus.

Denn wenn dieses langsame Gerät halbwegs brauchbar realisiert ist, dann 
kann man es immer anpingen, aber es meldet einfach über die serielle 
Schnitte zurück, dass es derzeit noch keine neuen Befehle empfangen 
kann.

von Harry L. (mysth)


Lesenswert?

Da du offenbar die ST-HAL nutzt, bietet es sich an, auch gleich FreeRTOS 
mit einzubinden, (geht auch via CubeMX) und deine Kommunikation in einen 
eigenen Task zu verlagern.
Dort darfst du dann statt HAL_Delay() osDelay() nutzen, ohne zu 
blockieren.

von Paul B. (paule201)


Lesenswert?

Danke für die ausführlichen Antworten!

Lothar M. schrieb:
1
> void main()
2
> {
3
>    EA_Init();
4
>    for (;;) {  // Hauptschleife dauernd schnellstmöglich durchlaufen
5
>       tiNow = get_timertick();
6
>       if (tiNow-tiLastset > 500) {
7
>          EA_set_output(status);
8
>          tiLastset = tiNow;
9
>       }

Das Programm schickt den "Init" Befehl in Endlosschleife und alle 500ms 
den set_Output Befehl. Soweit so gut.
Aber damit habe ich doch immer noch das Problem, dass alle ich das Gerät 
quasi überlaste.

Was ich suche ist ja nicht der zyklische Aufruf, dass mache ich im 
Hauptprogramm so wie es in der von Falk verlinkten Seite gezeigt ist. Da 
läuft ein 1ms Timer und fragt die Flags ab.

Evetuell ist das Beispiel auch schlecht gewählt, lasst uns daher etwas 
einfacheres nehmen.

Angenommen ich habe eine Funktion die mir 5 LEDs mit 500ms verzögerung 
anschaltet und wieder ausschaltet.
1
void LEDs()
2
{
3
LED 1 an
4
Delay 500
5
LED 2 an
6
Delay 500
7
LED 3 an 
8
....
9
}
Diese Funktion rufe ich nach einem Tasterdruck EINMAL auf, den ich in 
der Hauptschleife abfrage. Es wird also nicht zyklisch ausgeführt 
sondern nur bei Bedarf. Wie löse ich das Delay auf. Ich steh etwas auf 
dem Schlauch.
Muss ich dann jedes mal den Status der vorherigen LED abfragen?
1
if (Tik > 500 & LED 1 == 1)
2
{
3
LED 2 an 
4
} 
5
usw?


Danke für eure Mühe!

von Peter D. (peda)


Lesenswert?

MaWin O. schrieb:
> Es wird dich vielleicht überraschen, aber es muss immer eine maximale
> Geschwindigkeit bzw minimale Periodendauer geben.

Die maximale Geschwindigkeit sollte hautsächlich nur durch das Interface 
begrenzt sein. D.h. die Kommunikation und die Steuerung sollten parallel 
ablaufen und sich nicht gegenseitig blockieren können. Die 
Empfangspuffer sollten so groß sein, daß mindestens ein Steuerbefehl und 
ein Abfragekommando Platz haben. Ich mache es auch immer so, daß ich 
ADC-Werte reihum auslese, d.h. Abfragen können sofort mit dem letzten 
Meßwert aus dem RAM beantwortet werden.
Und wenn eine Spannungsrampe gefahren werden soll, dann kann ich dabei 
ständig den Busy-Status abfragen.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Ich würde "so etwas" lösen, in dem Ich vom Warten weg komme und hin zu 
Zeitpunkten, an denen etwas zu passieren hat, gehe. Diese Zeitpunkte 
(aka timer) lassen sich dann ganz gut mit anderem Input / asynchronen 
Ereignissen kombinieren.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Paul B. schrieb:
> Das Programm schickt den "Init" Befehl in Endlosschleife
Nein. Die HW wird natürlich nur 1x beim Powerup initialisiert. Muss man 
ja nicht laufend machen.

> und alle 500ms den set_Output Befehl. Soweit so gut.
> Aber damit habe ich doch immer noch das Problem, dass alle ich das Gerät
> quasi überlaste.
1. Dann musst du eben 600ms oder 1000ms oder noch länger warten.
2. Was ist das für ein lahmes "Gerät"?

Paul B. schrieb:
> Angenommen ich habe eine Funktion die mir 5 LEDs mit 500ms verzögerung
> anschaltet und wieder ausschaltet.
> ....
> Diese Funktion rufe ich nach einem Tasterdruck EINMAL auf, den ich in
> der Hauptschleife abfrage. Es wird also nicht zyklisch ausgeführt
> sondern nur bei Bedarf. Wie löse ich das Delay auf.
> Muss ich dann jedes mal den Status der vorherigen LED abfragen?
Nein, du machts einen "Zustandszähler" und wenn der auf 0 stehts, dann 
fragst du den Taster ab. Wenn der Taster gedrückt ist, schaltest du den 
Zähler um 1 weiter.

Wenn der Zustand 1 ist, dann schaltest du die 1. LED ein.
Wenn der Zustand 1 ist und die Zeit abgelaufen ist, dann schaltest du 
den Zunstand um 1 weiter.

Wenn der Zustand 2 ist, dann schaltest du die 2. LED ein.
Usw. usf.

In SW sieht das z.B. so aus:
1
int zustand = 0; 
2
int tinow, tilast;
3
main()
4
   Init_HW();
5
   for(;;) {
6
      tinow = gettick();
7
8
      if (zustand==0) { // auf Taster warten
9
         tilast=tinow;
10
         if (taste_gedrückt()) {
11
            zustand=1;
12
            tilast=tinow;
13
         }
14
      }
15
      
16
      if (zustand==1) { // LED1 an
17
         LED1on();
18
         if (tinow-tilast > 500) {
19
            zustand=1;
20
            tilast=tinow;
21
         }
22
      }
23
24
      if (zustand==2) { // zusätzlich LED2 an
25
         LED2on();
26
         if (tinow-tilast > 500) {
27
            zustand=3;
28
            tilast=tinow;
29
         }
30
      }
31
32
      if (zustand==3) { // zusätzlich LED3 an
33
         LED3on();
34
         if (tinow-tilast > 500) {
35
            zustand=4;
36
            tilast=tinow;
37
         }
38
      }
39
40
      if (zustand==4) { // alles wieder aus
41
         LED1off();
42
         LED2off();
43
         LED3off();
44
         if (tinow-tilast > 500) {
45
            zustand=0;
46
         }
47
      }
48
49
   }
50
}

: Bearbeitet durch Moderator
von J. S. (jojos)


Lesenswert?

Anstelle der if-Kette würde ich das switch-case verwenden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

J. S. schrieb:
> Anstelle der if-Kette würde ich das switch-case verwenden.
Mir fallen da auch noch ein paar Möglichkeiten ein, aber jetzt erst mal 
einen logischen Schritt nach dem anderen. Zuerst geht es allem voran um 
die Denkweise, dass man etwas nur dann macht, wenn es nötig ist und den 
Rest der Rechenzeit für was anderes verwendet. Denn die mainloop wird 
ist jetzt ja zigtausend mal pro Sekunde druchlaufen. Da kann man locker 
noch weitere Abfragen udn Zustandsautomaten dazuhängen.

Und wie man das hinterher tatsächlich implementiert, das bleibt dem 
jeweiligen Wissensstand überlassen.

: Bearbeitet durch Moderator
von Thomas R. (Gast)


Lesenswert?

Paul B. schrieb:
> Das wird doch dann schnell
> unübersichtlich.

Ich mache gleichzeitig folgendes:
Kartoffeln kochen,
Wäsche bügeln,
Musik geniessen,
Akkus laden,
das Wetter erleben,
und vieles mehr...

Wo soll ich da das "delay" hin schreiben?
Ich habe das niemals gebraucht, genau so wie das "goto".

"delay" ist von vorgestern und sollte verboten werden.

von Paul B. (paule201)


Lesenswert?

Danke für die Erklärung!

Lothar M. schrieb:
> 2. Was ist das für ein lahmes "Gerät"?

Ein Netzteil, welches sich per UART fernsteuern lässt. Lasse ich das 
Delay weg, nimmt er nur den ersten Befehl.

Lothar M. schrieb:
> In SW sieht das z.B. so aus:

Ist es wirklich üblich solche Zustandsautomaten Monster in die main zu 
packen? Ich dachte immer mal will so viel wie möglich in Funktionen 
auslagern. Ich dachte immer man mancht nur in der main die Abfrage des 
Tasters und springt dann in die Funktion.
Wenn ich den Zustandsautomaten in die Funktion packe, dann müsste ich 
sie ja mehrmals aufrufen damit ich alle Zustände durchspringen kann?
Ich seh den Wald wahrscheinlich vor lauter Bäumen nicht.
Gibts irgendwo auf GitHub ein schönes Beispiel wo man sich mal ein etwas 
komplexeres Projekt ansehen kann wo die Sache gut gelöst wurde.

Thomas R. schrieb:
> "delay" ist von vorgestern und sollte verboten werden.

Ein Beispiel aus deinem Funduds wäre nett und würde zur Lösung/Erklärung 
mehr beitragen als das Verteufeln von delay :).

von MaWin O. (mawin_original)


Lesenswert?

Lothar M. schrieb:
> In SW sieht das z.B. so aus:

Das ist ja grausam.

Mit asynchroner Programmierung schreibe ich es ganz einfach fast so hin, 
wie der Threadersteller es geschrieben hat. Ganz ohne globales 
Blockieren.

von Thomas R. (Gast)


Lesenswert?

Paul B. schrieb:
> Thomas R. schrieb:
>> "delay" ist von vorgestern und sollte verboten werden.
>
> Ein Beispiel aus deinem Funduds wäre nett und würde zur Lösung/Erklärung
> mehr beitragen als das Verteufeln von delay :).

In diesem Thread gibt es schon genug gute Beiträge und niemand verwendet 
"delay", nur du verwendet diesen Mist.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Thomas R. schrieb:
> genau so wie das "goto".

Thomas R. schrieb:
> "delay" .... sollte verboten werden.

Dogmatismus, ohne Sinn und Verstand.

von Sebastian W. (wangnick)


Lesenswert?

Paul B. schrieb:
> Wenn ich den Zustandsautomaten in die Funktion packe, dann müsste ich
> sie ja mehrmals aufrufen damit ich alle Zustände durchspringen kann?
> Ich seh den Wald wahrscheinlich vor lauter Bäumen nicht.

MaWin O. schrieb:
> Mit asynchroner Programmierung schreibe ich es ganz einfach fast so hin,
> wie der Threadersteller es geschrieben hat. Ganz ohne globales
> Blockieren.

Asynchrone Programmierung, also die Schachtelung von Rückrufschnipseln, 
ist eine mögliche alternative Notation zu Zustandsautomaten. MaWin O., 
wäre schön dazu von dir ein Beispiel zu sehen, vielleicht ähnlich dem 
Automaten von Lothar ... ?

LG, Sebastian

von Paul B. (paule201)


Lesenswert?

Thomas R. schrieb:
> In diesem Thread gibt es schon genug gute Beiträge und niemand verwendet
> "delay", nur du verwendet diesen Mist.

Zu denen ich noch Fragen habe, was üblich und "state of the art" ist. 
Von denen du bis jetzt übrigens keine beantworten konntest.

Worin siehst du den Mehrwert deiner Beiträge? Zwei an der Zahl, zweimal 
kein fachlicher Gewinn für die Diskussion. Was tribt dich an, inhaltlose 
Kommenentare zu Themen abzugeben, von denen du offenbar genauso viel 
weißt wie ich. Delay ist Scheiße, hab ich für mich auch festgestellt und 
deswegen gibts den Thread hier.

von Thomas R. (Gast)


Lesenswert?


von Stefan F. (Gast)


Lesenswert?

Fabian H. schrieb im Beitrag #7364923:
> Es gibt verschiedene Möglichkeiten, um dieses Problem zu lösen. Hier
> sind einige Vorschläge

Nur scheiße dass man von ChatGPT niemals Links bekommt, wo man die 
Antworten vertiefen kann. Ziemlich nutzlos ist das so.

von Helmut H. (helmuth)


Lesenswert?

Stefan F. schrieb:
> Nur scheiße dass man von ChatGPT niemals Links bekommt

muddu fragen "hast du links", hier z.B. u.a.
"
Online-Foren und Diskussionsgruppen:
    Stack Overflow: https://stackoverflow.com/
    Reddit r/embedded: https://www.reddit.com/r/embedded/
    Mikrocontroller.net: https://www.mikrocontroller.net/forum
"

von MaWin O. (mawin_original)


Lesenswert?

Sebastian W. schrieb:
> Asynchrone Programmierung, also die Schachtelung von Rückrufschnipseln,
> ist eine mögliche alternative Notation zu Zustandsautomaten. MaWin O.,
> wäre schön dazu von dir ein Beispiel zu sehen, vielleicht ähnlich dem
> Automaten von Lothar ... ?

Ja, gerne. Das sieht praktisch wie der Originalcode vom Threadersteller 
aus. Außer, dass dem delay()-Aufruf noch ein .await() oder etwas 
ähnliches angehängt wird (je nach Sprache). Und die Funktion wird meist 
auch noch mit dem keyword async oder ähnlichem dekoriert.
Das ist aber eigentlich unwichtig. Das Wichtige ist: Der Programmablauf 
bleibt lesbar und linear.

von Marci W. (Gast)


Lesenswert?

Hallo Leute,

ohne jetzt den Thread komplett gelesen zu haben (evtl. wurde meine 
Antwort schon gegeben):

In der "Automatisierungstechnik" (ich weiß, das haben wir hier auch) 
wird das so gehandhabt, dass eine Funktion erstellt wird, die in jedem 
Durchlauf der
Hauptschleife aufgerufen wird. Diese hat als Argument ein 
"Start"-Signal.
Ein statischer Pegel oder eine Flanke dieses Parameters triggert in der 
Funktion die durchzuführende Aktion. Dabei kehrt die Funktion sehr 
schnell zurück. Liegen in der Funktion dann Ergebnisse bzw. Daten vor, 
signalisiert die Funktion dies über ein Bit "Auftrag erledigt". Das 
übergeordnete Programm kann dann die Daten, die die Funktion erzeugt 
hat, ohne Verzögerung abholen und verwenden.

ciao

Marci

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Paul B. schrieb:


> Ist es wirklich üblich solche Zustandsautomaten Monster in die main zu
> packen? Ich dachte immer mal will so viel wie möglich in Funktionen
> auslagern.

Wenn das gezeigte Beispiel den gesamten Funktionsumfang zeigen würde, 
wäre ich mit der Größe der main() Funktion einverstanden. Ansonsten 
haben sich enums bewährt, dann muss man den Kommentar bei der Nutzung 
der magic numbers nicht immer wiederholen ;-)

Warum sollte man das nicht in Funktionen auslagern können? Bei dem ARM 
Cortex, die ich hauptsächlich nutze, gibt es ein Intrinsic, dass die CPU 
schlafen läßt bis irgend ein Interrupt ausgelöst hat.

Wenn jetzt jedes Modul, seine Interrupts lokal händelt und z.B. nötige 
Informationen in Modul-Lokalen Variablen, Queues etvl. mit dem main 
thread teilt, dann könnte z.B. jedes Modul eine Funktion zur Verfügung 
stellen, dass die aktuelle Zeit nimmt, und den Zeitpunkt, zu dem das 
Modul etwas zu tun hat, zurück geben lassen:
1
int main()
2
{
3
    time_pnt_t next = time_now();
4
5
    for ( ;;  )
6
    {
7
      next = module1( next );
8
      next = time_min( next, module2( next ) );
9
      next = time_min( next, module3( next ) );
10
11
      time_wait_till( next );
12
13
      __WFI();
14
      next = time_now();
15
    }
16
}

time_pnt_t wäre ein Typ, der einen Zeitpunkt mit der nötigen Auflösung 
speichern kann, der überlaufen kann und trotzdem zuverlässig, 
zweifelsfrei den Abstand zwischen zwei geplanten Ereignissen 
berücksichtig. `time_now()` liefert die aktuelle Zeit, `time_min()` 
liefert den früheren von 2 Zeitpunkten. `time_wait_till()` setzt einen 
Timer auf, der __WFI() zum gg. Zeitpunkt wieder aufweckt.

von Val D. (valeri_d)


Lesenswert?

Thomas R. schrieb:
> Ich habe das niemals gebraucht, genau so wie das "goto".

In Assembler kann man mit goto (JMP) oder goto mit Flag-Bedienungen viel 
Gutes anstellen. In anderen Programmiersprachen wurde goto durch andere 
Konstrukte ersetzt,  ohne dass es offensichtlich ist. ZB der break aus 
der switch oder while oder for Anweisung ist nichts anderes als ein 
goto.

von J. S. (jojos)


Lesenswert?

Sebastian W. schrieb:
> wäre schön dazu von dir ein Beispiel zu sehen, vielleicht ähnlich dem
> Automaten von Lothar ... ?

ich hätte da ein Beispiel für asynchrones Eventhandling:
1
#include "mbed.h"
2
3
EventQueue queue;
4
InterruptIn user_button(BUTTON1);
5
6
void EA_Init() {
7
  // some init stuff
8
}
9
10
void EA_set_output(uint8_t status) {
11
  // some output stuff
12
}
13
14
void PS_on(uint8_t status)
15
{
16
   queue.call(EA_Init);
17
   queue.call_in(500ms, &EA_set_output, status);
18
}
19
20
int main()
21
{
22
  user_button.rise( []() {
23
    PS_on(42);
24
  });
25
26
  queue.dispatch_forever();
27
28
  return 0;
29
}

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.