Forum: Compiler & IDEs C-Anfängerfrage zur Tilde


von Rudi D. (rulixa)


Lesenswert?

Warum schreibt man z.B.
LCD_PORT &= ~(1<<LCD_RS)  und nicht
LCD_PORT &= (0<<LCD_RS)

Ich bin übrigens sehr froh, dass ich vorher in Assembler unterwegs war, 
da z.B. in den lcd_routines.c oder .h oft das pinning des Displays am µC 
versteckt ist.
LG Rudi

von Udo S. (urschmitt)


Lesenswert?

Wenn du Assemblererfahrung hast, dann weisst du doch welcher binäre 
(oder hex) Wert du möchtest.
Schreib dir doch mal auf welcher Wert in das Register soll und was bei 
den Varianten rauskommt:
~(1<<LCD_RS)
(0<<LCD_RS)

Dann siehst du selbst was richtig ist und warum.
Nimm Papier und Bleistift und gehs durch, so wie Karl Heinz das immer 
propagiert, da ist der Lerneffekt am nachhaltigsten

von XXX (Gast)


Lesenswert?

Hallo

Mal dir das ganze doch mal auf, was da passiert.
Dann fällts dir wie Schuppen aus den Haaren.

Gruß
Joachim

von Antworter (Gast)


Lesenswert?

Hallo,

tolle Antworten bis jetzt...

Du musst Schritt für Schritt vorgehen:
1. (1<<LCD_RS) wird bearbeitet: "Die 1 um LDC_RS Stellen nach links 
schieben"
   Beispiel: aus 1 wird 00100 wenn LDC_RS = 2 ist.
2. Das ganze wird durch die Tilde bitweise negiert. Aus 00100 wird z.B. 
11011

Wenn Du unter 1. eine 0 nach links verschiebst, kommt eben auch 0 raus.

Viele Grüße

von Karl H. (kbuchegg)


Lesenswert?

Antworter schrieb:
> Hallo,
>
> tolle Antworten bis jetzt...
>
> Du musst Schritt für Schritt vorgehen:
> 1. (1<<LCD_RS) wird bearbeitet: "Die 1 um LDC_RS Stellen nach links
> schieben"
>    Beispiel: aus 1 wird 00100 wenn LDC_RS = 2 ist.
> 2. Das ganze wird durch die Tilde bitweise negiert. Aus 00100 wird z.B.
> 11011
>
> Wenn Du unter 1. eine 0 nach links verschiebst, kommt eben auch 0 raus.

Und genau darauf wäre er auch gekommen, wenn er das selber mit Papier 
und Bleistift durchgespielt hätte. Nur mit einem Unterscheid: Er hätte 
es nie wieder vergessen, weil er selber drauf gekommen ist. Einziger 
Nachteil: Es hätte 3 Minuten länger gedauert, bis er begriffen hat, dass 
er das Bitmuster

   0000 0000

so oft er will um x Stellen nach links verschieben kann und sich nichts 
ändert.

von Antworter (Gast)


Lesenswert?

Hallo,

@Karl Heinz Buchegger:

Ich gehe schon davon aus, dass hier nicht jeder aus jux und tollerei 
Fragen stellt.
Wenn er dann seine Frage vernünftig formuliert hat, finde ich es gelinde 
gesagt albern, ihm keine vernünftige Antwort zu geben.

Das kann jeder sehen wie er will. Eine ordentliche Antwort muss man dann 
auch nicht unbedingt noch kommentieren. Man kann seine persönliche 
Meinung auch für sich behalten...

Fazit: Wer gut fragt bekommt auch gute Antworten.

Viele Grüße

von Nachtaktiver (Gast)


Lesenswert?

Antworter schrieb:
> Fazit: Wer gut fragt bekommt auch gute Antworten.
>
> Viele Grüße

+1.

von Peter D. (peda)


Lesenswert?

Rudi D. schrieb:
> Ich bin übrigens sehr froh, dass ich vorher in Assembler unterwegs war,
> da z.B. in den lcd_routines.c oder .h oft das pinning des Displays am µC
> versteckt ist.

Das Pinning sollte niemals im Code versteckt sein, sondern an zentraler 
Stelle definiert werden, z.B. im "main.h" oder "hardware.h".

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=102296

In dem Beispiel sieht man auch sehr schön, wie man sich diese 
umständliche Schieberei-Schreibweise ersparen kann. Ein Pin wird dann 
einfach als Bitvariable angesehen.


Peter

von Rudi D. (rulixa)


Lesenswert?

So hab ich's in Assembler gemacht
1
;create  enable pulse 5 cycles auf 1 macht 0,75 us ändert kein Register
2
;mit fallender Flanke werden Daten übernommen
3
lcd_enable:
4
       sbi LCD_PORTB, PIN_E         ;2; Enable high
5
       nop
6
       nop
7
       nop
8
       cbi LCD_PORTB, PIN_E         ;2; Enable low
9
     rcall  delay50us    ;ab H>L Enable braucht das Display 38 us
10
     ret        ;bis es wieder bereit ist

in C sieht es so aus (nur abgeschrieben)
1
// erzeugt den Enable-Puls
2
void lcd_enable(void)
3
{
4
  LCD_PORT |= (1<<LCD_EN1);
5
    _delay_us(10);                   // kurze Pause
6
   // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
7
   // http://www.mikrocontroller.net/topic/80900
8
   LCD_PORT &= ~(1<<LCD_EN1);
9
}

Für mich, dachte ich, sollte das ident sein.
 cbi LCD_PORTB, PIN_E  == LCD_PORT &= ~(1<<LCD_EN1) == LCD_PORT &= 
(0<<LCD_EN1)

Mit cbi ändere ich ja nur den Status des Enable_pins und sonst kein 
anderes Bit des LCD_PORTs. Ich dachte dass &= ~(1<<LCD_EN1); auch nur 
dieses Bit ändert und nicht gleich alle Bits des Ports beeinflusst.

Deshalb gefällt mir die Lösung von peda in avr.freaks, weil für mich 
nicht mißverständlich. O.k. die Sache ist geklärt.
LG Rudi

von Rudi D. (rulixa)


Lesenswert?

Das hier ist noch einfacher zu verstehen, für mich fast wie Assembler, 
wieder am Beispiel des
1
 void lcd_enable(void)
2
{
3
  sbi (LCD_PORT, LCD_PIN_E);
4
  cbi (LCD_PORT, LCD_PIN_E); //wenn die Pulsdauer stimmt
5
}
6
7
#define sbi(PORT, bit)     (PORT|=(1<<bit)) // set bit in PORT
8
#define cbi(PORT, bit)     (PORT&=~(1<<bit))// clear bit in PORT
9
#define  LCD_PORT    PORTD
10
#define  LCD_DDR      DDRD
11
#define LCD_PIN_RS    0
12
#define LCD_PIN_E    3

auch abgeschrieben.
Wie bekommt man die Ausführungszeiten in C heraus. Ist ja in Assembler 
höchst einfach.

Da ist, wie von peda schon gesagt, die Bitschieberei nur 1x nötig zu 
definieren. Ich nähere mich halt langsam und verstehe, dass die Version 
auf AVR-freaks viel umfassender ist.

von Peter D. (peda)


Lesenswert?

Rudi D. schrieb:
> Wie bekommt man die Ausführungszeiten in C heraus. Ist ja in Assembler
> höchst einfach.

Erstmal rechnet ein Compiler alle Konstanten schon zur Compilezeit aus, 
d.h. das ~ und << erzeugt keinen Code.
Und dann schlägt der Optimierer zu und erkennt, daß nur ein Bit 
gesetzt/gelöscht wird und die Adresse im Bereich der Bitbefehle liegt.
Er mach also ein SBI/CBI daraus.

Das geht aber nicht immer, die größeren AVRs haben auch Ports im 
Memory-Bereich. Dann muß er LDS+ANDI/ORI+STS nehmen. Muß man aber in 
Assembler auch.


Peter


P.S.:
Ich hab mir die Schreibarbeit noch etwas vereinfacht und alle Ports in 
der sbit.h definiert:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=835728#835728

von Rolf Magnus (Gast)


Lesenswert?

Rudi D. schrieb:
> Wie bekommt man die Ausführungszeiten in C heraus.

Am besten, indem du den vom Compiler genrierten Assembler-Code 
anschaust, denn ...

> Ist ja in Assembler höchst einfach.

von Rudi D. (rulixa)


Lesenswert?

Peter Dannegger schrieb:
> Ich hab mir die Schreibarbeit noch etwas vereinfacht und alle Ports in
> der sbit.h definiert:
>
> http://www.avrfreaks.net/index.php?name=PNphpBB2&f...

Habe 2 sbit.h gefunden 300 byte und 9,5kByte, die eine ein Teil der 
anderen.
Da blicke ich noch nicht durch, zu neu für mich, to date.
In C scheint's ja viele legale Möglichkeiten zu geben dasselbe Ziel zu 
erreichen.
Weiss auch noch nicht was C allg. Statements sind und AVR extra ergänzt 
hat. Geschützte Bezeichnungen etc. Na ja, klein anfangen eben.
Verschiedene Sachen von mir sind bei Burkhard K's Labor zu finden. Das 
war aus Not, dieses allererste Projekt, www.b-kainka.de/ELO/rc5trans.pdf

LG Rudi

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.