Forum: Mikrocontroller und Digitale Elektronik LCD HD44780 CG Ram Adresse per Arduino


von Schmidolin (Gast)


Lesenswert?

Hallo erstmal :D

Ich verwende den Arduino Mega 2560 und Atmel Studio für die 
Programmierung. Ich will nun einen LCD (HD44780) verwenden und es 
funktioniert nun auch alles perfekt. Alle Buchstaben und Zeichen werden 
korrekt dargestellt, Cursor durch DDRAM Adressierung auf bestimmte 
Positionen setzten, Bildschirm löschen, etc...

Jedoch will ich nun auch eigene Symbole darstellen und die im CGRam 
speichern. Die dafür notwendigen Adressen beginnen ja ab 0x40 (Hex) bzw. 
64 (Decimal) bzw. 0100 0000 in Bit darstellen (Databit 7 bis Databit 0) 
und enden bei Startadresse + 64 Bit. Wenn ich nun aber den Befehl für 
"Set CGRam address" dem LCD übergebe, also RS = 0; RW = 0; DB7 = 0; DB6 
= 1; DB5 bis DB0 = 0 (für Startadresse des CGRam) dann reagiert der LCD 
lediglich mit einem Cursor-Shift auf die Position 64 (Decimal) - Zeile 
2, Spalte 1. Ist dies noch jemanden bekannt oder kann man sagen was hier 
falsch ist? Wenn es irgendwas mit der Pin Belegung wäre, würden ja auch 
die übergebenen Zeichen falsch dargestellt werden, dem aber nicht so 
ist. Evntl. liegt es an der Programmierung....

LG

Set Ram Location:
1
// LCD data pin setup for CG RAM line address command
2
void lcd_setCGRamLocation(int32_t location)
3
{
4
  // Custom char address start at 64 (decimal) in CG RAM
5
  set_HighLowToggle(lcd_db7, "low");
6
  set_HighLowToggle(lcd_db6, "high");
7
  
8
  if (location == 1)
9
  {
10
    // Set CG RAM address to custom char 1 address
11
    set_HighLowToggle(lcd_db5, "low");
12
    set_HighLowToggle(lcd_db4, "low");
13
    set_HighLowToggle(lcd_db3, "low");
14
    set_HighLowToggle(lcd_db2, "low");
15
    set_HighLowToggle(lcd_db1, "low");
16
    set_HighLowToggle(lcd_db0, "low");
17
  }
18
  else if (location == 2)
19
  {
20
    // Set CG RAM address to custom char 2 address
21
    set_HighLowToggle(lcd_db5, "low");
22
    set_HighLowToggle(lcd_db4, "low");
23
    set_HighLowToggle(lcd_db3, "high");
24
    set_HighLowToggle(lcd_db2, "low");
25
    set_HighLowToggle(lcd_db1, "low");
26
    set_HighLowToggle(lcd_db0, "low");
27
  }
28
  else if (location == 3)
29
  {
30
    // Set CG RAM address to custom char 3 address
31
    set_HighLowToggle(lcd_db5, "low");
32
    set_HighLowToggle(lcd_db4, "high");
33
    set_HighLowToggle(lcd_db3, "low");
34
    set_HighLowToggle(lcd_db2, "low");
35
    set_HighLowToggle(lcd_db1, "low");
36
    set_HighLowToggle(lcd_db0, "low");
37
  }
38
  else if (location == 4)
39
  {
40
    // Set CG RAM address to custom char 4 address
41
    set_HighLowToggle(lcd_db5, "low");
42
    set_HighLowToggle(lcd_db4, "high");
43
    set_HighLowToggle(lcd_db3, "high");
44
    set_HighLowToggle(lcd_db2, "low");
45
    set_HighLowToggle(lcd_db1, "low");
46
    set_HighLowToggle(lcd_db0, "low");
47
  }
48
  else if (location == 5)
49
  {  
50
    // Set CG RAM address to custom char 5 address
51
    set_HighLowToggle(lcd_db5, "high");
52
    set_HighLowToggle(lcd_db4, "low");
53
    set_HighLowToggle(lcd_db3, "low");
54
    set_HighLowToggle(lcd_db2, "low");
55
    set_HighLowToggle(lcd_db1, "low");
56
    set_HighLowToggle(lcd_db0, "low");
57
  }
58
  else if (location == 6)
59
  {
60
    // Set CG RAM address to custom char 6 address
61
    set_HighLowToggle(lcd_db5, "high");
62
    set_HighLowToggle(lcd_db4, "low");
63
    set_HighLowToggle(lcd_db3, "high");
64
    set_HighLowToggle(lcd_db2, "low");
65
    set_HighLowToggle(lcd_db1, "low");
66
    set_HighLowToggle(lcd_db0, "low");
67
  }
68
  else if (location == 7)
69
  {
70
    // Set CG RAM address to custom char 7 address
71
    set_HighLowToggle(lcd_db5, "high");
72
    set_HighLowToggle(lcd_db4, "high");
73
    set_HighLowToggle(lcd_db3, "low");
74
    set_HighLowToggle(lcd_db2, "low");
75
    set_HighLowToggle(lcd_db1, "low");
76
    set_HighLowToggle(lcd_db0, "low");
77
  }
78
  else if (location == 8)
79
  {
80
    // Set CG RAM address to custom char 8 address
81
    set_HighLowToggle(lcd_db5, "high");
82
    set_HighLowToggle(lcd_db4, "high");
83
    set_HighLowToggle(lcd_db3, "high");
84
    set_HighLowToggle(lcd_db2, "low");
85
    set_HighLowToggle(lcd_db1, "low");
86
    set_HighLowToggle(lcd_db0, "low");
87
  }
88
}

Send Command to LCD:
1
// Entry write and command mode
2
set_HighLowToggle(lcd_rw, "low");
3
set_HighLowToggle(lcd_rs, "low");
4
    
5
// Set CG RAM address
6
lcd_setCGRamLocation(location);
7
    
8
// Flush pin to set address
9
set_HighLowToggle(lcd_es, "high");
10
set_HighLowToggle(lcd_es, "low");

Falls es noch Fragen gibt, einfach stellen... :D
Die Methode set_HigLowToggle ist lediglich zum Arduino Register 
setzen....

von holger (Gast)


Lesenswert?

>  set_HighLowToggle(lcd_db7, "low");

Ich hab ja schon viele umständliche Routinen gesehen
die nichts anderes tun sollten als einen IO Pin zu setzen,
aber das ist echt der Hammer.

von Schmidolin (Gast)


Lesenswert?

holger schrieb:
>>  set_HighLowToggle(lcd_db7, "low");
>
> Ich hab ja schon viele umständliche Routinen gesehen
> die nichts anderes tun sollten als einen IO Pin zu setzen,
> aber das ist echt der Hammer.

bitte auf mein Anliegen eingehen, solch Kommentare sind nicht sehr 
produktiv oder weiß der "Profi" etwa warum das so gemacht wurde bzw. so 
ausschaut?

von Karl H. (kbuchegg)


Lesenswert?

Schmidolin schrieb:
> holger schrieb:
>>>  set_HighLowToggle(lcd_db7, "low");
>>
>> Ich hab ja schon viele umständliche Routinen gesehen
>> die nichts anderes tun sollten als einen IO Pin zu setzen,
>> aber das ist echt der Hammer.
>
> bitte auf mein Anliegen eingehen, solch Kommentare sind nicht sehr
> produktiv oder weiß der "Profi" etwa warum das so gemacht wurde bzw. so
> ausschaut?

Nein.
Aber der Profi weiss, das man sich mit möglichst komplexen dubiosen 
Funktionen immer nur selbst ins Knie schiesst.

Der Profi würde deine komplette Funktion so schreiben
1
    lcd_command( LCD_SET_CGADR | (code<<3) );
(code ist der Zeichencode für den die Bits definiert werden sollen)
und gut ists.

Tu dir selbst einen Gefallen und schreib dir erst mal ein paar 
Hilfsfunktionen wie zb eine Funktion, der du ein Commandobyte übergibst 
und welche dann die erforderlichen Aktionen ausführt um ein Kommando 
(egal welches) an das LCD zu übergeben.

Dann ist schon mal der ganze Themenkreis "was kann ich bei der Übergabe 
eines Kommandos alles falsch machen" insofern vom Tisch, als man das 
einmalig richtig hinkriegt und egal ob das Kommando dann "Clear Screen" 
oder eben "Set CGRAM Address" lautet, die Funktion, die ein Kommando 
überträgt macht das dann richtig ohne dass man sich in jeder Funktion 
wieder neu darum kümmern muss.

Organisation ist in der Programmierung das halbe Leben. Wer sich in 
jeder Funktion wieder neu um den ganzen Kleinkram kümmern muss, hat 
irgendwas nicht richtig verstanden.

von Karl H. (kbuchegg)


Lesenswert?

1
void lcd_setCGRamLocation(int32_t location)

int32_t?
Hast du auch nur den leistens Hauch eines Schimmers, was du deinem Mega 
damit antust?

Es ist ja jetzt nicht wirklich so, dass LCD Routinen für ein 
Standard-LCD rar gesäht wären. Warum studierst du nicht mal, wie andere 
Leute so etwas programmieren? Durch Codestudium anderer kann man viel 
lernen!

Die hier sind zwar nicht unbedingt der Weisheit letzter Schluss, aber an 
und für sich ganz ordentlich aufgebaut.
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
Sieh dir vor allen Dingen an, wie sich die Verarbeitung in einzelne 
Funktionshierarchien gliedert. Wie 'komplexere' Funktionen auf 
'einfachere' Funktionen zurückgreifen um die Drecksarbeit erledigen zu 
lassen und diese einfacheren Funktionen dann wieder auf noch tiefer 
liegende Funktionen zurückgreifen um Aktionsblöcke ausführen zu lassen.

Und noch ein Tip:
Strings willst du nicht wirklich als 'Aktionscode' verwenden. Derartige 
Kommandos benutzt man, wenn man über I/O Schnittstellen (zb UART) mit 
einem anderen Computer kommunizert. Aber innerhalb eines Programms ist 
so etwas unnötig. Da kostet dich die ganze Stringauswerterei mehr an 
Laufzeit als alles andere zusammengenommen.
Wenn du in einem Programm sprechende Namen haben willst (was 
grundsätzlich gut ist), dann versteck den Zahlenwert hinter einem 
#define und gut ists.
Durch
1
#define LOW  0
2
#define HIGH 1
3
4
....
5
6
  set_HighLowToggle(lcd_db7, LOW);
7
8
...
9
10
void set_HighLowToggle( uint8_t bitNr, uint8_t value )
11
{
12
  ...
13
}
kannst du deinen µC schon mal massiv entlasten. Abgesehen davon, dass 
eine derartige Unterscheidung nicht wirklich notwendig ist. Du weisst an 
dieser Stelle, dass du den Pin auf Low haben willst. Es gibt keinen 
Grund das unnötig zu verkomplizieren
1
   set_PinLow( lcd_db7 );
ist völlig ausreichend. Es erspart dir das Nachdenken darüber, wie du 
der eierlegenden Wollmilchsau beibringst, dass du den Pin auf Low haben 
willst und es erspart der Routine die Analyse darüber, was der Aufrufer 
eigentlich will.

von Schmidolin (Gast)


Lesenswert?

Thx für die antworten, das war sowieso das aller erste Programm mit dem 
ich die Funktionsweise herausfinden wollte (das das nicht gerade sehr 
effizient geschrieben ist, ist mir dabei schon klar) - so wie ich das 
jetzt herausgefunden hab, macht man beim setzten der CG Ram Adresse 
einen Cursor shift genau auf diese Adresse und kann den CG Ram 
beschreiben.  Setzt man nun das Bitmuster für die 8x5 lcd Zeilen springt 
der Cursor natürlich pro gesetzter Zeile mit, da ja automatisch 
inkrementiert wird. Das CG Ram Zeichen ist aber richtig gespeichert und 
kann über vorheriges setzen der DD Ram Adresse und anschließendes 
beschreiben wieder aufgerufen und dargeatellt werden. Das ein Cursor 
shift beim setzen der CG Ram Adresse durchgeführt wird hat mich nur 
verwirrt, da das nirgendwo beschrieben wird. Muss ich dann noch testen 
ob das nur bei mir jetzt ein Fehler ist, oder auch bei anderen so ist.

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.