sitemap link mailform link home

Taskverarbeitung

Artikel vom 30.09.2016

Ein einfaches Blinkprogramm mit einer LED an Port 13 könnte so aussehen:

#define LED_PORT1 13
#define TIME 500

void setup() {
  // put your setup code here, to run once:
  pinMode(LED_PORT1, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(LED_PORT1, HIGH);
  delay(TIME);
  digitalWrite(LED_PORT1, LOW);
  delay(TIME);

}

Durch die Verwendung der delay()-Funktion wird der Prozessor einfach in eine Art Schlafphase versetzt, so dass keine anderen Aufgaben bearbeitet werden können.

Da wäre es doch schön, wenn man mehrere (quasi) unabhängige Tasks definieren und starten könnte.

Schnell stellt man aber fest, dass der Arduino Uno keine Taskverarbeitung unterstützt. Dafür bräuchte es wenigstens ein Minimal-Betriebssystem.

Allerdings kann man mit einer geschickten, programmierten "Zeitscheiben-Aufteilung" eine relativ große Zahl von Prozessen quasi-parallel laufen lassen. So kann man bspw. mit dem weiter unten stehenden Demo-Programm drei LEDs unabhängig voneinander mit unterschiedlichen Frequenzen blinken lassen.

Anmerkung: Wer sich mit der Timer-Programmierung von ATMEL-Mikrocontrollern auskennt, kann natürlich Timer-Interrupts für die zeitliche Steuerung von Prozessen benutzen. Die nachfolgend gezeigte Programmiertechnik verzichtet aber bewusst darauf und nutzt die
Arduino-Funktion millis(), die einen Systemtakt im Millisekunden-Abstand zur Verfügung stellt.

Siehe auch https://learn.adafruit.com/multi-tasking-the-arduino-part-1/using-millis-for-timing

Und https://learn.adafruit.com/multi-tasking-the-arduino-part-1/ditch-the-delay

Und https://learn.adafruit.com/multi-tasking-the-arduino-part-2/what-is-an-interrupt

Meine Idee war es nun, den exakten Zeitpunkt für Aktionen mit Hilfe der Modulo-Funktion (%) aus dem Millisekunden-Takt zu ermitteln. Diese Funktion liefert den Rest bei einer Division:

unsigned long currentMillis = millis(); // Abspeichern des aktuellen ms-Taktes in currentMillis

if ((currentMillis % Periodendauer) == 0)
{
    digitalWrite(LED_Port, HIGH);
}

Wenn nun der Millisekunden-Ticker millis() ein Vielfaches der Periodendauer liefert, so ergibt die Division ein Ergebnis mit Rest = 0. Immer dann, und nur dann, wird die Aktion der if-Anweisung ausgeführt.

Ist z.B. die Periodendauer = 1000 ms (also 1 sec) , so ergibt die Modulo-Funktion jeweils nach 1 sec, 2 sec, 3 sec usw. einen Rest = 0 und die Aktion   digitalWrite(LED_Port, HIGH); wird ausgeführt.

Natürlich sollte man dann nach der halben Periodendauer (hier 500 ms) die LED auch wieder ausschalten.

Im folgenden Demo-Code gibt es sogar noch einen offset, der einen Versatz der Blinkzeiten in Bezug auf den Zeitpunkt des Programmstarts ermöglicht.

Demo-Code:

// Drei LEDs sind mit Vorwiderständen an drei Ports angeschlossen

#define LED_PORT1 13
#define LED_PORT2 12
#define LED_PORT3 11

// Bei der Verwendung von millis() müssen
// alle Konstanten und Variablen vom Datentyp long sein!
const long Periodendauer1 = 1000;
const long Offset1 = 0;
const long Periodendauer3 = 567;
const long Offset2 = 100;
const long Periodendauer2 = 888;
const long Offset3 = 200;

void setup() {
pinMode(LED_PORT1, OUTPUT);
pinMode(LED_PORT2, OUTPUT);
pinMode(LED_PORT3, OUTPUT);

// Alle LEDs erst einmal ausschalten

digitalWrite(LED_PORT1, LOW);
digitalWrite(LED_PORT2, LOW);
digitalWrite(LED_PORT3, LOW);

}

void loop() {

// Aufrufen derselben Funktion blink() für unterschiedliche LEDs mit
// unterschiedlichen Blinkfrequenzen / Periodendauern:

blink(LED_PORT1, Periodendauer1, Offset1);
blink(LED_PORT2, Periodendauer2, Offset2);
blink(LED_PORT3, Periodendauer3, Offset3);

}

void blink(int LED_Port, unsigned long Periodendauer, unsigned long offset)
{
unsigned long currentMillis = millis();
if ((currentMillis % Periodendauer) == 0 + offset)
{
digitalWrite(LED_Port, HIGH);
}
if ((currentMillis % Periodendauer) == (round(Periodendauer / 2) + offset))
{
digitalWrite(LED_Port, LOW);
}

}

 

 

.

Letzte Änderung:
March 23. 2023 21:04:40
«    top    »