Forum: Mikrocontroller und Digitale Elektronik FreeRTOS + Arduino = erstes Programm.


von X. A. (wilhem)


Lesenswert?

..das natürlich nie wie gewünscht funktioniert.
Hallo zusammen,
Wegen der Uni brauche ich eine Einführung in Echtzeitssysteme und 
Arduino.
Im Internet bin ich auf diesen Port des FreeRTOS 
http://code.google.com/p/rtoslibs/ der sehr vielversprenchend ist und 
daher ich damit anfangen wollte.

Angenommen, dass ich erst jetzt mit Echtzeitprogrammierung angefangen 
habe, habe ich mich die Examples in der Bibliothek angeschaut und das 
folgende Programm für Arduino 2009 geschrieben und hochgeladen habe
1
#include <FreeRTOS_AVR.h>
2
3
// The LED is attached to pin 4 and 5
4
const int greenLed = 4;
5
const int redLed = 5;
6
7
/*
8
 * Thread 1, turn the LED on and off.
9
 */
10
// Declare the thread function for thread 1.
11
static void Thread1(void* arg) {
12
  while (1) {
13
    
14
    digitalWrite(redLed, HIGH);
15
    // Sleep for 200 milliseconds.   
16
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
17
    // Turn LED off.
18
    digitalWrite(redLed, LOW);
19
    // Sleep for 200 milliseconds.   
20
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
21
  }
22
}
23
24
/*
25
 * Thread 2, turn the LED on and off.
26
 */
27
// Declare the thread function for thread 2.
28
static void Thread2(void* arg) {
29
  
30
  while (1) {
31
    
32
    digitalWrite(greenLed, HIGH);
33
    // Sleep for 200 milliseconds.   
34
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
35
    // Turn LED off.
36
    digitalWrite(greenLed, LOW);
37
    // Sleep for 200 milliseconds.   
38
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
39
  }
40
}
41
42
void setup() {
43
44
  pinMode(redLed, OUTPUT);
45
  pinMode(greenLed, OUTPUT);
46
  
47
  Serial.begin(115200);
48
  
49
  portBASE_TYPE s1, s2;
50
  
51
  /* Thread 1 prio 1 */
52
  s1 = xTaskCreate(Thread1, NULL, configMINIMAL_STACK_SIZE, NULL, 1, NULL);
53
  /* Thread 2 prio 2 */
54
  s2 = xTaskCreate(Thread2, NULL, configMINIMAL_STACK_SIZE, NULL, 2, NULL);
55
56
  // check for creation errors
57
  if (s1 != pdPASS || s2 != pdPASS) {
58
    Serial.println(F("Creation problem"));
59
    while(1);
60
  }
61
  
62
  vTaskStartScheduler();
63
  Serial.println(F("Insufficient RAM"));
64
  while(1);
65
66
}
67
// Loop is the idle thread.  The idle thread must not invoke any 
68
// kernel primitive able to change its state to not runnable.
69
void loop() {
70
  // Not used.
71
}

Nun ich habe 2 Tasks erzeugt, damit die an den Pins 4 und 5 verbundenen 
Led ein-ausgeschaltet werden können.
Die gewünschte Reihenfolge ist folgende:

redLed ON     redLed OFF     greenLed ON      greenLed OFF
|-------------|--------------|----------------|-----------------------> t
t0 = 0        t1 = 200 ms    t2 = 400 ms      t2 = 600 ms

ABER, wenn ich das Programm kompilieren und hochladen lasse, dass werden 
alle 2 Led gleichzeitig ein- und ausgeschlatet.
Also....ich hatte mir gedacht, dass da die 2 Tasks zwei verschiedene 
Prioritäten haben. Infolgedessen wird zuerst die Task mit prio 1 
ausgeführt und dann die Task mit prio 2. Hingegen passiert alles 
gleichzeitig.
Wie soll ich das Programm ändern? Wo steckt der Fehler?

Danke und Gruß!!!

von Karl (Gast)


Lesenswert?

Nun, das die Sachen gleichzeitig passieren ist doch gerade der Sinn 
eines RTOS. Hast du da was falsch verstanden?

von Jojo S. (Gast)


Lesenswert?

vTaskDelay()  gibt die CPU anderen Prozessen anstelle die Zeit in einer 
Endlosschleife zu verbraten. Zum Vergleich kannst du die Funktion ja mal 
durch das Arduino delay() ersetzen.
Im FreeRTOS Manual ist das Verhalten in den ersten Kapiteln auch sehr 
gut beschrieben.

von X. A. (wilhem)


Lesenswert?

Naja, ich dachte mir, dass der Sinn eines RTOS darin bestand, ein 
Programm in verschiedenen Tasks aufzuteilen und ausführen lassen. Aus 
der Webseite ist hier zB eine kurze Einführung zu ersehen:
http://www.freertos.org/implementation/TaskExecution.gif

und anscheinend ähnelt mein Program dem ersten Graf oben, währenddessen 
das Verhalten in dem zweiten Graf gewünscht ist. Ich verstehe nicht, wie 
ich die 3 Tasks miteinander koordinieren kann.

ich werde mir nun das Manual besorgen. Leider gibt es nicht so viele 
info im Internet, sondern muss man das Buch kaufen.

Danke!

von Jojo S. (Gast)


Lesenswert?

Task1 startet und schaltet die rote LED an und wartet dann. Wenn Task1 
anfängt zu warten kommt die nächste Task dran, also Task2 und schaltet 
die grüne LED an. Das passiert mit nicht sichtbarem Zeitversatz, einigen 
mikrosekunden. Wenn die grüne LED versetzt blinken soll müsstest du vor 
die while Schleife in Task2 noch ein vTaskDelay setzen.

von Jojo S. (Gast)


Lesenswert?

Wenn die Task voneinander abhängig laufen sollen dann sieh dir das 
Kapitel mit den Semaphoren an. Damit kann man eine Task anhalten bis sie 
durch ein Ereignis einer anderen wieder freigegeben wird.

von X. A. (wilhem)


Lesenswert?

Danke Jojo!!
Ich habe seit Stunden versucht, mit einer Semaphore das Programm 
umzuschreiben. Dennoch läuft es gar nicht. Die Led werden ein- und 
ausgeschaltet @ random.
Hier der Code:
1
#include <FreeRTOS_AVR.h>
2
3
// The LED is attached to pin 13 on Arduino
4
const int yellowLed = 2;
5
const int blueLed = 3;
6
const int greenLed = 4;
7
const int redLed = 5;
8
9
xSemaphoreHandle sem;
10
11
//------------------------------------------------------------------------------
12
/*
13
 * Thread 1, turn the LED off and on.
14
 */
15
// Declare the thread function for thread 1.
16
static void Thread1(void* arg) {
17
  while (1) {
18
19
    xSemaphoreTake(sem, portMAX_DELAY);
20
    
21
    digitalWrite(redLed, HIGH);
22
    // Sleep for 200 milliseconds.   
23
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
24
    // Turn LED off.
25
    digitalWrite(redLed, LOW);
26
    // Sleep for 200 milliseconds.   
27
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
28
    
29
    xSemaphoreGive(sem);
30
  }
31
}
32
//------------------------------------------------------------------------------
33
/*
34
 * Thread 2, turn the LED on and off.
35
 */
36
// Declare the thread function for thread 2.
37
static void Thread2(void* arg) {
38
  
39
  while (1) {
40
    
41
    xSemaphoreTake(sem, portMAX_DELAY);
42
        
43
    digitalWrite(greenLed, HIGH);
44
    // Sleep for 200 milliseconds.   
45
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
46
    // Turn LED off.
47
    digitalWrite(greenLed, LOW);
48
    // Sleep for 200 milliseconds.   
49
    vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
50
    
51
    xSemaphoreGive(sem);
52
  }
53
}
54
void setup() {
55
56
  pinMode(redLed, OUTPUT);
57
  pinMode(greenLed, OUTPUT);
58
  pinMode(blueLed, OUTPUT);
59
  
60
  Serial.begin(115200);
61
  
62
  portBASE_TYPE s1, s2, s3;
63
  
64
  // initialize fifoData semaphore to no data available
65
  vSemaphoreCreateBinary(sem);
66
  
67
  s1 = xTaskCreate(Thread1, NULL, configMINIMAL_STACK_SIZE, NULL, 1, NULL);
68
  s2 = xTaskCreate(Thread2, NULL, configMINIMAL_STACK_SIZE, NULL, 2, NULL);
69
70
  // check for creation errors
71
  if (sem == 0 || s1 != pdPASS || s2 != pdPASS) {
72
    Serial.println(F("Creation problem"));
73
    while(1);
74
  }
75
  
76
  vTaskStartScheduler();
77
  Serial.println(F("Insufficient RAM"));
78
  while(1);
79
80
}
81
//------------------------------------------------------------------------------
82
// Loop is the idle thread.  The idle thread must not invoke any 
83
// kernel primitive able to change its state to not runnable.
84
void loop() {
85
  // Not used.
86
}

Vielleicht verwende ich die Semaphore nicht richtig (meine Vermutung), 
aber Tutorial im Internet sind echt schwer zu finden und die meisten 
sind für mich unverständnis.

Bezüglich der Erklärung des ersten Problems, habe ich verstanden, wieso 
die Led fast gleichzeitig leuchteten. Nun verstehe was du mit delay() 
von Arduino meintest. Danke!!!

von Markus M. (mark_m)


Lesenswert?

Wenn Du bei Guckle nach "Nebenläufige Programmstrukturen" suchst, hast 
Du Lesestoff bis Weihnachten.

Grüsse

von chris (Gast)


Lesenswert?

Hallo Dave,

da ich mich nicht mit FreeRTOS auskenne: Wie aufwendig ist es, das 
System für Arduino in Betrieb zu nehmen? Muss man viel Zeit investieren, 
bis es mal grundsätzlich kompiliert?

Gruß,
chris

von X. A. (wilhem)


Lesenswert?

Hi chris
Ich bin auch in der gleichen Situation und daher sage ich dir, dass das 
Ganze im Betrieb zu bringen nicht so schwierig ist. Ich konnte die 
ersten 2 Led mit Arduino 2009 innerhalb ein paar Stunden blinken lassen.
Was schwierig ist, ist in Echtzeitsysteme umzudenken.
Semaphore, Mutex und so weiter benötigen richtig Zeit um RTOS zu lernen.
Ich habe mit diesen 2 FreeRTOS-like RTOSs angefangen:
http://code.google.com/p/rtoslibs/            (meine Empfehlung +++++)
https://bitbucket.org/ctank/ardos/wiki/Home   (meine Empfehlung ++++)

Mit dem zweiten habe ich Probleme beim kompilieren aber hat den Vorteil, 
dass die Beispiele einfacher zu verstehen sind.

Im Internet habe ich nichts viel gefunden. Was ich ich fand, war 
andereseits unverständlich.

Ich würde mich aber drüber freuen, wenn wir hier unsere Erfarhungen 
austauschen würden.

gruß

von holger (Gast)


Lesenswert?

>Ich habe seit Stunden versucht, mit einer Semaphore das Programm
>umzuschreiben. Dennoch läuft es gar nicht.

Kein Wunder, du fragst ja gar nicht ab ob du die
Semaphore bekommen hast oder nicht und schaltest trotzdem
munter weiter die LEDs.

von X. A. (wilhem)


Lesenswert?

holger schrieb:
>>Ich habe seit Stunden versucht, mit einer Semaphore das Programm
>>umzuschreiben. Dennoch läuft es gar nicht.
>
> Kein Wunder, du fragst ja gar nicht ab ob du die
> Semaphore bekommen hast oder nicht und schaltest trotzdem
> munter weiter die LEDs.

Ich meinte damit, dass die Led nicht nach der gewünschten Reihenfolge 
schalten. Das liegt bestimmt an der Semaphore. Ich kann noch nicht deren 
Funktion in einem Programm implementieren. Das Programm hingegen lässt 
sich kompilieren.

von holger (Gast)


Lesenswert?

>Ich meinte damit, dass die Led nicht nach der gewünschten Reihenfolge
>schalten. Das liegt bestimmt an der Semaphore.

Ich denke eher das das an deinen unterschiedlichen
Task Prioritäten liegt. Wer sagt denn das wenn Task2
fertig mit einmal blinken ist dann auch sofort Task1
drankommt? Task2 hat höhere Priorität und kann durchaus
auch zweimal nacheinander aufgerufen werden.

Was passiert wenn du beiden Tasks gleiche Priorität gibst?

von holger (Gast)


Lesenswert?

>Was passiert wenn du beiden Tasks gleiche Priorität gibst?

Wird auch nichts breingen wenn man mal weiter nachdenkt.
Es ist ja nicht sicher das der Task sich die Semaphore
gleich wieder schnappt.
Nach dem     xSemaphoreGive(); könnte ein taskYield();
klappen. Damit gibst du dem zweiten Task die Chance
die Semaphore zu schnappen.
Aber Semaphore geht bei dir ja noch nicht.

Mal abgesehen davon hast du da EINE Aufgabe in zwei Tasks
gepackt. Das ist irgendwie nicht so sinnvoll.

von Falk B. (falk)


Lesenswert?

Wie man Probleme mit HiTec löst, die man ohne sie nie hätte ;-)

Der OP muss glaub ich noch ein wenig das Grundkonzept von 
Multitasking verstehen, einfach nur hippes Arduino + RTOS reicht bei 
weitem nicht.

von Stefan (Gast)


Lesenswert?

Das Programm ist kein gutes Beispiel für Semaphoren. Dafür nimmt man 
Message Queues.
1
Task A:
2
 - Warten auf Nachricht
3
 - Blinken
4
 - Nachricht an B
5
6
Task B:
7
 - Warten auf Nachricht
8
 - Blinken
9
 - Nachricht an A

Hier gibt es am Anfang ein Henne/Ei Problem weil beide Tasks warten.
Das kann man lösen in dem eine Task sofort eine Nachricht schickt und 
dann wartet oder daß in einer Task initial eine Nachricht verschickt 
wird.

Diese Tests mit LEDs halte ich aber für fragwürdig da ein reelles 
Programm doch etwas anders gestrickt ist. Hier wird im Grunde genommen 
ein typisches Mainloop Design auf ein RTOS abgebildet. Ohne Vorteil aber 
mit allen Problemen die ein RTOS machen kann. Kein Wunder daß sich RTOS 
Verweigerer ins Fäustchen lachen.
Klar, irgendwie muß man anfangen aber das Ziel sollte man halt nicht aus 
den Augen verlieren.

von Stefan (Gast)


Lesenswert?

PS: Was mir noch aufgefallen ist:
1
vTaskDelay((200L * configTICK_RATE_HZ) / 100L);
Ich glaube das funktioniert eher zufälig. Offiziell wird es so 
beschrieben:
1
vTaskDelay((200/portTICK_RATE_MS);

Oder ist das eine Besonderheit des AVR Ports?

von X. A. (wilhem)


Lesenswert?

Ok danke an Stefan und Holger.
Nur ist es mir klar geworden, dass das Beispiel mit den Leds eher 
Probleme erzeugt als was zu klären. Nun lerne ich FreeRTOS direkt aus 
dessen Manual.
Die Idee mit den Nachrichten ist gut. Nun habe ich verstanden wie ich 
meine programme umschreiben soll.
Wie gesagt, ich muss wegen der Uni ein RTOS lernen und die ersten 
Programme habe ich immer mit Leds angefangen.

Der
1
configTICK_RATE_HZ

ist anscheinend ein Port für AVR und ARM.
Wenn ihr bessere Beispiele um FreeRTOS habt, bitte Bescheid geben!!!!

Danke

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.