Blink Sketch ohne delay() - AZ-Delivery

Hallo en welkom op onze post vandaag. Vandaag gaat het over een schets die waarschijnlijk iedereen kent, en zeker meerdere malen heeft geüpload naar zijn microcontroller: de Blink Sketch.

Ik heb zelf nog nooit veel aandacht besteed aan de schets, en ik gebruik het alleen om te controleren of een module geeft een teken van leven op alle.

Echter, het gebruik van vertraging (1000) in knipperende schets heeft een groot nadeel: de microcontroller wacht een seconde (1000 ms) op het punt, en kan niets anders doen in de tijd. Het is dus niet mogelijk om een tweede LED kort in- en uit te schakelen tijdens de vertraging.

Het wordt ook problematisch als u werkt aan een project waarbij de status van een pin moet worden opgevraagd tijdens het knipperen, bijvoorbeeld om te controleren of een schakelaar is ingedrukt. Als een knop tijdens de vertraging wordt ingedrukt en voor het einde van de vertraging wordt vrijgegeven, krijgt de microcontroller er niets van.

Laten we de volgende kleine codefragmenten als voorbeeld nemen:

  Void Setup() {

  pinMode(3, Output);   pinMode(4, Output);   pinMode(8, Input);
}

Void Lus() {   Als (digitaalLezen(8) == Hoge){     digitalWrite(4, !digitaalLezen(4)); Schakelt LED in om 4 aan/uit te pinnen   }   digitalWrite(3, Hoge); LED naar pin 3 OP     Vertraging(1000); Breken               digitalWrite(3, Lage); LED naar pin 3 UIT       Vertraging(1000); Breken            
}  

Aan het begin van de lus "void loop()" lezen we de status van de knop op pin 8. Als dit is ingesteld op HOOG, wordt de waarde van pin 4 omgekeerd met behulp van digitalWrite op pin 4.

Dan schakelen we pin 3 naar HIGH, wacht een seconde, houd de pin terug naar LOW, en wacht nog een seconde.

Dus als we op de knop drukken tijdens de twee vertragingen, gebeurt er niets. Alleen als we de knop ingedrukt houden terwijl de digitalRead(8) wordt aangeroepen, zetten we de tweede LED aan of uit.

Dit werd problematisch, bijvoorbeeld met het alarmsysteem, dat we onlangs in de blog presenteerden. Een bewegingssensor heeft daar het alarm geactiveerd. Als u voor het apparaat stond en de beveiligingscode wilde invoeren, werd het alarm steeds opnieuw geactiveerd, wat leidde tot een pauze in de invoer.

Daarom wordt aanbevolen om te doen zonder de vertraging() functie.

Een mogelijke oplossing zou zijn om de vertraging te verminderen tot 100 ms of zelfs minder, en om een teller hoog te tellen voor elke pas. Wanneer het een bepaalde waarde bereikt, reset deze op 0 en zet u de LED uit.

Maar we kunnen al het werk redden dankzij de millis() functie. De functie millis() retourneert het aantal milliseconden dat is verstreken sinds het huidige programma is gestart. Het aantal wordt na ongeveer 50 dagen teruggezet naar 0.

Om deze waarde op te slaan in een variabele, moet deze van het type "niet-ondertekend lang" zijn. Dit maakt een getal mogelijk tussen 0 en 4.294.967.295.

In ons voorbeeld maken we een variabele genaamd "previousMillis" en maken we een variabele van het type "const" waarin we het interval van 1000 ms instellen.

Bij het passeren van "void loop()" plaatsen we de output van milis() in de variabele "currentMillis". Vervolgens wordt gecontroleerd of er sinds de laatste pas 1000 ms zijn gepasseerd. Als dat zo is, wordt de waarde van previousMillis overschreven met die van currentMillis en wordt de LED ingeschakeld of uitgeschakeld.

 

Unsigned Lange previousMillis = 0; bespaart de tijd waarop de laatste schakelaar werd
Const Lange Interval = 1000; Lengte van de pauze in ms

Void Setup() {   pinMode(3, Output); LED 1   pinMode(4, Output); LED 2   pinMode(8, Input);  Knop
}

Void Lus() {   Als (digitaalLezen(8) == Hoge){     digitalWrite(4, !digitaalLezen(4)); Schakelt LED in om 4 aan/uit te pinnen   }
 Unsigned Lange currentMillis = millis(); Huidige tijd wordt opgeslagen in currentMillis   Als (currentMillis - previousMillis >= Interval) { Als er meer dan 1000 ms zijn verstreken      previousMillis = currentMillis; De tijd van het laatste circuit wordt geregistreerd    digitalWrite(3, !digitaalLezen(3)); LED is in- of uitgeschakeld   }
}

 

Nu kunnen we de tweede LED met de knop schakelen, ongeacht wat de eerste LED doet.

Als u het hele ding opnieuw hebt gemaakt en de code hebt geprobeerd, zult u vinden dat de belangrijkste lus door zo vaak wordt uitgevoerd dat het niet zo gemakkelijk is om de tweede LED met een knoop te schakelen.

Hier zouden we moeten de knop los te knopen (Engl. debouncing), maar dit is een onderwerp voor een andere blog post.

Ik hoop dat onze bijdrage vandaag liet zien hoe gemakkelijk het kan zijn om te werken met millis(). 

We willen u bedanken voor de groeiende belangstelling en de vele feedback inzet van de afgelopen weken en afscheid nemen tot morgen.

De jouwe Markus Neumann

 

 

 

 

 

Grundlagen software

2 Reacties

W. Parschfeld

W. Parschfeld

Alternativ wäre eine parallele Programmierung zu empfehlen – kann für viele zufälligen parallele Ereignisse benutz werden: z.B. Analog-Uhr auf graf. Display, Abfrage verschiedener Steuerimpulse, Kommunikation über I2C etc. (z.B. vom WiFi-Modul), laden von SD-Card… Gute Erfahrungungen habe ich mit der Bibliothek TimedAction gemacht …

A. Deppe

A. Deppe

Im Prinzip eine gute Idee – allerdings gibt es genau für dieses Problem (wenigstens für die MKR’s) die “scheduler” Funktion. Zusammen mit dem Scheduler macht die Delay (und Yield) Funktion dann wieder absolut Sinn , denn Delay legt die entsprechende Funktion in der Delay angewendet wird für den Delay Zeitraum schlafen und gib die Rechenzeit für andere “geschedulte” Funktionen frei. Das ist erheblich effizienter und ermöglicht multitasking.

Noch eine Bemerkung zu dem angeschnittenen Thema “Alarmanlage”: Wenn man Eingaben sicher verarbeiten will, ist es meistens eine gute Idee das Interupt handling dafür zu bemühen. Ich würde versuchenden die void loop so klein wie möglich zu halten und da nur das Interupt handling drin zu realisieren. Die eigentliche Verarbeitung würde ich in eigene Funktionen auslagern. Das ist nicht nur übersichtlicher sondern auch Speicher effizienter, weil die Funktionen/Variablen nur zur Laufzeit instanziert werden.

Auch hier kann der Scheduler helfen – um z.B. Ein- und Ausgabe zu deserialisieren.

Laat een reactie achter

Alle opmerkingen worden voor publicatie gecontroleerd door een moderator

Aanbevolen blogberichten

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery