Das kommt natürlich ganz drauf an wie du's zusammengelötet hast...
Bei mir ist 00010000 Enable
00100000 RS
01000000 R/W
Gruss, Jochen
Hi!
Bin ziemlich neu auf dem Gebiet C-Control und hab ne Frage zur letzten Routine. Wenn man im 4Bit-Modus arbeitet, dann werden doch die Daten in 2 Takten gesendet und beidesmal in den Datenbereich ganz vorne im byteport, also die ersten 4 Bits. Und wenns ein kommando is, dann in den ganzen byteport rein. Aber irgendwie versteh ich die routine nicht, eigentlich gar nicht! Außerdem ist bei B00100000 der 1er nicht an der Stelle vom RegisterSelect, des müsste doch heißen B00000100 oder? Und warum wird keine unterscheidung zwischen kommando und zeichen senden gemacht, bitte erklär mir das verständlich, ich versuchs schon seit längerem zu kapiern, wird aber net *Gg*
Code:' *** Daten-Definition *** define lcd_buf byte 'Zeichen oder Kommando define lcd_param byte ' *** Definition LCD-Ports *** define lcd_port byteport[2] define lcd_rs port[14] 'Register Select define lcd_rw port[13] 'Read/Write define lcd_e port[15] 'Enable '*** Programmoperationen *** gosub LCD_INIT pause 10 end ' Display initialisieren #LCD_INIT lcd_port = OFF 'alle Ports auf 0 setzen lcd_param=&H38 : gosub LCD_WRITECMD '8-Bit-Modus aktivieren lcd_port=&B00000010 'mit 8-Bit-Command in 4-Bit-Modus umschalten pulse lcd_e lcd_param = &H28 : gosub LCD_WRITECMD 'ab jetzt 4-Bit-Modus lcd_param = &H0C : gosub LCD_WRITECMD 'Display einschalten, kein Cursor, kein Blinken return ' Display löschen #LCD_CLS lcd_param = &H02 : gosub LCD_WRITECMD 'Cursor home lcd_param = &H01 : gosub LCD_WRITECMD 'Display clear return ' Zeilenwechsel #LCD_GOTOLINE if lcd_param = 1 then lcd_param = &H80 'in 1. Zeile wechseln if lcd_param = 2 then lcd_param = &HC0 'in 2. Zeile wechseln goto LCD_WRITECMD return ' LCD-Kommando #LCD_WRITECMD lcd_buf = OFF 'Controlregister aktivieren goto LCD_WRITE return ' Zeichenausgabe #LCD_WRITECHAR lcd_buf = &B00100000 'Datenregister aktivieren goto LCD_WRITE return ' Kommando oder Zeichen an Display senden #LCD_WRITE lcd_port = lcd_buf or (lcd_param shr 4) 'Hi-Nibble senden pulse lcd_e lcd_port = lcd_buf or (lcd_param and &H0F) 'Lo-Nibble senden pulse lcd_e return
Das kommt natürlich ganz drauf an wie du's zusammengelötet hast...
Bei mir ist 00010000 Enable
00100000 RS
01000000 R/W
Gruss, Jochen
Es wird doch ne Unterscheidung gemacht. Wenn man etwas schreibt ist RS high und wenn man Komandos gibt, low.
Matthias
Back on the road again...
Falls ihr wissen wollt, was ich so in meiner roboterfreien Zeit gertieben hab: www.plasmaniac.de.vu
Hallo Gast,
Die bits stehen nicht "ganz vorne", sondern "ganz hinten", im LOW nibble.
Damit komme ich auch immer wieder durcheinander:
1. Nummerierung der BITs (und auch der BYTEs / WORDs):
In CC_BASIC wird immer "LOW to HIGH" nummeriert, beginnend mit 1. Das bedeutet:
Die BITs im BYTEPORT[1] heissen BIT[1] bis BIT[8],
und dabei ist BIT[1] das LSB (das mit dem niedrigsten Wert: "2 hoch 0" = 1),
und BIT[8] das MSB (das mit dem höchsten Wert: "2 hoch 7" = 12.
--- Ich nummeriere bits (und bytes..) eigentlich immer ab 0, nicht ab 1; das machen auch die meisten Assembler und Datenblätter so.
--- Aber meine Verwechslungen entstehen oft auch dadurch:
In CC-BASIC schreibt man bei Aufzählungen untereinander zuerst BIT[1] (LSB), dann BIT[2], .. bis BIT[8] (MSB),
während ich das IMMER umgekehrt mache, nämlich zuerst bit_7 (MSB), dann bit_6, .. bis bit_0 (LSB).
Ich bin's halt seit über 30 Jahren so gewohnt, und ich kann mir so aus den bit-Werten leichter den HEX Wert des Bytes zusammenbasteln; Dir gehts anscheinend genauso (siehe Punkt2).
2. Der LCD_PORT ist definiert als BYTEPORT[2] und umfasst demnach die bit ports PORT[9] bis PORT[16].
Dabei ist wieder PORT[9] das LSB und PORT[16] das MSB.
PORT[9] bis PORT[12] ist also das niederwertige Halbbyte ("low nibble")
und PORT[13] .. PORT[16] ist das high nibble dieses bytes.
--- Also ist bei &B00100000 = &H20 im LCD_PORT = BYTEPORT[2] die "1" der PORT[14] (und das ist RS, siehe Punkt 4).
3. Leitungen des LCD:
RS = select command (0) or data (1)
R/W (quer) = write to LCD (0) oder read from LCD (1)
E = enable (pulse)
DB0..DB3 = data LOW nibble; nur benutzt im LCD 8-bit modus; ignoriert im 4-bit mode (!!)
DB4..DB7 = data HIGH nibble im 8-bit mode; im 4-bit-mode: zuerst high nibble, dann low nibble
Die Nummerierung der data bits im LCD beginnt also mit 0 (nicht mit 1).
4. Hardware-Beschaltung des BYTEPORT[2] für das LCD:
Das low nibble des BYTEPORT[2] (also PORT[9]..PORT[12]) liegt am high (!!) nibble der LCD DATA, weil der 4-bit mode des LCD genutzt werden soll.
Das high nibble des BYTEPORT[2] enthält die LCD Steuerleitungen, und zwar:
PORT[13] liegt an RW des LCD (0 = "write to LCD"),
PORT[14] liegt an RS des LCD (0 = "LCD command", 1 = "LCD data"),
PORT[15] ist das LCD enable signal (wird gepulst),
und PORT[16] ist nicht zum LCD verdrahtet.
Das low nibble des LCD ist NICHT verdrahtet (braucht auch keine pull ups), weil hier ja der 4-bit-modus des LCD genutzt wird.
5. Im LCD 4-bit-modus werden sowohl Data als auch Command in zwei Takten übertragen.
Im ersten Takt steht das high nibble, und im zweiten Takt das low nibble des zu übertragenden Bytes im PORT[9]..PORT[12] ( = low nibble) des LCD_PORT.
In beiden Fällen wird aber auch immer PORT[13]..PORT[16] gesetzt,
wobei PORT[15] = ENABLE immer 0 ist
und PORT[13] = RW ebenfalls immer 0 = "write to LCD" ist.
PORT[16] ist nicht zum LCD verdrahtet, bedeutet also fürs LCD nix.
Jeder Takt wird dem LCD mit einem pulse des PORT[15] (= LCD enable) signalisiert;
erst jetzt interpretiert das LCD die anliegenden Daten, nämlich:
PORT[9] .. PORT[12] = Wert des high nibble beim 1. Takt bzw. des low nibble beim 2. Takt;
PORT[13] = RW = "Write to LCD";
PORT[14] = RS = "data" (falls 1) oder "command" (falls 0).
6. Die Übertragung von commands und data im 4-bit mode müsstest Du jetzt nachvollziehen können:
LCD_WRITECMD setzt PORT[14] = RS = 0 = "LCD command",
LCD_WRITECHAR dagegen PORT[14] = RS = 1 = "LCD data".
Bei beiden ist PORT[13] = RW = 0 = "Write to LCD".
Im LCD_WRITE wird zuerst das high nibble, und dann das low-nibble erzeugt und jeweils mit pulse LCD_E an das LCD übergeben.
Für die Bedeutung der commands und der bits innerhalb der commands brauchst Du natürlich auch eine Beschreibung des LCD.
7. Mit dem LCD_INIT soll das LCD in den 4-bit modus versetzt werden.
Zuerst wird &H38 mit "gosub LCD_WRITECMD" ausgegeben.
Ich erkläre mir das so, bin mir aber nicht ganz sicher (-- vielleicht kann jemand sagen, ob's stimmt --):
FALLS das LCD zu diesem Zeitpunkt im 4-bit mode läuft, dann ist das EIN command ans LCD:
001 = LCD command "FUNCTION SET" mit DL = 1 = "8-bit-mode", N = 1 = "display 2 lines" und F = 0 = "5x8 char matrix"
FALLS ABER das LCD aber zu diesem Zeitpunkt bereits im 8-bit-mode war, z. B. nach power-on, dann erzeugt "gosub LCD_WRITECMD" jetzt ZWEI commands an das LCD:
command 1 (ist das high nibble von &H3: 001 = LCD command "FUNCTION SET" mit DL = 1 = "8-bit-mode" ( + floatendes low nibble der LCD data Leitungen)
command 2 (ist das low nibble von &H3: 1 = "Set DD-RAM address" auf wert 000 ( + floatendes low nibble der LCD data Leitungen)
Egal wie: das LCD ist jetzt definitiv im 8-bit-mode.
Das folgende "LCD_PORT = &B00000010 : pulse LCD_E" ist deshalb immer ein LCD command IM 8 BIT MODE (wird ja auch NICHT mit "gosub LCD_WRITECMD" ausgegeben, sonder direkt gepulst):
PORT[13] = RW = 0 = "write to LCD",
PORT[14] = RS = 0 = "LCD command" und
PORT[9]..PORT[12] = low nibble = 0010; das liegt ja aber am HIGH (!!) nibble der LCD data. Also:
001 = LCD command "FUNCTION SET" mit DL = 0 = "4-bit-mode" ( + floatendes low nibble der LCD data Leitungen)
Jetzt ist das LCD also definitiv im 4-bit-mode,
und die Ausgaben &H28 und &H0C mit "gosub LCD_WRITECMD" sind normale LCD commands im 4-bit modus:
&H28 = 001 = "FUNCTION SET" mit DL = 0 = "4-bit-mode", N = 1 = "display 2 lines" und F = 0 = "5x8 char matrix"
&H0C = 00001 = "DISPLAY" mit D = 1 = "Display on", C = 1 = "Cursor unsichtbar" und B = 0 = "blinken aus".
UFF, ich hoffe das stimmt alles,
sonst habe ich Dich jetzt sehr verwirrt!
Übrigens: Ich würd die "clear"-Routine nicht benutzen, sondern das, was weg sein soll einfach mit Leerzeichen übermalen, dann flimmerts nich so. Hier noch eine routiene, mit der man den Zeileninhalt nach rechts schieben kann. Wie man`s in beide Richtungen macht, poste ich später nochmal
#lcd_shift
parameter=&b00011100
gosub LCD_WRITECMD
return
Back on the road again...
Falls ihr wissen wollt, was ich so in meiner roboterfreien Zeit gertieben hab: www.plasmaniac.de.vu
sorry, noch immer ein paar fragen offen geblieben ..
- warum bei lcd_buf das RS an der falschen stelle
- wie muss man bei daten- bzw. kommando-senden vorgehen bzw. wohin muss man es schreiben
- die zwei zeilen mit shr und and 0F erklären ..
1. Wenn man z.B. 01110101 versenden will schiebt man das gnze zuerst mal um 4 Stellen nach rechts: die Zahl 0111 entsteht. Dann nimmt man die Zahl von vorhin mit 00001111 and, das bedeutet, dass, wenn im vergleich und im ursprung eine 1 an der gleichen Stelle ist, kommt die dann aus dem rechenschritt raus, weil man nur die letzten vier nimmt, kommt die zahl 00000101 raus.
2. Man schreibt den Buchstaben, den man schreiben will, im ASCII-Code in die Variable LCD_param. Dann gosubst du nach LCD_WRITECHAR und das Zeichen wird geschrieben. Wenn du eine Zeile auswälen möchtest, musst du 1 für Zeile 1 usw. in LCD_param schreiben. Dann gosubst du nach LCD_writecmd.
3. Das este bit ist das höhste bit. Es hat den grösten wert. Die bits sind bim Byteport spiegelverkeht.
Matthias
Back on the road again...
Falls ihr wissen wollt, was ich so in meiner roboterfreien Zeit gertieben hab: www.plasmaniac.de.vu
oder andersrum gesagt:
"lcd_buf = &B00100000" setzt alle bits auf 0, ausser BIT[6].
Später kommt dann für den ersten Takt
"lcd_port = lcd_buf or (lcd_param shr 4)"
Damit wird lcd_param zuerst mal um 4 bits nach rechts verschoben;
aus einem lcd_param = "abcdefgh" wird damit "0000abcd": der ehemalige high nibble steht jetzt als low nibble drin.
Dann wird noch der Inhalt von lcd_buf drauf ge-oder-t, also das "00100000", und deshalb steht jetzt "0010abcd" im lcd_param.
Dieses "0010abcd" geht im ersten Takt an lcd_port, also an den BYTEPORT[2], an dem das LCD hängt.
Und da ist diese "1" jetzt genau am pin "RS" des LCD angekommen, oder?
Das
lcd_port = lcd_buf or (lcd_param and &H0F)
im zweiten Takt ist jetzt auch einfach:
Mit dem AND wird aus lcd_param = "abcdefgh" zunächst "0000efgh": nur der ehemalige low nibble steht jetzt noch drin (immer noch als low nibble).
Dann wird wieder der Inhalt von lcd_buf drauf ge-oder-t, also das "00100000", und deshalb steht "0010efgh" im lcd_param, bevor's ans LCD geht.
Daten senden:
Du musst jedes byte einzeln senden,
wobei in lcd_param der Zeichencode stehen muss, z.b.
lcd_param = &H41 : gosub lcd_writechar ' schreibt ASCII A
lcd_param = &H42 : gosub lcd_writechar ' schreibt ASCII B
lcd_param = &H33 : gosub lcd_writechar ' schreibt ASCII 3
Kommandos senden:
geht entsprechend, aber: du musst dazu die LCD commands genau kennen. Wenn Du z. B. auf die 1. Zeile positionieren willst, könntest Du schreiben
lcd_param = &H80 : gosub lcd_writecmd
weil das CMD &H80 genau an den Anfang der 1. Zeile positioniert.
Aber normalerweise schickst du nicht selbst LCD commands durch die Gegend, sondern rufts einfach die Hilfs-Funktionen auf, wie z. b.
lcd_param = 1 : gosub lcd_gotoline ' positioniert auf die 1. Zeile
oder
gosub lcd_cls ' löscht alles
und die schicken dann für dich das LCD command raus (eins oder mehrere).
ok recht herzlichen dank
und das letzte problem wäre noch, dass im byteport[2] ja folgendes drinsteht:
d4 d5 d6 d7 | R/W RS EN X ... Bedeutung
9 10 11 12 | 13 14 15 16 ... Pins
d.h. warum wirds nicht so gemacht: lcd_buf = &B00000100
dann wär das bit an stelle RS gesetzt!
ganz einfach:
mit "lcd_buf = &B00000100" setzt Du das dritt-niedrigste bit auf eins; das heisst aber nicht PORT[14], sondern PORT[11], und ist deshalb nicht das EN - bit.
Das BYTEPORT[2] ist schon so zum LCD verdrahtet, wie du's geschrieben hast, NUR:
Du hast die Reihenfolge der bits in Deinem Bild verkehrt rum aufgemalt. PORT[9] ist derjenige mit dem niederigsten Wert; den musst Du ganz nach RECHTS zeichnen, wenn Du Dich nachher an diesem Bild orientieren willst, um den LCD_BUF mit bits zu laden:
X EN RS RW d7 d6 d5 d4 ... Bedeutung für LCD
16 15 14 13 12 11 10 9 ... PORT-Nummer der CC1
Jetzt kannst Du schreiben: LCD_BUF = &B00100000;
da gibst Du ja auch ganz RECHTS das Bit mit dem geringsten Wert an.
Und das "RS" gehört ja in das dritt-höchste bit (PORT[14]), das muss also im Bild (und auch in der bit-Maske) an dritter Stelle von LINKS stehen.
Lesezeichen