Forum: Compiler & IDEs Multitasking - Zeitproblem


von achim (Gast)


Lesenswert?

Hallo
zur Anzeige auf einer LED Matrix mit 8x8 LED mit dem I2C Bus verwende 
ich den folgenden Code. Dieser läuft sehr gut, ohne jedes Problem.
1
void Matrix_Write2Bild1Zeit(uint8_t start)  // schreibt bild1
2
  {
3
    int8_t nr = 0;          // array nr auf 0
4
    for (uint8_t i=start; i<16; i+=2)    // Auswahl der Zeile jede 2.
5
      {
6
        i2c_start(Bild_modul2_addr<<1);  // schreibt modul 1
7
        i2c_write(i);        // angabe Zeile
8
        i2c_write(bild1[nr]);      // anzeige array
9
        nr = nr +1;          // array nr um 1 erhöht
10
        _delay_ms(200);
11
        i2c_stop();          // Bus stop
12
      }
13
  }
Dazu übergebe ich dies:
1
Matrix_Write1Bild1Zeit(0);  // schreibt bild1
Damit übergebe ich den Wert 0 und rufe das Programm auf. Innerhalb des 
Programmes wird mit der Zeile 0 begonnen und jede 2 Zeile beschrieben. 
Gleichzeitig wird aus dem Array Bild1 die nr durchgezählt und auf der 
Matrix dargestellt. Damit es langsam von oben nach unten geschoben wird 
ist das delay mit drin.

Das Problem ist die Umsetzung in Multitasking.

1. Versuch
Das delay austauschen - geht gar nichts mehr. z.B. so:
1
int16_t led1=0;
2
  pause++;
3
  if(pause==200)
4
    {
5
      Code      // Schaltet 
6
    }
7
  else  
8
    {    
9
      (pause=0;)
10
    }
Da beide Schleifen verschachtelt sind, klappt es nicht bzw. beeinflussen 
sich gegenseitig
pause wird aus einem Timer mit 1ms gesteuert.
1
if(flag_1ms)
2
  {
3
    flag_1ms=0;
4
    pause++;      
5
    led_blinken1();        // Aufruf Unterprogramm
6
  }
Auch wenn ich die Abfrage über alles lege, geht es nicht.
Da es 8 Zeilen sind und jede Zeile mit eoiner Verzögerung von 200ms 
läuft, ergibt es ca 1,6 Sekunden. Vollkommen ungeeignet,
Leider finde ich keinen Ansatz wie ich die Sache angehen kann.
Es sollen ca. 6 - 8 Matrix laufen. Ohne die Verzögerung geht es ohne 
Probleme.
Atmega124p, 16 MHz, Zeit 1ms, Timer
achim

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Was für ein Multitasking hast du denn?

Wenn du irgendeine Art von RTOS hast, solltest du da einen Timer
starten und an dieser Stelle die Steuerung an das OS abgeben.  Die
genauen Umstände richten sich dann nach dem RTOS.

Wenn du selbstgezimmertes Multitasking machst, brauchst du auch
irgendeine Form von Timer.  Prinzipiell kannst du dort natürlich
einen Hardwaretimer starten und in dessen Interruptroutine dann den
Stop für den I²C-Bus reinpacken, aber meist ist es sinnvoller, ein
allgemeineres Timer-Konzept zu haben, bei dem man jeweils zu bestimmten
Zeitpunkten oder nach bestimmten Zeitdauern etwas tun lassen kann.

Ggf. müsste dies dann mit einem Zustandsautomaten (state machine)
gekoppelt werden, der in diesem Falle zwischen den Zuständen „ruhend“
(nichts auf dem I²C los), „I²C gestartet“ und „I²C wartend“ (als 
nächstes
muss dann der Stop kommen) wechselt.

: Bearbeitet durch Moderator
von Karl (Gast)


Lesenswert?

Ein µC ohne OS macht prinzipiell kein Multitasking. Der arbeitet eine 
Aufgabe nach der anderen ab. Mach einfach einen Timer der eine Variable 
hochzählt. d.h. du zählst nr nicht in der Schleife sondern 
Zeitgesteuert. jedes mal, wenn sich nr geändert hat schreibst du dann 
die neue Zeile über I2C

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl schrieb:
> Ein µC ohne OS macht prinzipiell kein Multitasking.

Das ist zu sehr pauschalisiert.  Sowie Interrupts benutzt werden,
hast du eine gewisse Nebenläufigkeit im Code, die man als Multitasking
ansehen kann.  Kooperatives Multitasking käme sogar ohne Interrupts
aus (und sag nicht, dass kooperatives Multitasking keinen Sinn hätte:
erinnert sei hier an ältere Windows- und MACOS-Versionen).

von achim (Gast)


Lesenswert?

Hallo Jörg
ich verwende einen Timer des 1284 und erzeuge damit eine ms. Einen RTOS 
verwende ich nicht. Bisher habe ich es sogemacht, das alle 
Unterprogramme usw. immer durchlaufen. Als Muster habe ich das 
Multitasking aus dem WIKI genommen. Es geht (fast) alles ohne Probleme. 
Nur leider diese verschachtelten Schleifen nicht. Ich suche einen Ansatz 
wie man das machen kann

Hallo Karl
Karl schrieb:
> d.h. du zählst nr nicht in der Schleife sondern
> Zeitgesteuert.
Das klappt auch nicht, da die nr in Abhängigkeit der Zeilenzahl gesetzt 
wird. nr wird in der Schleife erhöht.

Warum soll Multitasking nicht gehen. Auch mit RTOS habe ich nur einen 
Kern zur Verfügung und kann nur eine Sache ausführen. Über das Thema 
wurde schon lange diskutiert, so von KH oder Falk. Für mich ist es 
wichtig, es geht einfach zu machen, nachvollziehbar und habe neben den 
RTOS noch Platz für meine Programme.
achim

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

achim schrieb:

> Nur leider diese verschachtelten Schleifen nicht. Ich suche einen Ansatz
> wie man das machen kann

Nannte ich dir doch schon: Zustandsautomat.

> Für mich ist es
> wichtig, es geht einfach zu machen, nachvollziehbar und habe neben den
> RTOS noch Platz für meine Programme.

RTOS ist nicht gleichbedeutend mit „platzfressend“.  Die gibt's durchaus
auch recht dünnwandig.  Der Vorteil ist, dass jemand anders den Code
schon debuggt hat. ;-)  Der Nachteil, ja, wenn man nicht auch das RTOS
selbst komplett verstanden haben will, hat man einige „undurchsichtige“
Teile an Code, bei denen man sich einfach nur auf die Doku verlässt.

Aber das mach' ich auf meinem PC auch: wenn ich „rm foo“ eingebe, dann
verlasse ich mich auch drauf, dass anschließend das OS den Namen „foo“
im Dateisystem auflöst, den zu dieser Datei gehörigen Eintrag aus dem
Verzeichnis löscht und, falls dies der letzte Eintrag für diese Datei
war, anschließend alle zu dieser Datei gehörenden Blöcke auf dem
Massenspeicher ausfindig macht und wieder freigibt.  Um das zu benutzen,
muss ich mich nicht damit auseinandergesetzt haben, wie diese Blöcke im
Dateisystem angeordnet sind oder wie die Namenssuche im Detail arbeitet.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Aber das mach' ich auf meinem PC auch: wenn ich „rm foo“ eingebe, dann
> verlasse ich mich auch drauf, dass anschließend das OS den Namen „foo“
> im Dateisystem auflöst, den zu dieser Datei gehörigen Eintrag aus dem
> Verzeichnis löscht und, falls dies der letzte Eintrag für diese Datei
> war, anschließend alle zu dieser Datei gehörenden Blöcke auf dem
> Massenspeicher ausfindig macht und wieder freigibt.

Wenn's so einfach wäre ;-)
1
>foo
2
sleep 500000 <foo &
3
rm foo

;)

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

OK, ich hätte statt „letzter Eintrag“ schreiben sollen „letzte
Referenz“. ;-)

von Falk B. (falk)


Lesenswert?

@ achim (Gast)

>zur Anzeige auf einer LED Matrix mit 8x8 LED mit dem I2C Bus verwende
>ich den folgenden Code. Dieser läuft sehr gut, ohne jedes Problem.

Ist aber dennoch total falsch!

>void Matrix_Write2Bild1Zeit(uint8_t start)  // schreibt bild1
>  {
>    int8_t nr = 0;          // array nr auf 0
>    for (uint8_t i=start; i<16; i+=2)    // Auswahl der Zeile jede 2.
>      {
>        i2c_start(Bild_modul2_addr<<1);  // schreibt modul 1
>        i2c_write(i);        // angabe Zeile
>        i2c_write(bild1[nr]);      // anzeige array
>        nr = nr +1;          // array nr um 1 erhöht
>        _delay_ms(200);
>        i2c_stop();          // Bus stop
>      }
>  }

Wozu für jede Zeile eine komplette I2C Transaktion mit start und stop?
Wozu 200ms Delay am Ende?
Das ist alles goßer Unsinn!
Werder kannst noch willst du dazulernen. Ich hatte dir eine korrekte 
Version für das Beschreiben der LED-Matrix gegschickt, sie hat wunderbar 
funktioniert. Aber aus einem wieder mal sehr irrationalen Grund hat sie 
dir wohl nicht gefallen.

>Leider finde ich keinen Ansatz wie ich die Sache angehen kann.

http://www.nadelspiel.com/stricken/strickmuster/

>Es sollen ca. 6 - 8 Matrix laufen. Ohne die Verzögerung geht es ohne
>Probleme.

Ach so? Oben hast du das Gegenteil behauptet!

>Atmega124p, 16 MHz, Zeit 1ms, Timer

Du hast immer noch nicht verstanden, dass man NICHT zwingend mit 1ms das 
Multitasking machen muss. 10ms oder jeder andere Wert sind OK, wenn es 
für die Aufgabe brauchbar ist.

von achim (Gast)


Lesenswert?

Hallo Falk
die 200ms haben den Grund einer Verzögerten Anzeige. Das Bild wird 
dadurch langsam aufgebaut. Nehme ich 50ms geht es recht zügig. Lasse ich 
die Zeit weg, kommt das Bild sofort. Der verwendte IC lässt max 8 
Adressen beim Bus zu. Habe auf der Platine jetzt 2 ICs drauf und auf 
einer anderen noch mal ein IC. Zusätzlich sind dann noch ca 2 möglich. 
Soweit ich Hardware habe. Wieso habe ich oben was naderes behauptet? Ich 
nutze in dem Prg Tasterentprellung von KH 10 bzw 20 ms für die Taster 
und einige Servos. Dein Programm nutze ich auch. Doch leider bekomme ich 
damit auch kein Multitasking hin. Es geht dabei um die scheinbare 
Darstellung und Bewegung auf verschiedenen Matrix und fast gleichzeitige 
Nutzung anderer Module. Du hast doch selber den Beitrag geschrieben. Ob 
ich jetzt 1 oder 20 ms nutze ist doch fast gleichgültig, hast du selber 
geschrieben. Nutze zufällig gerade 1ms.
Die Zeit hat auch einen anderen einfachen Grund. Mit dieser Verzögerung 
kann ich Bilde von einer Matrix auf eine andere Matrix "schieben", oder 
bilder von oben oder links oder rechts. Dadurch ist eine Laufschrift 
möglich.
Der Hersteller gibt doch selber Matrix mit 7x8 oder andere Grössen an.
Wieso Blödsinn, Teile von diesem Code stammen von dir oder Angaben aus 
dem Datenblatt.
achim

von Falk B. (falk)


Lesenswert?

@ achim (Gast)

>die 200ms haben den Grund einer Verzögerten Anzeige. Das Bild wird
>dadurch langsam aufgebaut.

Wenn das die Absicht ist, ist die Umsetzung dennoch falsch. Wie man es 
richtig macht, hast du schon vor einer kleinen Ewigkeit im Artikel 
Multitasking gesehen.

>und einige Servos. Dein Programm nutze ich auch. Doch leider bekomme ich
>damit auch kein Multitasking hin. Es geht dabei um die scheinbare
>Darstellung und Bewegung auf verschiedenen Matrix und fast gleichzeitige
>Nutzung anderer Module.

Tja, dazu muss man ein paar grundlegende Dinge verstehen, was dir seit 
Jahren leider misslingt.

von uwe (Gast)


Lesenswert?

ein delay zerstört Multitasking, du mußt ohne delay arbeiten mit einem 
Zustandsautomaten und timern.

von Karl H. (kbuchegg)


Lesenswert?

achim schrieb:

> Das delay austauschen - geht gar nichts mehr. z.B. so:
>
1
> int16_t led1=0;
2
>   pause++;
3
>   if(pause==200)
4
>     {
5
>       Code      // Schaltet
6
>     }
7
>   else
8
>     {
9
>       (pause=0;)
10
>     }
11
>
> Da beide Schleifen verschachtelt sind, klappt es nicht

das ist nicht der Grund.
Aber wie üblich bist du wieder mal schlampig in deinen Gedankengängen.

Wie soll denn pause da jemals den Wert 200 kriegen können?
Sobald es ungleich 200 ist, zum Beispiel den Wert 1 nach dem ersten 
erhöhen hat, setzt du es sofort wieder auf 0 zurück. Mit dem Effekt, 
dass pause ständig den Wert 1 bei der Abfrage auf 200 haben wird. 1 ist 
aber nicht gleich 200 und daher ... setzt es dein Codeschnipsel gleich 
wieder auf 0 zurück. Beim nächsten SChleifendurchlauf wird es wieder 
erhöht, hat dann den Wert 1, 1 ist ungleich 200 .... daher wieder auf 0 
setzen. ad infinitum.
1
    pause++;
2
    if(pause==200)
3
     {
4
        Code      // Schaltet
5
        pause = 0;
6
     }

Aber wie schon gesagt: In einer Multitaskung Umgebung, die auf Timern 
basiert (also ohne RTOS welches die Taskmschaltung macht) zieht man das 
alles ganz anders auf.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Karl Heinz (kbuchegg) (Moderator)

>Aber wie üblich bist du wieder mal schlampig in deinen Gedankengängen.

Nur die persistente, gemeine Konfusion.

>Aber wie schon gesagt: In einer Multitaskung Umgebung, die auf Timern
>basiert (also ohne RTOS welches die Taskmschaltung macht) zieht man das
>alles ganz anders auf.

Dazu sollte man aber zuerst mal ein paar Programmiergrundlagen 
beherrschen.

: Bearbeitet durch User
von Karl (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Das ist zu sehr pauschalisiert.  Sowie Interrupts benutzt werden,
> hast du eine gewisse Nebenläufigkeit im Code, die man als Multitasking
> ansehen kann.

O.K. ich hab hatte "meine eigene Definition" von Multitasking, die ehr 
dem Begriff Multiprocessing entsprach.

achim schrieb:
> Hallo Karl
> Karl schrieb:
>> d.h. du zählst nr nicht in der Schleife sondern
>> Zeitgesteuert.
> Das klappt auch nicht, da die nr in Abhängigkeit der Zeilenzahl gesetzt
> wird. nr wird in der Schleife erhöht.

Mach es so:

Der Timer setzt alle 200 ms eine Variable write_line = 1

void Matrix_Write2Bild1Zeit(uint8_t start)  // schreibt bild1
  {
    static int8_t nr = 0;          // array nr auf 0
    static uint8_t i = start
    i2c_start(Bild_modul2_addr<<1);  // schreibt modul 1
    i2c_write(i);        // angabe Zeile
    i2c_write(bild1[nr]);      // anzeige array
    nr = nr +1;          // array nr um 1 erhöht
    i += 2
    i2c_stop();          // Bus stop
    if (i > 16){
      i = 0;
    }
  write_line = 0;
  }

while(1){
  if write_line{
    Matrix_Write2Bild1Zeit();
  }
}


Dann wird alle 200 ms eine Zeile geschickt.

von Achim S. (achims)


Lesenswert?

Hallo
Danke für eure Info und Hilfe.
Multitasking ist kein leichtes Thema. Wie oft hat KH schon gepredigt, 
kein delay.  Vielleicht ist das was ich mache noch blöder oder so, die 
Verbindung von I2C Bus und Multitasking. Nach meinen ersten Aufbauten 
und Programmen, kann ich jetzt schon sagen, es geht. Auch wenn es für 
mich nicht einfach ist. Andere mögen darüber lächeln.
Das mit dem Schlampig hast du recht. Hatte die Sachen nicht weiter 
gedacht. Bin gestern auf das gleiche gekommen. Deshalb auch meine Frage 
nach Denkanstössen oder Richtung.
Als Grundlage ist das Programm von KH und Peter. Ordne alles, wirklich 
alles der Zeit unter. Alle delay fliegen raus.
Danke, melde mich zum Ergebnis
achim

von Achim S. (achims)


Lesenswert?

Karl schrieb:
> void Matrix_Write2Bild1Zeit(uint8_t start)  // schreibt bild1
>   {
>     static int8_t nr = 0;          // array nr auf 0
>     static uint8_t i = start

Damit wird bei jedem Aufruf nr und i auf 0 gesetzt und die ganze Anzeige 
bleibt in der Zeile 0 hängen.

von nga (Gast)


Lesenswert?

Achim Seeger schrieb:
> Damit wird bei jedem Aufruf nr und i auf 0 gesetzt und die ganze Anzeige
> bleibt in der Zeile 0 hängen.

Schlüsselwort static net verstanden...

von Achim S. (achims)


Lesenswert?

Nach handbuch C bedeutet static, das man diese Funktion nur innerhalb 
der datei verwendet werden kann in der sie definiert wurde.
Das ist aber nicht das Problem.
Wenn ich es z.B. so schreibe:
1
void HT16K33_Write2Bild1Zeit(uint8_t start)  // schreibt bild1
2
    {
3
  static int8_t nr;  // array nr auf 0
4
  int8_t i;  
5
  if(start<2)
6
    {
7
      i=start;
8
    }
9
  i2c_start(HT16K33_modul2_addr<<1);  // schreibt modul 1        
10
        i2c_write(i);        // angabe Zeile
11
  i2c_write(bild1[nr]);      // anzeige array
12
        i2c_stop();        // Bus stop  
13
  nr = nr+1;        // array nr um 1 erhöht
14
  i += 2;
15
  if (i > 16)
16
    {
17
      i = 0;
18
      nr = 0;
19
    }
Damit begrenze ich die Eingabe auf Beginn der Zeilen 0 und 1. Bei jedem 
Durchlauf soll i um 2 erhöht werden. Ich starte es aber immer bei 0 oder 
1 neu, da alle 200ms ein neuer Aufruf der Funktion erfolgt. Dabei muss 
das begrenzt werden und darf erst wieder auf 0 gehen wenn i=16 erreicht 
wurde, nur beim ersten mal nicht. Jetzt bleibt i in der Zeile 0 hängen 
und zählt 0 nicht hoch.
achim

von Markus F. (mfro)


Lesenswert?

Achim Seeger schrieb:
> Nach handbuch C bedeutet static, das man diese Funktion nur innerhalb
> der datei verwendet werden kann in der sie definiert wurde.

Du solltest dein Buch ein bißchen genauer lesen (oder, wenn's nicht 
drinsteht, wegschmeißen und ein anderes kaufen).

"static" hat innerhalb von Funktionen eine andere Bedeutung als 
außerhalb (die, die Du - richtig - erlesen hast).

Und natürlich ist "static" keine Funktion, sondern ein Schlüsselwort 
bzw. eine Speicherklasse. Was das ist, sollte auch in deinem Buch 
stehen, sonst -> Tonne.

von Achim S. (achims)


Lesenswert?

Hallo Markus
Danke für die Info. Das Buch braucht nicht gleich in die Tonne. Werde 
die Stelle suchen und lesen. Leider ist mir der Unterschied bisher nicht 
klar gewesen.
achim

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.