PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] LCD Write



29.01.2004, 23:06
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*




' *** 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

30.01.2004, 08:28
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

Matthias
30.01.2004, 14:08
Es wird doch ne Unterscheidung gemacht. Wenn man etwas schreibt ist RS high und wenn man Komandos gibt, low.

Matthias

jörg
30.01.2004, 14:11
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" = 128).

--- 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 &H38): 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 &H38): 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!

Matthias
30.01.2004, 14:14
Ü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

30.01.2004, 16:34
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 ..

Matthias
30.01.2004, 17:20
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

jörg
30.01.2004, 18:05
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).

30.01.2004, 19:08
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!

jörg
30.01.2004, 19:33
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.

30.01.2004, 19:43
ok super, danke noch mal vielmals, jetzt hab ichs verstanden

07.02.2004, 17:31
hmm..

auf folgender seite http://www.wieselsworld-online.de/themen/listen/LCDCommand.htm sind die kommandos aufgelistet, die ja in 2 takten über die datenleitungen übertragen werden, aber in den spaltenüberschriften, was soll das, das is irgendwie verwirrend.. :/

07.02.2004, 17:32
sind außerdem 10 bits und nicht 8 ..

jörg
07.02.2004, 18:01
Na ja, die Tabelle beschreibt, was das LCD braucht, nämlich:
8 Datenbits: D0 (das LSB) bis D7 (das MSB)
das R/W bit ("Read/Write"): 0 = zum LCD schreiben, 1 = vom LCD lesen
das RS bit ("register select"): 0 = die Daten gehören in eins der LCD Register, 1 = die Daten gehören ins DD oder ins CG RAM

Kjion
07.02.2004, 18:07
Das mit den 10 Bit stimmt schon ;)

8-Bit Daten ( D0 - D7 ), 2-Bit Steuerleitungen ( RS, R/W ).

MfG Kjion

07.02.2004, 18:21
jap is schon klar, aber was hat das mit den kommandos zu tun? werden die über die leitungen übertragen? ich hätt geglaubt die werden in 2 takten über d4 - d7 übertragen..

jörg
07.02.2004, 18:52
Die Tabelle beschreibt ja nur, was das LCD braucht: 8 bit für die Daten, und 2 bit zur Steuerung (damit Du dem LCD sagen kannst, was Deine 8 bit bedeuten sollen).

Wenn Du das LCD im 8-Bit mode betreibst, musst Du die 8 Datenbits D0 bis D7 und die Steuerbits R/W und RS richtig anlegen und das mit einem Toggle auf der zusätzlichen E-Leitung ("chip enable") dem LCD signalisieren. Du brauchst also insgesamt 8 + 2 + 1 = 11 Leitungen von Deinem Controller zum LCD.

Wenn Du aber das LCD im 4-Bit mode betreibst, musst Du die 8 Datenbits
in zwei "Takten" übertragen: zuerst die höherwertigen 4 bits, dann die niederwertigen; diese bits müssen jedesmal an die 4 höherwertigen bits des LCD angelegt werden, also an die LCD Leitungen D4 bis D7; und bei beiden Takten müssen auch wieder R/W und RS richtig angelegt sein, und Du musst das Chip enable E togglen. Insgesamt brauchst Du damit 4 + 2 + 1 = 7 Leitungen von Deinem Controller zum LCD. Du hast also 4 Leitungen gespart, musst aber jedes Byte in zwei Takten übertragen.

07.02.2004, 19:14
"diese bits müssen jedesmal an die 4 höherwertigen bits des LCD angelegt werden" -- meinst du niederwertigen?

also hat das nix damit zu tun, dass zB beim kommando cursor home (0000000010) über der port d1 gesetzt ist? ich versteh ja dass die daten im niederwertigen teil des byteports in 2 takten übertragen werden, also zuerst hi- und dann lo-nibble!

aber wie kann man ein 10-bit-langes kommando senden, wenn man in 2 takten 4 bits sendet (4*2 = 8!) und was haben die spaltenüberschriften mit den kommandobits zu tun?

jörg
07.02.2004, 20:01
"diese bits...": Jetzt kapiere ich das Missverständnis:
Ich meine die LCD Datenleitungen D4 bis D7 (das ist halt so festgelegt beim 4 bit mode des LCD), und das sind die 4 höherwertigen bits des LCD im 8-bit modus.
Bei der CC1 sind diese 4 Leitungen D4 bis D7 üblicherweise verdrahtet mit Port[9] bis Port[12], und das sind die 4 niedrigwertigen Bits des byteport[2]; die LCD Leitungen D3 bis D0 sind nicht zur CC1 verdrahtet.


"also hat das...":

Wenn Du das cmd "CursorHome" zum LCD schicken willst, musst Du dem LCD irgendwie sagen: "RS=0" und R/W=0" und "Daten=0000 0010".

Im 8-bit modus könntest Du das in einem einzigen "Ausgabe-Takt" erledigen:
OUT 0 nach RS
OUT 0 nach R/W
OUT 0000010 nach D7..D0
TOGGLE E
(Insgesamt gibst Du dabei 2 + 8 + 1 = 11 bits ans LCD aus)

Im 4-bit modus brauchst zu zwei Takte:
Zuerst Takt 1:
OUT 0 nach RS
OUT 0 nach R/W
OUT 0000 nach D7..D4
TOGGLE E
Dann Takt 2:
OUT 0 nach RS
OUT 0 nach R/W
OUT 0010 nach D7..D4
TOGGLE E
(Jeder Takt gibt 2 + 4 + 1 = 7 bits ans LCD aus!)

Bei der CC1 benutzt Du dafür das Unterprogramm LCD_WRITE (oder so ähnlich);
das kann sowieso nur schreiben - deshalb brauchst du das R/W bit nie angeben;
auch das E-bit zum Togglen wird automatisch gemacht -- Du siehst es deshalb nicht.
Du musst nur noch sagen, ob Du ein ASCII char meinst(LCD_WRITECHAR), oder ein Kommando (LCD_WRITECMD),
und welche Daten Du senden willst (alle 8 bits, in einem byte).
Abhängig davon wird im Unterprogramm das RS bit zum LCD gesetzt, und dann Dein Byte in den zwei Takten zum LCD übertragen - zuerst das höhere Halbbyte, dann das niedere.

chris152
07.02.2004, 20:20
edit: aus Datenschutzgründen entfernt

chris152
07.02.2004, 20:22
edit: aus Datenschutzgründen entfernt

jörg
07.02.2004, 21:36
Also:

Die Tabelle beschreibt die Bits und die Daten, die das LCD versteht; die Tabelle beschreibt NICHT einen Übertragungsmodus. Nur im 8-bit mode kann man sagen: "ich schicke die Datenbits 00000010 direkt an die pins D7..D0 des LCD (in einem einzigen Takt)".

Die gesetzten RS bits bei den beiden letzten Zeilen sagen genau das Gegenteil, nämlich: Das sind DATEN. Alle Zeilen davor haben RS=0 und sind deshalb KOMMANDOS.

Wenn Du die D-Bits "0000 0010" ans LCD schickst, je nach Modus in einem oder in zwei Takten, heisst das für das LCD:
Entweder
"Führe das Kommando CursorHome aus", nämlich genau dann, wenn RS=0 und R/W=0
oder
"Schreibe HEX 02 ins aktuelle RAM an die aktuelle Position und inkrementiere bzw. dekrementiere die Position dann", nämlich wenn RS=1 und R/W=0
oder
"Lies das nächste Zeichen aus dem aktuellen RAM von der aktuellen Position und inkrementiere bzw. dekrementiere die Position dann", nämlich genau wenn RS=1 und R/W=1 (Du darfst dann allerdings keine D-Bits schreiben, sondern muss sie ja lesen, notfalls wieder in 2 Takten).
oder
"Zeige mir das Busy Flag", nämlich genau wenn RS=0 und R/W=1 (Du darfst dann wieder keine D-Bits schreiben, sondern muss sie lesen, notfalls wieder in 2 Takten).

In der Praxis musst Du nie das Busy Flag vom LCD lesen, wenn Du in CBASIC programmierst - Dein Programm ist sowieso immer langsamer als das LCD. Deshalb wirst Du RS=0 und RW=1 nie verwenden.

Auch "Daten vom LCD lesen" benutzt Du normalerweise nicht -- normalerweise willst Du ja Daten zum LCD schreiben, und nicht nachschauen, was gerade auf dem LCD steht. Deshalb wirst Du auch RS=1 und RW=1 kaum verweden.

Bleibt also übrig:
RW=1 (das heisst: Du schreibst was ans LCD),
und da musst Du halt sagen, was das LCD mit den D-Bits anfangen soll:
Entweder schickst Du ein Zeichen, das das LCD anzeigen soll (RS=0),
oder Du schickst ein Kommando, das das LCD ausführen soll, wie z.B. "CursorHome" (RS=1).


Vielleicht solltest Du Dir die Tabelle etwas anders hinschreiben, nämlich:

1. Mit R/W gibt man an, ob zum LCD geschrieben wird (R/W=0), oder ob vom LCD gelesen wird (R/W=1, wird selten benutzt).
Wenn man wirklich mal vom LCD lesen will (R/W=1), darf man natürlich nichts auf die D-Bits schreiben - die will man ja gerade lesen, das müssen also ein Eingabe-Ports sein.

2. Mit RS gibt man an, welcher Teil des LCD betroffen ist. Betroffen ist entweder das LCD RAM (RS=1), oder es ist ein "LCD Kommando-Register" (RS=0).
Wenn man ins LCD DD-RAM schreibt (RS=1), muss man in den D-Bits das ASCII-Zeichen angeben, das man anzeigen will; wenn man ausnahmsweise mal aus dem LCD RAM lesen will, darf man natürlich keine D-Bits schreiben, sondern muss sie lesen.
Wenn man in ein LCD Register schreibt (RS=0), führt man ein Kommando aus, und man muss dann in den D-Bits angeben, welches der 8 Kommandos das sein soll; einige dieser 8 Kommandos haben noch Zusatz-Bits wie z. B. "I/D" bei "EntryModeSet".
Register lesen geht nicht, nur Busy Flag lesen geht, aber das braucht man in CBASIC nicht.

3. Die 8 D-Bits übergibt man natürlich nur, wenn man zum LCD schreibt (also nicht, wenn man ausnahmsweise mal vom LCD liest).
Je nach Mode gehen die 8 bits in einem Takt rüber (8 bit mode), oder in 2 Takten (4 bit mode).
Welchen mode man benutzt, hängt von der Beschaltung ab: Wenn ausser dem E-Bit und den Steuer-Bits RS und R/W auch noch alle 8 D-Bits beschaltet sind, kann man den 8 bit mode benutzen. Wenn statt dessen nur die D-Bits D4..D7 beschaltet sind, geht (nur) der 4 bit mode, der dann zwar zwei Takte pro Byte braucht, aber dafür schon mit 7 bit-Ports auskommt (im Gegensatz zu 11 bit-Ports für den 8 bit mode).

08.02.2004, 08:10
ok vielmals thx, warum kennst du dich da so gut aus bzw. empfiehl mir ein paar seiten!
thx

jörg
08.02.2004, 14:33
Na ja, ich mache seit 30 Jahren Software, und da sollte ein LCD schon drin sein. Ausserdem war das weniger eine Software-Frage von Dir , als eine Gedulds-Frage bei mir... (hab's nicht so gemeint: man MUSS so lange fragen, bis man's versteht; und "Verstehen" ist kein Problem des Fragenden, sondern des Anwortenden, denn "Der Empfänger hat immer Recht!")

Datenblatt-Sammlung für diverse LCDs und den Standard-Controller kannst Du Dir bei Conrad runterladen; aber wenn man das Prinzip mal verstanden hat, ist Deine Seite als Zusammenfassung viel nützlicher.

09.02.2004, 19:30
lcd_param = &H38 : gosub LCD_WRITECMD '8-Bit-Modus aktivieren
lcd_port = &H02 'mit 8-Bit-Command in 4-Bit-Modus umschalten
pulse lcd_e '= 2x tog lcd_e
lcd_param = &H28 : gosub LCD_WRITECMD 'ab jetzt 4-Bit-Modus

- wieso wird zuerst der 8-bit-modus aktiviert um danach mit dem kommando home in den 4-bit-modus zu wechseln? das is doch das kommando home!!
- außerdem kann write doch kein 8-bit-kommando schreiben, weil ja geshiftet wird und nur in port 9 bis port 16 geschrieben wird!
- und wozu ist &H28?

jörg
09.02.2004, 21:37
Einiges dazu findest Du auch in dem langen posting vom 30.01.2004, 15:11, Punkt 7 ("INIT"), anderes nicht, deshalb also:

Warum zuerst mit &H38 ("FunctionSet") in den 8-bit-mode -- Ich denke mir das so (bin mir aber nicht ganz sicher):
Niemand kann mit Bestimmtheit sagen, in welchem Modus das LCD beim Aufruf von LCD_INIT ist:
Eigentlich sollte es selbst einen power-on reset gemacht haben und deshalb im 8-bit-mode sein (ist so definiert);
manchmal tut es das aber auch nicht (ist so definiert, zb wenn nicht genug Spannung oder sowas da ist);
wenn aber ein anderer Programm-Zweig schon mal LCD_INIT aufgerufen hat, dann ist es im 4-bit mode.
Deshalb sollte LCD_INIT so geschrieben sein, dass es sowohl bei aktuell laufendem 4-bit, als auch bei 8-bit mode immer in den 4-bit-mode schaltet.
EINE Möglichkeit dazu ist (hab nicht gecheckt, ob's die einzige ist):
Zuerst in den 8-bit mode setzen; dann weiss man woran man ist;
dann in den 4-bit mode setzen; da will man ja hin;
dann im 4-bit-mode alles weitere sagen, denn die Routinen braucht man eh.

Deshalb also zuerst &H38 mit LCD_WRITE_CMD schicken, denn:
Im 4-bit mode ist das das Command "FunctionSet" (bits 001) mit Parametern DL=1="8-bit-mode" (die folgenden Parameter sind auf der HTML-Seite nicht beschrieben: N=1= "2 Zeilen-Display" und F=0= "5x7 characters in 5x8 Matrix").
Im 8-bit-mode gibt diese Ausgabe etwas Mist, aus zwei Gründen:
Erstens gibt LCD_WRITE ja in zwei Takten aus, aber das sind dann im 8-bit-mode für das LCD auch ZWEI Befehle.
Und zweitens sind ja gar nicht alle 8 Datenleitungen des Port zum LCD durchkontaktiert, sondern nur die niedrigwertigen 4 bits des Port auf die höherwertigen vier Datenleitungen des LCD; die niedrigwertigen DL's des LCD hängen in der Luft.
Das LCD erhält also irrtümlich zwei Commands:
&B0011xxxx (FunctionSet, DL=8 bit), und &B1000xxxx (SetDDRAM): Aber OK, ist kein Beinbruch.

Immerhin: Jetzt sind wir also definitiv im 8-bit-mode.
Im Gegensatz zu vorhin (Ausgabe mit LCD_WRITE) legen wir jetzt das Byte &H02 DIREKT an den LCD_PORT an. Das ist also NICHT das Command "02=CursorHome" -- wird ja nicht mit LCD_WRITE ausgegeben; sondern:
Auf grund der Hardware-Kontaktierung stehen im höherwertigen Halbbyte des Port die Steuerleitungen zum LCD (hier: R/W=0 "write", RS = 0 = "RegisterSelect"), und im niederwertigen Halbbyte des Port die 4 HÖHERWERTIGEN Datenbits für's LCD (ist ja so verdrahtet für den 4-bit-mode!!)
Folglich bedeutet die DIREKTE Portausgabe &H02=&B00000010 für das LCD das Command $B0010xxxx, und das ist "FunctionSet" mit DL=0= "4-bit-mode" (restliche bits sind wieder undefiniert, weil nicht kontaktiert).

So: Jetzt sind wir also definitiv endlich im 4-bit-mode.
Das &H28 wird mit LCD_WRITECMD ausgegeben, ist also ein command und bedeutet fast dasselbe wie das vorher das &H02 direkt am Port angelegt, nämlich wieder "FunctionSet" mit DL=0= "4-bit-mode", aber jetzt können wir auch die restlichen bits definiert setzen und damit "2 Zeilen" und "5x8 Matrix" sagen (ähnlich wie vorher &H38 für den 8-bit-mode).


Falls sich tatsächlich ein Hardware-Entwickler das ABSICHTLICH so VORHER überlegt hatte, kann ich nur sagen: Muss Des-sign? -- Aber lass Dich nicht abschrecken: es gibt auch Einfacheres!

10.02.2004, 19:21
weiß das wer?

11.02.2004, 18:32
Und dann würd ich noch gern wissen, obs egal ist, ob man sich im cg- oder dd-ram befindet, wenn man ein kommando schreibt.
danke für eure hilfe!!!!

11.02.2004, 18:38
oops sorry, hab net gesehen dass es auf der 2. seite weiterging ..
warum muss man zweimal in den 4-bit-modus wechseln, einmal mit 8-bit-command und dann nochmal mit &H28?

11.02.2004, 18:40
und vielmals thx, ich hoff es macht dir nix, soviel zu erklärn ;)

jörg
12.02.2004, 12:04
DD/CG RAM:
Register schreiben ( = Commands schicken) kann man unabhängig vom grad selektierten RAM.
Nur wenn man Daten schreibt (oder liest), muss man wissen, was gerade selektiert ist (CGRAM muss man nur selektieren, wenn man Zeichen programmieren will).

Zwei mal in 4-bit-mode:

1. Umschaltung mit &H02 direkt am Port:
OK: Wenn man im 8-bit-mode ist, und die &H02 direkt an den LCD_PORT anlegt, schaltet man in den 4-bit mode um. ABER: Es sind ja gar nicht nicht alle 8 Datenleitungen zum LCD durchkontaktiert. Das LCD erhält also an seinen 8 Datenleitungen nur die bits $B0010xxxx, wobei die 'x' undefiniert sind. Das LCD erkennt deshalb zwar das Command 001="FunctionSet" mit DL=0= "4-bit-mode", aber die restlichen beiden Bits für "Zeilen-Zahl" und "Matrix-Grösse" können nicht gesetzt werden.

2. Deshalb im 4-bit-mode Kommando &H28
Die Zeilenzahl und die char Matrix kann man nur mit FunctionSet angeben, deshalb (nochmal) FunctionSet sagen (und dabei im 4-bit-mode bleiben), und jetzt auch die beiden bits für "2 Zeilen" (N=1) und "5x8 Matrix" (F=0) setzen; das geht ja jetzt, weil das ganze Command in 2 Takten über den 4-bit-Bus übertragen wird.

Mach nix, sooo genau hatte ich's vorher auch nicht angeschaut...

12.02.2004, 17:05
danke!!
was wär ein tag ohne dass ich wieder ohne irgendwo ein prob zu haben ..

die terminal-dateien spielen irgendwie verrückt. manche programme gehen, manche gehen wieder nicht. nach einiger zeit funktioniert das programm wieder mit der terminal-datei und dann wieder net!! ich hab schon alle einstellungen ausprobiert. im geräte-manager steht bei flusssteuerung "keine". vielleicht weiß wer was ich da immer falsch mache..

jörg
12.02.2004, 17:15
was heisst: "terminal-dateien", und was heisst "geht / geht nicht" ?

12.02.2004, 17:33
wow du bist ja schnell *gg* naja den hyperterminal (start --> alle programme --> zubehör --> kommunikation --> hyperterminal) mit dem man die ausgaben anzeigen kann, also das was an die serielle schnittstelle gesendet wird vom mikrocontroller mit print bzw. put und eingaben kannst auch machen mit get oder input.
ja ich hab jetzt zwei programme geschrieben, eins für die folientastatur, und eins mit menü, wo man das lcd steuern kann .. kann ich auch reinschreiben, wenn du willst. und manchmal funktioniert das menü-programm mit der terminal-datei, also wenn ich zB was eingebe, was auf dem lcd stehen soll, das wird dann passend hingeschrieben, aber manchmal kann ich im terminal tippen was ich will und nix passiert.

jörg
12.02.2004, 17:53
Seit irgend einem windows update geht meine hyterterminal nicht mehr ("DLL fehlt"); drum benutze ich immer das TERMINAL.EXE. Aber ich erinnere mich an probleme im zusammenhang mit download des programms in die CC1; ich glaube, ich musste das HT vorher beenden und neu starten, oder so.
PS: du drückst schon den START-Knopf an der cc1 (LED leuchtet)?
PPS: meine test-programme fangen meistens mit einem PRINT an, damit ich sehen kann, ob das richtige Programm in der CC1 geladen ist. Bau doch das mal ein und probiers dann.

14.02.2004, 15:19
Ok thx funktioniert trotzdem manchmal nicht :(

Zu nem andern Thema: Ich hab gelesen dass nach nem Reset (Stromversorgung aus, dann an) der Inhalt des CG- und DD-RAMs nicht initialisiert sei. Aber bei nem Reset werden die RAMs doch geleert, das is dann doch ein Widerspruch.
Wohin zeigen eigentlich die Adresszeiger nach nem Reset?

jörg
14.02.2004, 19:20
Power-Up:
Wenn das LCD power-up ordentlich mitkriegt, macht es selbst einen Init (in den 8-bit-mode); dabei wird auch das DD-RAM mit SPACE gelöscht und initialisiert.

Der programmierte INIT init macht im Prinzip dasselbe, nur in den 4-bit-modus. Dabei ruft man üblicherweise das Command "clear" auf, und das löscht das DD-RAM mit SPACE und positioniert auf das erste Zeichen.

Das CG-RAM wird nicht angefasst, hat also zufälligen Inhalt. Bei mir steht manchmal noch drin, was ich vorher reingeschrieben hatte; meistens aber sind mindestens einige bits gekippt.

14.02.2004, 19:30
danke .. wenn clear sowieso aufs erste zeichen positioniert, wozu is dann noch home und wozu is dann noch gotoline1 wenns home und clear gibt *gggg*
befindet sich der Address counter nach strom ab und an an der home-pos. des dd-rams?

14.02.2004, 19:32
ähm, kennst du ne seite im net wo das mit dem reset steht?

jörg
14.02.2004, 19:43
CLS: Stimmt: HOME usw. ist wohl überflüssig nach CLS.

power-up: Ja, ist gesetzt, falls das LCD das ordenlich mitgekriegt hat (das LCD macht intern dann auch CLS). Nutzt aber mir nix, weil ich den 4-bit-mode brauche.

Die Beschreibung, mit RESET und allem drum und dran, gibts bei Conrad im Netz, irgendwo bei den LCDs. Die Hitachi-Beschreibung auf S. 195 / Fig. 11 + 12 ist aber falsch: da fehlen die bits, und ausserdem fehlt SetDDRAM und ReadBusy.

psycho
15.02.2004, 15:10
Auf dem Bild http://www.c-control.de/bilder/main_unit_gross.jpg hier, is der Microcontroller die eine schwarze Platine mit dem Motorola-Logo oder ist das nur die CPU (ohne Watchdog, Oscillator usw.).
Gibtsn Unterschied zwischen MC68HC05 und MC68HC05B6?

jörg
15.02.2004, 16:42
Der grosse quadratische schwarze Chip mit dem Motorola-Logo, das ist der Microcontroller vom Typ MC68HC05B6 (die reine CPU, mit dem im Chip enthaltenen ROM, EEPROM, RAM...).
Links oben davon der längliche schwarze IC (2x8) ist der RS232 Treiber.
Links unten der kleinere IC (4x2) ist das EEPROM für die CBASIC Programme.
Der Quarz ist unterhalb der CPU.
Der Rest sind Leds, START/RESET-Schalter, Jumper... und vor allem jede Menge Anschluss-Pins, entweder direkt an die CPU, oder auch an die RS232-Schnittstelle.

Wirkt auf dem Bild viel grösser, ist aber nur etwa 55 x 70 mm klein.

Die ganze Platine heisst "C-Control Steuercomputer", und wird von der Idee her komplett wie sie ist huckepack auf ein weiteres Board gesteckt, z. B. auf das "C-Control Application Board". Man kann aber auch den MC "solo" kaufen und auf ein eigenes Board stecken.

MC68HC05 ist eine Motorola Prozessor-Familie; die Mitglieder unterscheiden sich vor allem im on-chip Speicherausbau (ROM, EEPROM, RAM), sind aber gleich zu programmieren (so viel ich weiss).
Die MC68HC05B6 ist ein Mitglied dieser Familie; wenn Motorola speziell das CBASIC "Betriebssystem" ins ROM gebrann hat, ist es die CC1 von Conrad geworden.

psycho
15.02.2004, 17:18
wozu braucht der mc68hc05 eigens wieder nen eeprom, wenn eh einer auf der c-control unit druff is?

Matthias
15.02.2004, 18:02
@jörg: Auf den meißten cc ist ein MC68HC705B16, der sich aber wie ein 05B6er handhaben lässt.
@psycho: Das externe E²prom is für das Basic-programm. Das Interne für das "Betriebssystem" und ein kleines bisschen Assembler.

Matthias

psycho
16.02.2004, 11:37
aha ..
der mikrocontroller verfügt ja über ports a bis d, in welchem zusammenhang stehen die mit den 16 digitalleitungen, 2 pwm und 8 analogeingängen?

jörg
16.02.2004, 13:56
Die Ports A bis D des MC sind Byte-Ports und bestehen jeweils aus 8 unabhängige Bit-Ports.
Port A ist in der CC1 für das Betriebssystem verbraten.
Port B und C sind zusammen die 16 digitalen IN / OUT ports.
Port D wird üblicherweise als 8 analoge IN ports konfiguriert.
Die analogen Ausgänge sind nochmal zwei unabhängige OUT Ports (PWM).

psycho
16.02.2004, 16:27
kanns nicht sein dass es sich beim port b um ad[8] handelt? bei den ports a bis d handelt sichs nur um digiports?? vielleicht kannst du mir mal deine mc-linksammlung per mail schicken, das wär was *gg*

weils ja nur 2 byteports gibt..

jörg
16.02.2004, 17:08
NÖ, ist schon so:

Den MC "PORTA" gibts bei CBASIC nicht; da liegen bei der CC1: I2C bus, LEDs, START Schalter, RTS, CTS
"PORTB" heisst in CBASIC wahlweise "port[1]" bis "port[8]" (als bit ports), oder alle 8 zusammen "byteport[1]"
"PORTC" heisst "port[9]" bis "port[16]", oder "byteport[2]"
"PORTD" ist auf A/D eingestellt und heisst "ad[1]" bis "ad[8]"
"PLMA" heisst "da[1]", und "PLMB" heisst "da[2].

psycho
16.02.2004, 20:33
ok, dann is ad[8] nicht port b sondern port d?? hab dazu im net nämlich keine infos gefunden!

psycho
17.02.2004, 19:27
??

jörg
17.02.2004, 22:21
ja, ad[8] gehört zum Port D.

Auch ad[1] bis ad[7] gehören zum Port D, denn der Port D hat ja 8 bits (ist ein Byte-Port). Und alle 8 bits hängen intern standardmässig am Analog-Digital-Konverter, sind deshalb also A/D-Ports.

psycho
23.02.2004, 20:25
wisst ihr wo ich rausfinden kann, wo die leds, folientastatur, lcd usw. in c-control bzw. in assembler dranhängen?

bis jetzt weiß ich nur folgendes:

lcd: byteport[2]
folientastatur: ad[8]
leds irgendwo an port a (obwohl der ja eigentlich fürs betriebssystem reserviert is, wie kann das sein?)

24.02.2004, 17:26
weiß das wer?

jörg
27.02.2004, 23:34
Wo was (standardmässig) dran hängt, steht in den Schaltplänen, z. B. ApplicationBoard.
Am PORTA hängen die System-LEDs; die kannst Du nicht direkt programmieren.
Die eigenen LEDs kannst Du an jeden freien Port hängen.