mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Lauflicht mit Carry Bit in C


Autor: Tobias Tetzlaff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich hatte schon mal nachgefragt, wie ich ein Lauflicht realisieren kann.

Ich habe 2 8Bit Schieberegister, auf denen ich eine LED "wandern" lassen 
will.

Mit diesem Code geht es in eine Richtung:

char lauflicht1 = 0x01;
char lauflicht2 = 0x00;

Carry1 = ( lauflicht1 > 127 );
  lauflicht1 *= 2;

  Carry2 = ( lauflicht2 > 127 );
  lauflicht2 = ( lauflicht2 * 2 ) | Carry1;

    lauflicht1 |= Carry2;

...
...
Ausgabe auf Schieberegister.

Nun meine Frage:

Wenn lauflicht2 den wert 0x80 hat, also die letzte LED leuchtet,
wie bekomme ich es hin, das das Lauflicht andersrum läuft, bis 
lauflicht1 den Wert 0x01 hat ???
Von hier aus soll es wieder von vorn beginnen.

Danke im Vorraus...

Gruß Toby

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probiers mal mit Division...
und das nächste Mal poste ins richtige Forum.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> wie bekomme ich es hin, das das Lauflicht andersrum läuft, bis
> lauflicht1 den Wert 0x01 hat ???
> Von hier aus soll es wieder von vorn beginnen

Schnapp dir Papier und Bleistift und spiele
obigen Code mal am Papier durch. Wichtig:
Da es dir auf die Bits ankommt, schreibe alle
Zahlen binär an!

Wenn du verstanden hast, wie obiges funktioniert
dann sollte es für dich ein leichtes sein, die
Richtung umzudrehen.
Wieder: zuerst am Papier durchspielen was passieren
muss. Wenn du dann eine klare Vorstellung davon hast
was in welcher Reihenfolge passieren muss, dann ist
es Zeit das Ganze in C zu giessen.

Autor: Tobias Tetzlaff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,

ich habe nun folgendes mal im AVR Studio in Einzelschritt durchlaufen 
lassen:

unsigned char lauflicht1 = 128;
unsigned char Carry1, Carry2;

int main(void){
for(;;){
  // einfach wiederholend
  Carry1 = ( lauflicht1 > 127 );
  lauflicht1 *= 2;
  lauflicht1 |= Carry1;

}
}

Sobald lauflicht1 128 ist, wird Carry1 1.
lauflicht1 wird 0, lauflicht1 wird 1, Carry1 wird 0.


Nun habe ich folgendes probiert:

unsigned char lauflicht1 = 128;
unsigned char Carry1, Carry2;

int main(void){
for(;;){

  // einfach wiederholend rückwärts
  Carry1 = ( lauflicht1 < 3 );
  lauflicht1 /= 2;
  lauflicht1 |= Carry1;

}
}

Dabei wird Carry1 1, wenn lauflicht1 1 ist.
Aber eigentlich sollte Carry1 128 werden, nur wieß ich nicht, wie ich 
das hinbekomme.

Kannst du mir eine kleine Hilfe geben?

Müsste ja irgendwie so werden:
if (Carry1 = ( lauflicht1 < 3 )){
Carry1 = 128;
}

Aber dann hab ich ja wieder ein if drin!

Gruß Toby

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Carry1 = ( lauflicht1 > 127 );
> Carry1 = ( lauflicht1 < 3 );
Was sollen diese Anweisungen bewirken? Das "<" und das ">" sind 
Vergleichsoperatoren. Das müsste einen dicken Fehler geben. Wenn das 
Shift-Operatoren sein sollen, dann "<<" und ">>". Wenn man versucht, 
einen unsigned char um 127 Stellen zu verschieben, kommt aber in jedem 
Fall 0 raus...

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
for(;;){

  // einfach wiederholend rückwärts
  Carry1 = ( lauflicht1 < 3 );
  lauflicht1 /= 2;
  lauflicht1 |= (Carry1>>7);

}

geht zum Beispiel.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
johnny.m wrote:
>> Carry1 = ( lauflicht1 > 127 );
>> Carry1 = ( lauflicht1 < 3 );
> Was sollen diese Anweisungen bewirken? Das "<" und das ">" sind
> Vergleichsoperatoren. Das müsste einen dicken Fehler geben. Wenn das
> Shift-Operatoren sein sollen, dann "<<" und ">>". Wenn man versucht,
> einen unsigned char um 127 Stellen zu verschieben, kommt aber in jedem
> Fall 0 raus...

Nee, das ist schon richtig so. Das Ergebnis aus den 
Vergleichsoperationen ist ja entweder 1 oder 0.

Sprich:
 char z = (128 > 4); //z = 1
bzw
 char y = (4 > 128); //y = 0

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach, das soll eine "1" geben, wenn lauflicht1 kleiner als 3 ist... Der 
€uro fällt heute centweise... Ist natürlich korrekt.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Simon:
Jau, habs grad gemerkt... Wie gesagt:
#define EURO 100
#define CENT 1

for(unsigned int cents = CENT; cents <= EURO; cents += CENT)
{
    pling();
}

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
*lacht.

Ja genau :-)

Autor: Tobias Tetzlaff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Simon,

hierbei :

Carry1 = ( lauflicht1 < 3 );
  lauflicht1 /= 2;
  lauflicht1 |= (Carry1>>7);


bleibt Carry1 immer 1, und lauflicht1 bleibt 0 !

Dann muß man wohl andersrum schieben:

Carry1 = ( lauflicht1 < 1 );
  lauflicht1 /= 2;
  lauflicht1 |= (Carry1<<7);

Allerdings sind im Vorwärtsbeispiel von K.H. die LEDs nie aus.
Beim Rückwärtslauf sind die LEDs einmal ganz aus.

Im übrigen muß es Carry1 = ( lauflicht1 < 1 ); und nicht Carry1 = ( 
lauflicht1 < 3 ); heißen, da sonst einmal LED 7 und 0 an sind.

Ganz davon abgesehen,
wenn ich ein Lauflicht daraus machen will, welches ständig auf und ab 
läuft,
muß ich doch eine weitere Variable nehmen, die definiert, ob auf oder 
abwärts gezählt wird, da sonst die beiden Rechnungen sich gegenseitig 
aufheben, ist das richtig?

Gruß Toby

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tobias Tetzlaff wrote:
> Hallo Simon,
>
> Dann muß man wohl andersrum schieben:
>
> Carry1 = ( lauflicht1 < 1 );
>   lauflicht1 /= 2;
>   lauflicht1 |= (Carry1<<7);

Verdammt, du hast Recht. Dass mir sowas mal passiert ;)

PS: Gibts eigentlich keine Möglichkeit unter C an die Rotate-Befehle im 
AVR ranzukommen?

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Carry1 = ( lauflicht1 > 127 );

Die Idee dahinter ist Folgende:

Wenn ich mir 8 Bit Binärzahlen anschaue

    00000000   = 0
    00000001   = 1
    00000010   = 2
    00000100   = 4
    00001000   = 8
    ...
    01000000   = 64
    ...
    01111110   = 126
    01111111   = 127
    10000000   = 128
    10000001   = 129
    10000010   = 130
    ...
    11111110   = 254
    11111111   = 255

Dann fällt auf, dass das am weitesten links stehende Bit
bei allen Zahlen größer als 127 immer 1 ist.

Genau dieses Bit brauchen wir aber. Wenn die 8 Bit Zahl
um 1 stelle nach links geshiftet wird, dann geht uns dieses
Bit verloren. Wir brauchen es aber, da wir es ja rechts wieder
einfügen wollen.
Eigentlich wollen wir ja Folgendes machen (um ein 8 Bit
lauflicht zu realisieren)

  wir nehmen die 8 Bit                 zb   01010100

  und unterteilen sie in
  2 Bereiche: Das am weitesten
  links stehende Bit und den
  Rest                                     0 1010100

  Das am weitesten links stehende
  Bit legen wir mal zur Seite
  und der Rest wird um 1 Stelle
  nach links geschoben                0     1010100x

 (Das x symbolisiert nur, dass da eine
  Stelle 'aus dem Nichts' nachgerutscht ist)

  Danach nehmen wir das zur Seite
  gelegte Bit und fügen es am
  rechten Ende als Bit 0 wieder ein         10101000

Wenn du jetzt mit dem Bitmuster vergleichst, mit dem wir gestartet
sind, dann sind alle Stellen um 1 nach links gerutscht und
das oberste Bit unten wieder drann. Genauso wie es bei einem
lauflicht sein soll.

Machen wir die Opertion nach mal

        10101000

      1  0101000

      1 0101000x

        01010001

und noch mal

        01010001
      0  1010001
      0 1010001x
        10100010

und nochmal

        10100010
      1  0100010
      1 0100010x
        01000101

und so dreht sich das Bitmuster immer im Kreis.

Ein wesentlicher Bestandteil war aber, das am weitesten links
stehende Bit abzutrennen (seinen Wert festzustellen). Und da
kommt jetzt die Erkentnis von oben ins Spiel. Aus der Tabelle
haben wir gesehen, dass der Vergleich x < 127 immer dann
eine 1 ergibt, wenn das am weitesten links stehende Bit
auch eine 1 ist.

Natürlich hätte man das auch anders machen können. Zb.
mit einer Bitmaskierung.

   if( x & 0b10000000 )
     Carry = 1;
   else
     Carry = 0;

würde genau das gleiche machen. Der & Operator verknüpft
alle gleichwertigen Bits mit einem UND und liefert das Ergebnis

      10010111
 &    00101100
     ---------
      00010100

Im Ergebnis findet sich nur dort eine 1 wieder wo sowohl
in der ersten Zahl als auch in der zweiten Zahl eine 1 war.

Bei uns wäre das

      10101000
  &   10000000
      --------
      10000000

bzw.

      01010001
  &   10000000
      --------
      00000000

Das Ergebnis dieser & Verknüpfung ist genau dann 0 wenn
das linkste Bit ebenfalls 0 ist. Ansonsten ist das Ergebnis
0b1000000.

Jetzt nutzen wir noch aus, dass in C 0 immer auch einem
logischem Falsch entspricht und alles andere ist logisch wahr
und kommen zu:

   if( x & 0b10000000 )
     Carry = 1;
   else
     Carry = 0;



Ich denke mal, dass sollte deine Probleme soweit mildern,
dass du das Lauflicht umdrehen kannst und auch weisst, was
du dabei tust.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Im übrigen muß es Carry1 = ( lauflicht1 < 1 ); und nicht Carry1 = (
> lauflicht1 < 3 ); heißen, da sonst einmal LED 7 und 0 an sind.

In dem Fall kommt man mit einem Vergleich überhaupt
nicht weiter. Es gibt keinen einfachen Vergleich
(ohne zusätzliche Arithmetik) der mir immer und
überall sagen würde ob das LSB gesetzt ist oder nicht.

Die Abfrage würde zb so aussehen:

    if( x % 2 == 0 )
      Carry = 0
    else
      Carry = 1

oder kürzer:

    Carry = ( x % 2 );

Normalerweise optimieren das Compiler auch tatsächlich
intern zu einer & Maskierung, wie oben gezeigt.
ich finde aber, dass an dieser Stelle eine explizite
Maskierung ala

   Carry = ( x & 0b00000001 );

klarer ist.
So wird besser ausgedrückt, dass es um den Zustand
des untersten Bits geht.



Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> wenn ich ein Lauflicht daraus machen will, welches ständig auf und
> ab läuft, muß ich doch eine weitere Variable nehmen, die definiert,
> ob auf oder abwärts gezählt wird, da sonst die beiden Rechnungen
> sich gegenseitig aufheben, ist das richtig?

Ja das stimmt. Im allgemeinen Fall kommst du um eine
zusätzliche Variable nicht herum.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned char lauflicht0 = 1, lauflicht1 = 0, direction = 1;


void lauflicht( void )
{
  if( direction ){
    lauflicht1 <<= 1;
    lauflicht1 |= lauflicht0 >> 7;
    lauflicht0 <<= 1;
    direction = ~lauflicht1 & 0x80;     // 0 on 1000.0000.0000.0000
  }else{
    lauflicht0 >>= 1;
    lauflicht0 |= lauflicht1 << 7;
    lauflicht1 >>= 1;
    direction = lauflicht0 & 0x01;      // 1 on 0000.0000.0000.0001
  }
}


Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.