Hallo,
> wenn temp1 = 10101111 wäre ... dann ist es nach >> 4 = 00001010> Richtig?
Ja.
> Wieso wird maskiert?
Das ist tatsächlich redundant; durch ">>4" wird das höherwertige Nibble
schon 0.
> Und was macht:> temp2 = temp2 & 0x0F; // unteres Nibble> holen und maskieren> LCD_PORT &= 0xF0;
Na, oben hattest Du es doch schon verstanden: Das obere Nibble wird
durch das "&"-Skalpell wegoperiert, also auf 0 gesetzt. Das SFR, das als
LCD_PORT bezeichnet wird, wird gelesen, das untere Nibble des gelesenen
Werts wird auf 0 gesetzt, und dann wird der neue Wert zurück in das SFR
geschrieben.
Gruß
risu
Die zweite Operation ist nur überflüssig, wenn temp1 vom typ char (oder
anderem 8bit Typ) ist.
Dann hat die Bitshift-Operation zur Folge, dass die oberen 4 Bit mit
Null aufgefüllt werden und der Inhalt von temp1 um 4 Bit nach rechts
geschoben wird und Bit 0 bis Bit 3 des alten temp1 entsprechend nicht
mehr existieren.
Aber (du hast nicht angegeben, von welchem typ temp 1 ist) wenn temp1
ein int wäre, wäre folgendes denkbar:
Angenommen temp1 ist vorher 0b1110 0110 1101 1011
Dann ist es nach dem shift 0b0000 1110 0110 1101
Dann würde es durchaus Sinn machen, mit 0x0F == 0b0000 0000 0000 1111 zu
undieren.
Das Ergebnis wäre dann 0b0000 0000 0000 1101.
Viele Grüße,
Peter
Hallo Peter,
> ...du hast nicht angegeben, von welchem typ temp 1 ist ...
Richard schrieb als erste Zeile:
> unsigned char temp2 = temp1;
Meine Erklärung bezog sich spezifisch darauf.
Viele Grüße
Fred
Hallo Peter,
natürlich stimmt was Du sagst, und ich hätte nicht aus dem fehlenden
"typecast" bei "unsigned char temp2=temp1;" schließen dürfen, dass
"temp1" auch "unsigned char" ist.
Gruß
Fred
Hallo nochmal,
ich hab noch eine kleine Ergänzung zum Programmierstil:
1
temp2=temp2&0x0F;// unteres Nibble holen und maskieren
2
LCD_PORT&=0xF0;
3
LCD_PORT|=temp2;// setzen
Das sieht aus, wie eine sogenannte Read-Modify-Write Anweisung.
Dabei möchte man bestimmte Bits einer Variable ändern, die anderen aber
unverändert lassen.
In deinem Beispiel möchtest du nur Bit 0 bis Bit 3 von temp betrachten
und diese in LCD_PORT an die Stellen von Bit 0 bis Bit 3 schreiben,
wobei die anderen Bits von LCD_PORT so bleiben sollen, wie sie vorher
waren.
Ich nehme an, LCD_PORT ist ein Portregister, schreibt also direkt auf
die Hardwareports.
Dein Programmierstil ist hier suboptimal, denn die zweite Zeile
1
LCD_PORT&=0xF0;
schreibt auf die Bits 0 bis 3 von LCD_PORT tatsächlich null raus, wenn
auch nur für einen kurzen Moment, bis mit
1
LCD_PORT|=temp2;// setzen
diese Bits mit etwas sinnvollem gefüllt werden.
Das ist ein unnötiger Peripheriezugriff, der Port könnte auch gleich so
gesetzt werden, wie er sein soll. Eventuell kannst du duch das
(unnötige) hochfrequente Schalten zwischen Zeile 2 und Zeile 3 sogar
mehr Störaussendung deiner Schaltung erwarten. Das ist jedoch nur
relevant, wenn dadurch der Rest deiner Schaltung störempfindlich ist,
oder das Gerät verkauft werden soll und dafür eine CE-Prüfung notwendig
ist.
Besser wäre folgende Vorgehensweise:
1
temp2&=0x0F;//Bit 4 bis 7 von temp2 sind jetzt 0
2
temp2|=LCD_PORT&0xF0;//Bit 4 bis 7 von LCD_PORT werden in temp2 zusätzlich mitgespeichert
3
LCD_PORT=temp2;//und jetzt alles auf ein Mal auf die Hardware schreiben
4
5
//wenn temp2 danach noch mit Bit 4 bis 7 == 0 gebraucht wird, noch folgendes:
6
7
temp2&=0x0F;
So wird nur einmal auf LCD_PORT geschrieben.
Viele Grüße,
Peter
Hallo,
hab mir das Tutorial angesehen, die Routinen sind einfach nicht sauber
ausprogrammiert. Sie sollten von der Logik her schon funktionieren, aber
wie ich bereits geschrieben habe, entstehen durch die mehrfachen
Read-Modify-Write Zugriffe auf den Port - ja es ist ein port, steht in
dem entsprechenden Headerfile - Hochfrequente Flanken, die nicht jedes
Display mag. Man muss beachten, dass die AVRs viel schneller sind, als
die meisten Paralleldisplays betrieben werden dürfen, da ist es fehl am
Platz gewünschten Bits der Reihe nach in verschiedenen Anweisungen auf
den Port zu odern.
> Aber beim unteren Nibble> LCD_PORT |= temp2; ist es dann 00001010 ! Es muss aber 00001000 sein.
Das setzt das untere Nibble auf Null:
LCD_PORT &= 0xF0;
Das hast du wohl übersehen. Die Routine funktioniert rein mathematisch
schon.
Probier es doch mal so:
1
voidlcd_command(unsignedcharcommand)
2
{
3
unsignedcharcommand_shadow=command;
4
5
command=command>>4;// oberes Nibble holen
6
LCD_PORT=command;
7
_delay_us(100);
8
lcd_enable();
9
10
command_shadow&=0x0F;// unteres Nibble holen und maskieren
11
LCD_PORT=command_shadow;// setzen
12
_delay_us(100);
13
lcd_enable();
14
15
_delay_us(42);
16
}
Schließ dabei nur das Display an den Port an, ich schreibe hier immer
uaf den ganzen Port. Das R/W und C/D Flag sind hier implizit drin.
Wenn du schon unbedingt den 4-Bit modus verwenden musst, ließ doch mal
das Manual von deinem Display oder einem kompatiblen von EA
(www.lcd-module.de). Da stehen Hinweise zum Timing und auch die
entsprechenden Bits, die für die einzelnen Kommandos gesetzt werden
müssen. So ein Displaytreiber ist gleich selber geschrieben, ich hätte
auch einen, der ist aber für 8-Bit Anschluss.
Im Prinzip sind das nicht viele Kommandos, die man wirklich braucht.
Init();
SetCursor(x,y);
Cursor_sichtbar(bool);
WriteCharacter(char);
Das wars eigentlich. Die kann man einfach aus dem manual abschreiben,
und dann funktionierts auch.
Grüße,
Peter
Mit dem rechts Schieben ist es nicht ganz so intuitiv wie mit dem links
Schieben. Während beim Schieben nach links (<<) jeweils von rechts mit 0
aufgefüllt wird, hängt die beim rechts Schieben (>>) vom Typ der
Variablen ab. Bei unsigned Typen wird ebenfalls eine 0 eingeschoben, bei
signed wird jedoch das MSB dupliziert. Wenn wir hier temp1 ebenfalls als
unsigned annehmen, macht es weiterhin keinen Unterschied, man sollte
jedoch trotzdem dran denken ;)
Greets
Basti.
Peter Diener wrote:
> hab mir das Tutorial angesehen, die Routinen sind einfach nicht sauber> ausprogrammiert.
Das stimmt.
Wenn z.B. die 2 freien Pins des Ports in Interrupts verwendet werden,
gibts das schönste Chaos.
Am besten ist es daher, wenn man die atomaren Pin-setz/clear Befehle
nimmt.
Dann ist man auch nicht mehr an einen Port oder an eine bestimmte
Pinreihenfolge gebunden.
Es gehen völlig beliebige 6 Pins und wesentlich lesbarer wird die Sache
obendrein:
Beitrag "Re: LCD nicht nur für einen Port in C"
Peter