Forum: Mikrocontroller und Digitale Elektronik verständnisfrage zu bit schieben


von Stk 500 anfänger (Gast)


Lesenswert?

hallo, bin gerade dabei mich in das thema lcd ansteuerung einzuarbeiten 
und um dies besser zu verstehen, untersuche ich gerade das LCD- 
ansteuerungsprogramm im AVR- GCC tutorial.

größtenteils ist mir die ansteuerung bzw. programmierung einleuchtend. 
nur hänge ich an einigen stellen in bezug auf bits, welche verschoben 
werden:

- hier zum beispiel:
1
LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
2
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
LCD_PORT wird in der Headerdatei mit DDRD ersetzt und LCD_DB mit PD0. 
aber was wird in diesen Zeilen jetzt genau gemacht? 0xF0 ist ja das 
gleiche wie 0b00001111 aber was wird dann mit anders DDRD &=~(0b00001111 
>> (4- PD0)) genau gemacht?
ich denke wenn ich das verstehen würde, würde ich auch die untere zeile 
verstehen.


wo ich auch noch arge verständisprobleme habe ist dieser Abschnitt:
1
lcd_out( data );             // zuerst die oberen, 
2
    lcd_out( data<<4 );           // dann die unteren 4 Bit senden
in der variabe data befindet sich ja eine 8- bit variable, welche an die 
funktion lcd_out() übergeben wird (so viel zur ersten zeile). aber was 
macht jetzt genau lcd_out( data<<4 ); ?
was macht da vor allen dingen die schreibweise (data<<4) ?
kann es sein, dass hier die einzelnen bits in der variable um 4 stellen 
nach rechts verschoben werden?
bedeutet << eigentlich nicht nach links schieben?


mfg andi

von Stk 500 anfänger (Gast)


Lesenswert?

........................................................

von Karl H. (kbuchegg)


Lesenswert?

Stk 500 anfänger schrieb:

> - hier zum beispiel:
>
1
> LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
2
>     LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
3
>
> LCD_PORT wird in der Headerdatei mit DDRD ersetzt und LCD_DB mit PD0.
> aber was wird in diesen Zeilen jetzt genau gemacht? 0xF0 ist ja das
> gleiche wie 0b00001111

Nein

> aber was wird dann mit anders DDRD &=~(0b00001111
>>> (4- PD0)) genau gemacht?

rechne es dir aus.
probiers mit einem Wert von 0 für LCD_DB
probiers mit einem Wert von 1 für LCD_DB

formuliere eine Hypothese

probiers mit einem Wert von 2 und dann noch mit einem Wert von 3 für 
LCD_DB und sieh nach ob deine Hypothese stimmt.

So analysiert man Code

> ich denke wenn ich das verstehen würde, würde ich auch die untere zeile
> verstehen.

Dann probiers aus.
Dadurch, dass dir das hier immer wieder jemand vorkaut lernst du nichts.


> wo ich auch noch arge verständisprobleme habe ist dieser Abschnitt:
>
1
lcd_out( data );             // zuerst die oberen,
2
>     lcd_out( data<<4 );           // dann die unteren 4 Bit senden
3
>
> in der variabe data befindet sich ja eine 8- bit variable, welche an die
> funktion lcd_out() übergeben wird (so viel zur ersten zeile).

Ja.
Und was macht die Funktion lcd_out als erstes mit den übergebenen 8 Bit?

> aber was
> macht jetzt genau lcd_out( data<<4 ); ?

was macht denn    data << 4

und was macht daher lcd_out, wenn man ihm das übergibt?

> was macht da vor allen dingen die schreibweise (data<<4) ?

Das solltest du jetzt aber eigentlich schon erkennen.

  a << b

schiebt die Bits in a um b Stellen nach links

> kann es sein, dass hier die einzelnen bits in der variable um 4 stellen
> nach rechts verschoben werden?

links.
Deshalb zeigt auch der (gedachte) Pfeil nach links.
Nach rechts schieben wäre  >>, weil hier der (gedachte) Pfeil nach 
rechts zeigt. Ist doch nicht so schwer zu merken

von Stk 500 anfänger (Gast)


Lesenswert?

mit diesem codeschnipsel hab ich jetzt mal das mit dem bit schieben mal 
ganz unabhängig vom LCD am STK500 ausprobiert:
1
 while (1)
2
  {
3
4
PORTB = 0xF0;    //entspricht 0b11110000 => LED0-3 an
5
6
 long_delay(1000);
7
8
 PORTB   &=~ (0xF0 >>3);    //entspricht 0b11100000
9
10
 long_delay(1000);
11
12
PORTB = 0xF0;     //entspricht 0b11110000
13
14
long_delay(1000);
15
16
PORTB |= (0xF0 >> 3);    //entspricht 0b11111110
17
18
long_delay(1000);
19
20
21
  }

das ergebnis des schiebens habe ich mit den LEDs am STK kontrolliert. 
das rechts schieben mit
PORTB |= (0xF0 >> 3); funktionert (hier werden ja bei 0b11110000 von 
links aus 3 mal eine 1 eingeschoben und so die bits nach rechts 
verschoben).

aber das mit PORTB   &=~ (0xF0 >>3); funktioniert nicht wie ich es mir 
vorstelle. analog zu PORTB |= (0xF0 >> 3); müsste hier ja jetzt von 
links aus 3 mal eine 0 eingefügt werden und so die bits nach rechts 
verschoben werden.
tut es aber nicht (siehe code).

wo liegt mein denkfehler?

mfg

von STK500-Besitzer (Gast)


Lesenswert?

>PORTB = 0xF0;    //entspricht 0b11110000 => LED0-3 an

Du solltest beachten, dass beim STK500 eine "1" am Ausgang die LED 
ausschaltet.

>aber das mit PORTB   &=~ (0xF0 >>3); funktioniert nicht wie ich es mir
vorstelle.

Zerlege die Zeile mal:

(0xF0 >> 3)  :         0b00011110
~(0xF0 >> 3) :         0b11100001

PORTB = 0xF0
PORTB &= ~(0xF0 >> 3)
0b11110000 & 0b11100001 = 11100000

wenn ich mich jetzt nicht vertippt habe.

von Stk 500 anfänger (Gast)


Lesenswert?

STK500-Besitzer schrieb:
>>PORTB = 0xF0;    //entspricht 0b11110000 => LED0-3 an
>
> Du solltest beachten, dass beim STK500 eine "1" am Ausgang die LED
> ausschaltet.

das weiß ich schon. es ist doch richtig, dass beim STK500 bei PORTB = 
0xF0; LED0-3 an sind, oder?

STK500-Besitzer schrieb:
> Zerlege die Zeile mal:
>
> (0xF0 >> 3)  :         0b00011110
> ~(0xF0 >> 3) :         0b11100001
>
> PORTB = 0xF0
> PORTB &= ~(0xF0 >> 3)
> 0b11110000 & 0b11100001 = 11100000
>
> wenn ich mich jetzt nicht vertippt habe.

ich verstehe jetzt nicht wirklich was mir dieser vorschlag sagen soll.


ich hab jetzt mein testprogramm nochmal ein wenig vereinfacht:
1
PORTB = 0xF0;    //entspricht 0b11110000 => LED0-3 an
2
3
 long_delay(1000);
4
5
 PORTB   &=~ (0xF0 <<3);   //entspricht 0b01110000 => LED0,1,2,3 und 7 an
6
7
 long_delay(1000);

im kommentar hab ich jetzt mal geschrieben was PORTB &=~ (0xF0 <<3); mit 
meinen LEDs macht. aber irgendwie finde ich das nicht schlüssig. habe 
wohl irgendeinen denkfehler.

meiner meinung müsste die zeile die bits so schieben, dass auf der 
rechten seite 3 mal eine 0 eingefügt wird und so ein bitmuster von 
0b10000000 entsteht.
wo liegt mein denkfehler?

mfg

von spess53 (Gast)


Lesenswert?

Hi

>wo liegt mein denkfehler?

PORTB = 0xF0           -> 11110000

PORTB &=~ (0xF0 <<3)   -> 11110000 & 01111111 = 01110000

MfG Spess

von Stk 500 anfänger (Gast)


Lesenswert?

spess53 schrieb:
> PORTB = 0xF0           -> 11110000
>
> PORTB &=~ (0xF0 <<3)   -> 11110000 & 01111111 = 01110000
>
> MfG Spess

und wie kommst du jetzt auf das 01111111?

mfg

von ... (Gast)


Lesenswert?

"~ (0xF0 <<3)" ist gleich 0b01111111 bzw. 0x7F

von spess53 (Gast)


Lesenswert?

Hi

>und wie kommst du jetzt auf das 01111111?


~ (0xF0 <<3) = 01111111

MfG Spess

von Stk 500 anfänger (Gast)


Lesenswert?

spess53 schrieb:
> ~ (0xF0 <<3) = 01111111
>
> MfG Spess

sitz irgendwie gerade ziemlich auf dem schlauch. 0xF0 ist ja 11110000. 
jetzt um 3 stellen nach links verschoben ergibt das bei mir 10000000. 
muss ich dann wegen dem ~ das ganze noch invertieren um dann auf 
01111111 zu kommen?

mfg

von negator (Gast)


Lesenswert?

So sieht's aus.

~ entspricht der bitweisen Negation, Einerkomplement, Invertierung oder 
welche Namen es dafür auch noch geben mag...

mfg

von spess53 (Gast)


Lesenswert?

Hi

>muss ich dann wegen dem ~ das ganze noch invertieren um dann auf
>01111111 zu kommen?

Ja. Oder meinst du ~ bedeutet 'etwa' oder 'ungefähr'.

MfG Spess

von Stk 500 anfänger (Gast)


Lesenswert?

jetzt hab ich mal nochmal zum besseren ein verständnis der ganzen 
bitmanipulation ein weiteres programm geschrieben:
1
#include <avr/io.h>
2
#include <util/delay.h>  
3
4
5
6
7
void long_delay(uint16_t ms)
8
{
9
  for(;ms>0; ms--)
10
  {
11
  _delay_ms(1);
12
  }
13
}
14
15
16
17
18
      
19
20
21
  
22
int main(void)
23
{
24
  DDRB = 0b11111111; //alle Pins an Port B als Ausgang
25
  
26
  
27
  
28
29
  while (1)
30
  {
31
PORTB |= (1<<PB0);  //ergibt 0b00000001 => alle LEDs außer LED0 an
32
33
 long_delay(1000);
34
35
 
36
37
PORTB &=~ (1<<PB0);  //ergibt 0b00000000 => alle LEDs an
38
39
40
 long_delay(1000);
41
42
43
44
45
  }
46
  return 0;
47
}

jetzt verstehe nicht warum dann PORTB &=~ (1<<PB0); 0b00000000 ergibt. 
1<<PB0 macht ja 0b00000001. das ~ invertiert das ganze zu 0b11111110. 
kann es sein, dass jetzt das & beide bitmuster UND- verknüpft zu 
0b00000000?

mfg

von Karl H. (kbuchegg)


Lesenswert?

>> Du solltest beachten, dass beim STK500 eine "1" am Ausgang die LED
>> ausschaltet.
>
> das weiß ich schon. es ist doch richtig, dass beim STK500 bei PORTB =
> 0xF0; LED0-3 an sind, oder?

Wie kommst du darauf?

Bei den Led Nummern wird genauso wie bei den Bitnummern rechts 
angefangen zu zählen. Dort ist ja schliesslich die niederwertigste 
Stelle.

Da 0xF0  binär 0b11110000  darstellt, leuchten die LEDs 4 bis 7 und 
nicht 0 bis 3, wenn eine LED bei einem 1 Bit leuchtet.

von Stk 500 anfänger (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Da 0xF0  binär 0b11110000  darstellt, leuchten die LEDs 4 bis 7 und
> nicht 0 bis 3, wenn eine LED bei einem 1 Bit leuchtet.

das ist ja genau beim STK500 nicht der fall. hier leuchtet eine LED 
nämlich genau dann, wenn am ausgang eine 0 (low-pegel) herauskommt. und 
dadurch leuchten beim STK500 bei 0xF0 (0b11110000) LED0- LED3.

mfg

von Karl H. (kbuchegg)


Lesenswert?

Stk 500 anfänger schrieb:
> Karl heinz Buchegger schrieb:
>> Da 0xF0  binär 0b11110000  darstellt, leuchten die LEDs 4 bis 7 und
>> nicht 0 bis 3, wenn eine LED bei einem 1 Bit leuchtet.
>
> das ist ja genau beim STK500 nicht der fall. hier leuchtet eine LED
> nämlich genau dann, wenn am ausgang eine 0 (low-pegel) herauskommt. und
> dadurch leuchten beim STK500 bei 0xF0 (0b11110000) LED0- LED3.

Ja was jetzt?
Weiter oben war die Rede davon, dass eine LED bei einer 1 am Port 
leuchtet. Ich hab kein STK500, aber wie die LED auf meinem 
Entwicklungsboard leuchten, weiß ich.

von Heins (Gast)


Lesenswert?

spess53 schrieb:
> Hi
>
>>muss ich dann wegen dem ~ das ganze noch invertieren um dann auf
>>01111111 zu kommen?
>
> Ja. Oder meinst du ~ bedeutet 'etwa' oder 'ungefähr'.
>
> MfG Spess

Klasse :-)

Ich musste Schmunzeln :-)

von Heins (Gast)


Lesenswert?

Beim Stk500 sind die LEDs low aktiv!

die leuchten wenn Low anliegt und sind aus wenn high anliegt!

von Stk 500 anfänger (Gast)


Lesenswert?

ja es ist schon so wie ich es geschrieben habe. am STK500 hängen die 
LEDs mit der Anode über einen pullup widerstand dauerhaft an Vcc und mit 
der kathode am Ausgang des AVR. erst wenn der am ausgang eine 0 bringt, 
wird dadurch ja intern die kathode der LED mit GND verbunden und die LED 
leuchtet.

die LEDs am STK leuchten deshalb immer nur bei einer 0 am ausgang des 
AVR.

mfg

von Karl H. (kbuchegg)


Lesenswert?

Stk 500 anfänger schrieb:

> #include <avr/io.h>
> #include <util/delay.h>
>


Gewöhn dir das ab, da haufenweise Leerzeilen einzufügen.
Die bringen keine Übersicht. Die ziehen den Code nur in die Länge und 
sonst gar nichts. Was du ansonsten leicht auf einer Bildschirmseite 
überblicken kannst, artet bei vielen Leerzeilen dahingehend aus, dass du 
ständig rumscrollen musst. Nicht gerade übersichtlich.


> int main(void)
> {
>   DDRB = 0b11111111; //alle Pins an Port B als Ausgang

soweit richtig

>   while (1)
>   {
> PORTB |= (1<<PB0);  //ergibt 0b00000001 => alle LEDs außer LED0 an

eigentlich nicht.
Durch das |= sagt man:
mir egal welche anderes Bits an diesem Port schon gesetzt sind. Ich will 
auf jeden Fall PB0 noch mit dazu auf 1 haben.

d.h.  'alle LEDs außer' ist falsch. Denn auf die anderen LEDs ausser 
LED0 hat diese Anweisung keinen Einfluss.

>  long_delay(1000);
>
>
>
> PORTB &=~ (1<<PB0);  //ergibt 0b00000000 => alle LEDs an

Bitte:
Das ~ gehört zum (1<<PB0) !
SO wie ein negatives Vorzeichen zur Zahl gehört.
Das ~ ist eine OPeration wie jede andere auch.
Also schreib sie auch dort hin wo sie hingehört

   PORTB &= ~(1<<PB0);

Das löscht das Bit PB0, und nur das Bit PB0. Alle anderen Bits an diesem 
Port bleiben unberührt.

> jetzt verstehe nicht warum dann PORTB &=~ (1<<PB0); 0b00000000 ergibt.

tut es auch nicht.

> 1<<PB0 macht ja 0b00000001. das ~ invertiert das ganze zu 0b11111110.
> kann es sein, dass jetzt das & beide bitmuster UND- verknüpft zu
> 0b00000000?

Was heist "kann es sein". Diese Und-Verknüpfung ist der ganze Witz an 
der Sache. So wie es beim setzen die Oder-Verknüpfung war.


            01001000     das sei der Zustand vom Port B jetzt

     oder   00110000     jetzt odern wir eine Maske dazu, in der 2
                         Bits gesetzt sind

           ---------
            01111000     Das Ergebnis ist der originale Inhalt vom
                         Port B in dem zusätzlich noch die beiden
                         Bits aus der Maske auf jeden Fall auf 1 sind

Dasselbe umgekehrt mit Und und der negierten Maske.


          11001010      Port B habe irgendeinen Zustand

    und   11111001      diese Maske wird dazugeundet.
        -----------

          11001000      wo in der Maske eine 1 war, bleibt der Original-
                        inhalt vom Port B erhalten. Dort wo in der Maske
                        eine 0 steht, kommt auch im Ergebnis auf jeden
                        Fall eine 0 raus.


Aber das alles ist doch eigentlich auch ausführlich im AVR-GCC-Tutorial 
ausgeführt, oder etwa nicht?

von spess53 (Gast)


Lesenswert?

Hi

>jetzt verstehe nicht warum dann PORTB &=~ (1<<PB0); 0b00000000 ergibt.
>1<<PB0 macht ja 0b00000001. das ~ invertiert das ganze zu 0b11111110.
>kann es sein, dass jetzt das & beide bitmuster UND- verknüpft zu
>0b00000000?


PORTB &=~ (1<<PB0) heisst: PORTB = PortB & (~ (1<<PB0))

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:

eigentlich nicht.
> Durch das |= sagt man:
> mir egal welche anderes Bits an diesem Port schon gesetzt sind. Ich will
> auf jeden Fall PB0 noch mit dazu auf 1 haben.
>
> d.h.  'alle LEDs außer' ist falsch. Denn auf die anderen LEDs ausser
> LED0 hat diese Anweisung keinen Einfluss.

Um da noch einmal nachzuhaken:
In deinem Code sind ganz einfach die Kommentare falsch.

So muss es richtig heißen
1
 while (1)
2
 {
3
    PORTB |= (1<<PB0);   // LED 0 ausschalten
4
    long_delay(1000);
5
6
    PORTB &=~ (1<<PB0);  // LED 0 einschalten
7
    long_delay(1000);
8
  }

Denn innerhalb der while-Schleife kontrollierst du aussschliesslich und 
nur die LED 0. Die anderen LED können leuchten oder auch nicht leuchten, 
je nachdem was vor der Schleife alles passiert ist. SPielt aber keine 
Rolle, denn innerhalb der Schleife wird nur Bit 0 vom Port B manipuliert 
und die anderen werden in Ruhe gelassen.

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.