Forum: Compiler & IDEs Zähler ausrollen lassen


von Achim S. (achims)


Lesenswert?

Hallo
In C verwende ich bisher immer einen Zähler, nach diesem Beispiel

for (farbe=0; farbe <4; farbe++)

Damit kann ich die Farben und LED ändern. Es ist dabei immer die gleiche 
Geschwindigkeit.
Wie kann ich es aber machen, das sich die Geschwindigkeit verändert. So 
nach dem Muster eines Würfels. Beim würfeln kommen die ersten Zahlen 
sehr schnell und wird dann immer langsamer, bis zum Stillstand.
Habe nichts dazu gefunden. Hat jemand eine Idee?
achim

von Lukas T. (tapy)


Lesenswert?

for (farbe=0; farbe <4; farbe++)
  for (i=farbe; i >0; i--)
    warte_50ms

von Achim S. (achims)


Lesenswert?

Hallo Lukas
verstehe deine Sache nicht ganz. Bis her habe ich so gemacht (mehr 
Code). Dabei verwende ich bereits 2 Zähler und eine delay.
1
if (get_input_bit(IO_INPUT_1))            // Abfrage S3 Port
2
   delay(20);                             // Pause Entprellung 20 ms
3
   if (get_input_bit(IO_INPUT_1))         // Abfrage S3 bei loslassen 
4
   while (get_input_bit(IO_INPUT_1))      // Wiederholung Schleife
5
   {  }                    
6
:
7
:
8
:
9
10
int farbe;             // Variable farbe
11
     for (farbe=0; farbe<4; farbe++)      // Zähler farbe von 0 bis 3 
12
       {         // 0 = aus, 1 = grün. 2 = rot,3 = orange
13
         int ledNr;    // Variable ledNr
14
         for (ledNr=7; ledNr>-1; --ledNr)   // Zähler ledNr von 7 bis 0
15
           {
16
             leds_set_status(farbe, ledNr);  // setzt entsprechende LED
17
             delay(150);      // Pause 150 ms
18
           }
19
       }
In diesem Stück laufen die Farben von 0 bis 3 und die LED von 0 bis 7. 
Beide Zähler sind in einander. Das ganze soll nach ca. 5 s langsam 
ausrollen. Der Start erfolgt dabei mit S3
achim

von Karl H. (kbuchegg)


Lesenswert?

'Ausrollen' beduetet, dass deine Delay Zeiten nach und nach größer 
werden. D.h. du überlegst dir eine Abhängigkeit, wie du das von der 
Anzahl der Durchgänge durch die Schleifen abhängig machst.

Zudem ist die ganze Sache mit den ineinander geschachtelten Schleifen 
nicht so prickelnd, wenn du erst mal ca 5 Sekunden 'rollen' lassen will.

D.h. vereinfache die Sache erst mal soweit, dass du dir sowas wie einen 
'Durchgang' definierst. Ein Durchgang ist nichts anderes als das 
weiterschalten auf die Nächste Farben/LED Kombination. D.h. mit jedem 
Durchgang wird auf die nächste Kombination weitergeschaltet. Ziel ist 
es, die hier eher unhandlichen ineinander geschachtelten Schleifen 
loszuwerden.
Wie geht das?
Zb. so (Achtung: das ist nicht die endgültige Version, sondern erst mal 
nur ein Ansatz, der weiter ausgebaut wird)
1
  ledNr = 0;
2
  farbe = 0;
3
4
  while( 1 )
5
  {
6
    ledNr++;
7
    if( ledNr == 8 )
8
    {
9
      ledNr = 0;
10
      farbe++;
11
      if( farbe == 4 )
12
        farbe = 0;
13
    }
14
15
    leds_set_status(farbe, ledNr);
16
    delay(150);
17
  }

Die Weiterschaltungslogik von LED und Farben funktioniert genau gleich, 
wie zum Beispiel die Weiterschaltung von Sekunden und Minuten bei einer 
Uhr. Genau das gleiche System. Der springende Punkt ist, dass du den 
Vorgang 'weiterschalten zum nächsten Zustand' dir als eine Operation 
machst. Bei einer Uhr ist das eben 1 Sekunde mehr, woraus sich eine neue 
Sekunde und Minute ergibt und bei dir ist es eben 1 Led mehr, woraus 
sich eine neue Led/Farbe Kombination ergibt.

Gut. Damit hast du jetzt erst mal eine einzige Schleife, die alles 
steuert. Und genau das willst du ja auch. Denn jetzt geht es darum, dass 
diese Schleife nach ca. 5 Sekunden aufhören soll. 5 Sekunden, das sind 
bei ca. 150 Millisekunden pro Schleifendurchlauf daher 5000 / 150 gleich 
33 Wiederholungen. Also baust du die Endlosschleife erst mal auf eine 
Schleife um, die 33 Wiederholungen macht
1
  ledNr = 0;
2
  farbe = 0;
3
4
  for( durchgang = 0; durchgang < 33; durchgang++ )
5
  {
6
    ledNr++;
7
    if( ledNr == 8 )
8
    {
9
      ledNr = 0;
10
      farbe++;
11
      if( farbe == 4 )
12
        farbe = 0;
13
    }
14
15
    leds_set_status(farbe, ledNr);
16
    delay(150);
17
  }

Das sollte sich jetzt um die ca. 5 Sekunden kümmern. Erst mal. Die Frage 
ist, ob man das universeller machen kann?
Kommt drauf an. Wenn mir die 5 Sekunden wichtig sind, und ich nicht viel 
rechnen will und vor allen Dingen weil ich weiß, dass ich die delay 
Zeiten in weiterer Folge variieren möchte (wegen dem Ausrollen), zieh 
ich mir die ominösen 5 Sekunden direkt in den Code hinein. Zb so
1
  ledNr = 0;
2
  farbe = 0;
3
4
  laufZeit = 0;
5
6
  while( laufZeit < 5000 )
7
  {
8
    ledNr++;
9
    if( ledNr == 8 )
10
    {
11
      ledNr = 0;
12
      farbe++;
13
      if( farbe == 4 )
14
        farbe = 0;
15
    }
16
17
    leds_set_status(farbe, ledNr);
18
19
    delay(150);
20
    laufZeit += 150;
21
  }

Auch das ergibt wieder die ca. 5 Sekunden. Aber diesmal indem die 
verstrichene Zeit seit Beginn mitgezählt wird. Ich brauch immer nur 
sicher stellen, dass die delay Zeit auch auf ledZeit aufgeschlagen wird 
und irgendwann lande ich dann bei einem Wert der größer als die ominösen 
5 Sekunden (5000 Millisekunden) wird und damit ist dann alles zu Ende.

So weit so gut.
Jetzt möchtest du aber auslaufen lassen. Auslaufen bedeutet nichts 
anderes, als das die delay Zeiten größer werden. D.h. du brauchst eine 
Abhängigkeit. Sagen wir einfach mal nach 2 Sekunden sollen die delay 
Zeiten doppelt so lange sein
1
  ledNr = 0;
2
  farbe = 0;
3
4
  laufZeit = 0;
5
6
  while( laufZeit < 5000 )
7
  {
8
    ledNr++;
9
    if( ledNr == 8 )
10
    {
11
      ledNr = 0;
12
      farbe++;
13
      if( farbe == 4 )
14
        farbe = 0;
15
    }
16
17
    leds_set_status(farbe, ledNr);
18
19
    if( laufZeit < 2000 )
20
    {
21
      delay(150);
22
      laufZeit += 150;
23
    }
24
    else
25
    {
26
      delay(300);
27
      laufZeit += 300;
28
    }
29
  }

Da die Schleifensteuerung über das mitsummieren der Delay Zeiten gemacht 
wird, ergibt das wieder die 5 Sekunden, ohne dass ich groß was tun muss. 
Ich muss nur drauf achten, dass ich auch wirklich die jeweilige Delay 
Zeit auch zur Variablen laufZeit dazuzähle.

Jetzt kenn ich deine delay Funktion nicht, ob die so gestaltet ist, dass 
man der eine Variable übergeben darf. Ich nehme mal, dass dem so ist. 
D.h. ich kann das vereinfachen und mich erst mal von diesem Zusammenhang 
DelayZeit und Laufzeit summieren befreien, bzw. das so machen, dass ich 
es nicht vergessen kann.
1
  ledNr = 0;
2
  farbe = 0;
3
4
  laufZeit = 0;
5
6
  while( laufZeit < 5000 )
7
  {
8
    ledNr++;
9
    if( ledNr == 8 )
10
    {
11
      ledNr = 0;
12
      farbe++;
13
      if( farbe == 4 )
14
        farbe = 0;
15
    }
16
17
    leds_set_status(farbe, ledNr);
18
19
    if( laufZeit < 2000 )
20
      delayZeit = 150;
21
    else
22
      delayZeit = 300;
23
24
    delay( delayZeit );
25
    laufZeit += delayZeit;
26
  }

Was habe ich jetzt erreicht?
Was ich erreicht habe ist, dass ich mir irgendwas ausdenken kann, wie 
ich die Delay Zeit von der bereits verstrichenen Laufzeit abhängig 
mache. Zb könnte ich sagen: bis 2 Sekunden läuft alles mit 150 
Millisekunden. Ab 2 Sekunden wird zum Beispiel die DelayZeit mit jedem 
Durchgang um 10 Millisekunden länger. Da gibt es jetzt mehrere 
Möglichkeiten. Man könnte das direkt ausrechnen, man kann aber auch 
einfach die delayZeit einfach immer nur um ca. 10 Millisekunden länger 
machen.
1
    ...
2
3
    if( laufZeit < 2000 )
4
      delayZeit = 150;
5
    else
6
      delayZeit += 10;
7
8
    ...

Der Rest des Programms ist so umgeformt worden, dass ich hier an dieser 
Stelle mit dieser Delay Zeit machen kann was ich will, die Led und die 
Farben laufen trotzdem weiter und die 5 Sekunden werden auch (so 
einigermassen) eingehalten.
D.h. du kannst hier an dieser Stelle kreativ werden und dir Verfahren 
und Algorithmen ausdenken, aufgrund welcher Zusammenhänge du die Delay 
Zeit länger machen willst. Zum Beispieil indem die Delay Zeit nicht um 
10 Millisekunden länger wird, sondern sich von Durchgang zu Durchgang 
verdoppelt (aufpassen, das das nicht überläuft!)
1
    ...
2
3
    if( laufZeit < 2000 )
4
      delayZeit = 150;
5
    else if( delayZeit < 16383 )
6
      delayZeit *= 2;
7
8
    ...

Oder nicht verdoppeln, sondern zb nur mal 2/3 rechnen, damit es nicht 
gar so schnell wächst. Oder ....

Hier ist dir jetzt Tür und Tor geöffnet, und du kannst verschiedene 
Dinge ausprobieren.

von Achim S. (achims)


Lesenswert?

Hallo Karl Heinz
erst ein mal Danke für deine Antwort. Hatte damit gerechnet, das es so 
viel ist. Hast aber vollkommen recht. Da habe viel zu lesen. Werde es 
durcharbeiten und entsprechend machen. Gebe dir Antwort und Prg dazu.
Achim

PS deine Tasterentprellung und das Multitasking arbeiten hervorragend, 
sogar auf einem ATmega 128. Danke

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:

> viel ist. Hast aber vollkommen recht. Da habe viel zu lesen. Werde es
> durcharbeiten

Genau darum gehts.
Um den Einstieg wie man sich die Sachen beispielsweise organisiert, 
damit sie handhabbar werden. D.h. sieh das als Vorschlag an und 
entwickle dann dein eigenes System.

von Achim S. (achims)


Lesenswert?

Hallo Karl Heinz
bin beim lesen und testen. Wie es sich gehört habe ich deine Sachen 
genommen und fleissig weiter gemacht. Ein paar sachen sind mir 
aufgefallen. Versuche es mal zu erklären.
1
ledNr = 0;
2
  farbe = 0;
3
4
  for( durchgang = 0; durchgang < 33; durchgang++ )
5
  {
6
    ledNr++;
7
    if( ledNr == 8 )
8
    {
9
      ledNr = 0;
10
      farbe++;
11
      if( farbe == 4 )
12
        farbe = 0;
13
    }
14
15
    leds_set_status(farbe, ledNr);
16
    delay(150);
17
  }

Du verwendest durchgang und zählst damit bis 32. Das delay bleibt aber 
bei 150. Damit verändert sich die Pausenzeit gar nicht.
1
for(durchgang=0;durchgang<5000;durchgang++)
2
:
3
:
4
leds_set_status(farbe, ledNr);  // setzt entsprechende LED
5
delay(durchgang);          // Pause 150 ms
6
durchgang +350;
Damit bekomme ich eine deutliche Veränderung der Zeit. Die Zeiten die 
drin stehen sind nur zum testen. Was mir aber noch aufgefallen ist. Am 
Ende stoppt es nicht sondern läuft mit langsamer Geschwindigkeit weiter.
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.