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
Probiers mal mit Division... und das nächste Mal poste ins richtige Forum.
> 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.
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
> 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...
1 | for(;;){ |
2 | |
3 | // einfach wiederholend rückwärts
|
4 | Carry1 = ( lauflicht1 < 3 ); |
5 | lauflicht1 /= 2; |
6 | lauflicht1 |= (Carry1>>7); |
7 | |
8 | }
|
geht zum Beispiel.
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:
1 | char z = (128 > 4); //z = 1 |
bzw
1 | char y = (4 > 128); //y = 0 |
Ach, das soll eine "1" geben, wenn lauflicht1 kleiner als 3 ist... Der €uro fällt heute centweise... Ist natürlich korrekt.
@Simon: Jau, habs grad gemerkt... Wie gesagt:
1 | #define EURO 100
|
2 | #define CENT 1
|
3 | |
4 | for(unsigned int cents = CENT; cents <= EURO; cents += CENT) |
5 | {
|
6 | pling(); |
7 | }
|
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
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?
> 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.
> 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.
> 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.
1 | unsigned char lauflicht0 = 1, lauflicht1 = 0, direction = 1; |
2 | |
3 | |
4 | void lauflicht( void ) |
5 | {
|
6 | if( direction ){ |
7 | lauflicht1 <<= 1; |
8 | lauflicht1 |= lauflicht0 >> 7; |
9 | lauflicht0 <<= 1; |
10 | direction = ~lauflicht1 & 0x80; // 0 on 1000.0000.0000.0000 |
11 | }else{ |
12 | lauflicht0 >>= 1; |
13 | lauflicht0 |= lauflicht1 << 7; |
14 | lauflicht1 >>= 1; |
15 | direction = lauflicht0 & 0x01; // 1 on 0000.0000.0000.0001 |
16 | }
|
17 | }
|
Peter
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.