Forum: Mikrocontroller und Digitale Elektronik Eigene Zeichen auf EA DOGM162


von David G. (ded)


Lesenswert?

Hi,

ich spiele gerade ein wenig mit einem EA DOGM162L-A Display von 
Electronic Assembly rum. Funktioniert so weit auch alles super. 
Allerdings wollte ich nun noch ein paar selbstdefinierte Zeichen 
ausgeben lassen. Das Feld wo das Zeichen ausgegeben werden soll bleibt 
aber leer. Hat jemand eine Idee woran das liegen könnte? Programmiert 
wird ein M16C28 in C über HEW4. Ansteuerung des Displays erfolgt via 
SPI. Vielen Dank für die Hilfe.

Gruß David.

P.S.: Hier mein Code dazu:
1
void generate_char(char adress, const char *data){  // erzeugt eigenes Zeichen
2
  int i;
3
  RS=0;
4
  send_command(adress);              // CG RAM Adresse setzen
5
  
6
  for (i=0;i<8;i++){
7
    send_char(data[i]);              // Bitmuster übertragen
8
  }
9
  RS=0;
10
  send_command(0x80);                // DD_RAM Adresse 0 setzen
11
}
12
13
void arrow_up(int line, int pos){
14
  char arrow_up[8] = {               // Bitmuster erstellen
15
    0b00000000,
16
    0b00000100,    //  #
17
    0b00001110,    // ###
18
    0b00010101,    //# # #
19
    0b00000100,    //  #
20
    0b00000100,    //  #
21
    0b00000100,    //  #
22
    0b00000000
23
  };
24
  generate_char(CHAR0_ADR, arrow_up); // Zeichen erstellen  
25
  set_cursor(line, pos);              // Cursor setzen
26
  send_char(LCD_GC_CHAR0);            // Zeichen ausgeben
27
}

von spess53 (Gast)


Lesenswert?

Hi

>send_command(adress);              // CG RAM Adresse setzen

Wie sieht denn 'adress' aus?

MfG Spess

von David G. (ded)


Lesenswert?

Hi,

'adress' wird hier "generate_char(CHAR0_ADR, arrow_up);" übergeben und 
ist mit 0x40 definiert. Das müsste ja die Startadresse des CG RAM sein.

von spess53 (Gast)


Lesenswert?

Hi

>Das müsste ja die Startadresse des CG RAM sein.

Ist richtig.

>  RS=0;
>  send_command(adress);              // CG RAM Adresse setzen

>  for (i=0;i<8;i++){
>    send_char(data[i]);              // Bitmuster übertragen
>  }
>  RS=0;
>  send_command(0x80);

Setzt 'send_char' RS selbst auf 1? Wenn nicht, fehlt RS=1.

MfG Spess

von David G. (ded)


Lesenswert?

send_char ist eine Funktion, welche Chars auf das Display ausgibt. Ist 
die gleiche Funktion wie send_command, eben nur mit dem vorgeschobenen 
RS=1.

von David G. (ded)


Lesenswert?

Keine zündenden Ideen? Irgendjemand?

von David G. (ded)


Lesenswert?

push

von David G. (ded)


Lesenswert?

Letzter Versuch. Kann wirklich niemand helfen?

von spess53 (Gast)


Lesenswert?

Hi

>Letzter Versuch. Kann wirklich niemand helfen?

Mit den Codeschnipseln nicht.

MfG Spess

von Ralle (Gast)


Lesenswert?

versuche mal das Zeichen auf Adresse 1 und nicht 0 zu generieren,
hatte da auch mal schwierigkeiten mit.

Ralle

von David G. (ded)


Lesenswert?

Hi,

@Ralle: Danke für den Tipp. Das Ergebnis bleibt aber leider das gleiche.

@spess53: Welche Informationen benötigst du denn noch? Hier zumindest 
noch die fehlenden Funktionen:
1
void send_command(char byte) {  //sendet einen Befehl an das LCD
2
  CSB=0;
3
  for(i=0;i<8;i++){
4
    CLK=0;
5
    SI=0;
6
    if(byte & 0x80){
7
      SI=1;
8
    }
9
    byte <<= 1;
10
    CLK=1;
11
  }
12
  CSB=1;
13
}
14
15
void send_char(char byte) {    //sendet ein Zeichen an das LCD
16
  RS=1;
17
  send_command(byte);
18
}

von Ralle (Gast)


Lesenswert?

rufst du das auch auf

void arrow_up(int line, int pos){
  char arrow_up[8] = {               // Bitmuster erstellen
    0b00000000,
    0b00000100,    //  #
    0b00001110,    // ###
    0b00010101,    //# # #
    0b00000100,    //  #
    0b00000100,    //  #
    0b00000100,    //  #
    0b00000000
  };

Ralle

von David G. (ded)


Lesenswert?

Selbstverständlich wird das aufgerufen. Mit
1
 arrow_up(2,0);

von Ralf G. (ralg)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Letzter Versuch. Kann wirklich niemand helfen?
>
> Mit den Codeschnipseln nicht.
>
> MfG Spess

David G. schrieb:
> void arrow_up(int line, int pos){
>   char arrow_up[8] = {               // Bitmuster erstellen
>     0b00000000,
>     0b00000100,    //  #
>     0b00001110,    // ###
>     0b00010101,    //# # #
>     0b00000100,    //  #
>     0b00000100,    //  #
>     0b00000100,    //  #
>     0b00000000
>   };
>   generate_char(CHAR0_ADR, arrow_up); // Zeichen erstellen
>   set_cursor(line, pos);              // Cursor setzen
>   send_char(LCD_GC_CHAR0);            // Zeichen ausgeben

Hier sieht das nämlich so aus:
'generate_char': Aufruf mit Adresse und einer Funktion
'arrow_up': erzeugt für sich persönlich ein Array (wozu sind 'line' 
und 'pos'?)
'send_char': was ist 'LCD_GC_CHAR0'

von David G. (ded)


Lesenswert?

CHAR0_ADR ist wie oben schon beschrieben 0x40, also die Startadresse des 
CG RAM. Und arrow_up ist ein Array, welches das Muster beinhaltet und 
zeilenweise in den CG RAM geschrieben wird. Line und pos bestimmen 
lediglich an welcher Stelle das Symbol ausgegeben wird. Stand hier so in 
dem Artikel dass nach einem selbstdefinierten Zeichen eine Position 
vorgegeben werden muss.

LCD_GC_CHAR0 entspricht einfach nur einer Null, da die selbstdefinierten 
Zeichen ja in die ersten acht Adressen des Data RAM, also 0-7, 
geschrieben werden. Oder sehe ich hier irgendetwas falsch?

von Ralf G. (ralg)


Lesenswert?

Ralf G. schrieb:
> 'arrow_up': erzeugt für sich persönlich ein Array (wozu sind 'line'
> und 'pos'?)
!!

David G. schrieb:
> Und arrow_up ist ein Array, welches das Muster beinhaltet
Ja, aber nicht lange!

David G. schrieb:
> Selbstverständlich wird das aufgerufen. Mit arrow_up(2,0);
Und was passiert mit der 2 und der 0?

von spess53 (Gast)


Lesenswert?

Hi

>Selbstverständlich wird das aufgerufen. Mit
> arrow_up(2,0);

Das passt aber nicht zu dem:.

>void generate_char(char adress, const char *data){  // erzeugt eigenes >Zeichen
>  int i;
>  RS=0;
>  send_command(adress);              // CG RAM Adresse setzen

>  for (i=0;i<8;i++){
>    send_char(data[i]);              // Bitmuster übertragen
>  }
>  RS=0;
>  send_command(0x80);                // DD_RAM Adresse 0 setzen
>}

Du übergibst 'send_command(adress)' eine 2. Da fehlt der Befehl 'Set 
CGRAM' (0b01000000) und die Adresse muss ein Vielfaches von 8 sein.

MfG Spess

von David G. (ded)


Lesenswert?

Ralf G. schrieb:
>> Und arrow_up ist ein Array, welches das Muster beinhaltet
> Ja, aber nicht lange!

Wieso nicht lange? Kannst du mir das bitte erklären?

Ralf G. schrieb:
>> Selbstverständlich wird das aufgerufen. Mit arrow_up(2,0);
> Und was passiert mit der 2 und der 0?

Na die 2 steht für die Zeile(1,2) und die 0 für die Position(0...15).

Vielen Dank für deine Geduld mit mir =)

von Ralf G. (ralg) (Gast)


Lesenswert?

1. Du rufst eine Funktion (arrow_up) mit zwei Parametern auf, die in der 
Funktion nicht weiter verwendet werden. (?)
2. Die Variable (arrow_up) in der Funktion (auch arrow_up) wird 
initialisiert und das war's auch schon. Zum Funktionsende hat es sich 
für die Variable erledigt. Man kann nicht mehr darauf zugreifen (falls 
man sie als Wert zurückgibt, dann höchstens zufällig, aber nicht mal das 
ist der Fall). Von 'außen' ist die Variable sowieso nicht zu sehen.
3. Falls die Übergabe der Koordinaten irgendwann mal implementiert sein 
sollte, ist das doch völlig unsinnig. Wieso ein Zeichen definieren und 
dann gleich noch die Position auf dem Display mit dazu?

von David G. (ded)


Lesenswert?

zu 1.: Die Parameter werden doch verwendet. Sie legen die Position des 
Zeichens fest.

zu 2.: Die Variable arrow_up wird initialisiert und dann mittels 
'generate_char(CHAR0_ADR, arrow_up);' in den CG RAM auf die Adresse 0x40 
geschrieben, also als Zeichen 0 im DD RAM abgelegt.

zu 3.: Die Position habe ich festgelegt, weil hier im Artikel 
"Pseudo-Graphische LCD-Ansteuerung" folgender Satz in einem roten Kasten 
steht: "Vorsicht: Nach Übertragung eines benutzerdefinierten Zeichens, 
muss im LCD-IC explizit eine neue Schreibposition mittels zb 
lcd_setcursor, lcd_home oder lcd_clear gesetzt werden."

von Karl H. (kbuchegg)


Lesenswert?

David G. schrieb:
> zu 1.: Die Parameter werden doch verwendet. Sie legen die Position des
> Zeichens fest.
>
> zu 2.: Die Variable arrow_up wird initialisiert und dann mittels
> 'generate_char(CHAR0_ADR, arrow_up);' in den CG RAM auf die Adresse 0x40
> geschrieben, also als Zeichen 0 im DD RAM abgelegt.
>
> zu 3.: Die Position habe ich festgelegt, weil hier im Artikel
> "Pseudo-Graphische LCD-Ansteuerung" folgender Satz in einem roten Kasten
> steht: "Vorsicht: Nach Übertragung eines benutzerdefinierten Zeichens,
> muss im LCD-IC explizit eine neue Schreibposition mittels zb
> lcd_setcursor, lcd_home oder lcd_clear gesetzt werden."

Trotzdem zeigt dein Code eine Verständnisschwäche auf.

Dem LCD wird EINMAL bekannt gemacht, wie das Zeichen mir dem Code x 
auszusehen hat, danach wird dieses Zeichen verwendet. Es besteht daher 
überhaupt kein Grund, in der Ausgabefunktion dem LCD jedesmal wieder 
klar zu machen, welche Pixel hell und welche Pixel dunkel zu färben 
sind.

Daher: die Dinge trennen!

Ist ist eine Sache, dem LCD das Aussehen eines Zeichens zu übermittlen.
Ist es aber eine ganz andere Sache, dieses Zeichen danach zu verwenden.

Und nein, du kannst auf die Art nicht beliebig viele benutzerdefinierte 
Zeichen benutzen. Soabld die das Aussehen des Zeichens mit dem Code 2 
änderst, werden alle bereits ausgegebenen Zeichen mit genau diesem Code 
ebenfalls auf das neue Aussehen geändert.

In der typischen Programmstruktur

int main()
{
  Initialisierung

  Vorarbeiten

  while( 1 )  {

    Programmlogik

  }
}

fällt die Zeichendefinition in den Bereich Initialisierung, während die 
Zeichenausgabe im Bereich Vorarbeiten/Programmlogik vorkommt.

Es kann natürlich vorkommen, dass man während der Programmlogik das 
Aussehen eines Zeichens auch einmal ändern muss. Das ist dann aber eher 
die Ausnahme, genauso wie es die Ausnahme ist, dass man einen Port 
während des laufenden Betriebs in der Ein/Ausgangskonfiguration 
umkonfigurieren muss oder einen Timer umkonfigurieren muss. In der 
Mehrzahl der Programme werden diese Einstellungen im Bereich 
Initialisierung gemacht und bleiben dann während des Programmlaufes 
immer gleich, sprich werden nicht mehr verändert.

von David G. (ded)


Lesenswert?

Hallo Karl Heinz Buchegger,

natürlich hast du Recht. Aber ist das nicht letztlich nur ein 
"Schönheitsfehler"? Das dürfte doch an der Funktionalität an sich nichts 
ändern, oder?

von Ralf G. (ralg)


Lesenswert?

Aah, mein Fehler!

Karl Heinz Buchegger schrieb:
> Trotzdem zeigt dein Code eine Verständnisschwäche auf.
Trotzdem? Da hab' ich mir die Klammern noch mal genau unter die Lupe 
genommen.

   0b00000100,    //  #
   0b00000000         // hier habe ich eine Klammer 'hingelesen'
 };                   // hier war für mich die Funktion zu Ende

Ich habe mich an der Stelle festgebissen: Wieso braucht man eine 
Funktion um ein Zeichen zu definieren?

David G. schrieb:
> Hallo Karl Heinz Buchegger,
>
> natürlich hast du Recht. Aber ist das nicht letztlich nur ein
> "Schönheitsfehler"? Das dürfte doch an der Funktionalität an sich nichts
> ändern, oder?
Für das Display wurde ein Zeichensatz erstellt, der fest eingebaut ist. 
Nun ist dort im Speicher 'noch etwas Platz' und da kann man sich seine 
eigenen Zeichen 'hinmalen'. Sind die einmal dort (bis zum Ausschalten) 
ruft man diese, genauso wie alle anderen über ihren ASCII-Code auf (nur 
dass man bei z.B. 0x41 bzw. 65 auch 'A' im Quelltext schreiben kann)
Also definiert man die Zeicen nur einmal in einem Array, schreibt sie in 
den RAM vom Display und bringt sie später über ihren Index+Offset 
(=ASCII-Code) zur Anzeige.

von David G. (ded)


Lesenswert?

Ok. Ist klar. Also meine Funktion sieht jetzt so aus:
1
void arrow_up(){
2
  char arrow[8] = {                //Bitmuster erstellen
3
    0b00000000,
4
    0b00000100,    //  #
5
    0b00001110,    // ###
6
    0b00010101,    //# # #
7
    0b00000100,    //  #
8
    0b00000100,    //  #
9
    0b00000100,    //  #
10
    0b00000000
11
  };
12
  generate_char(CHAR0_ADR, arrow);        //Zeichen erstellen  
13
}
Dann rufe ich zuerst in meiner init-Funktion die arrow_up() auf, und 
müsste ja dann später mittels 'send_char(0);' mein Zeichen anzeigen 
lassen können. Geht aber nicht...

von spess53 (Gast)


Lesenswert?

Hi

Bist du sichcher, das bei Aufruf deiner Funktion auch Instruction Table 
0 eingestellt ist? Also irgendwann vorher ein Function Set mit IS[2:1] = 
00.

MfG Spess

von Ralf G. (ralg)


Lesenswert?

David G. schrieb:
> Dann rufe ich zuerst in meiner init-Funktion die arrow_up() auf, und
> müsste ja dann später mittels 'send_char(0);' mein Zeichen anzeigen
> lassen können. Geht aber nicht...
Wenn alles richtig initialisiert ist, muss das so gehen.

Allerdings:
Soll das für immer und ewig das einzige Zeichen sein, welches du 
definierst?
Willst du da jedesmal eine neue Funktion schreiben?

von David G. (ded)


Lesenswert?

@spess53: Du hast Recht. Hatte wirklich vergessen auf instruction table 
0 zu setzen. Habe das jetzt gemacht. Allerdings immer noch keine Ausgabe 
des Pfeils.

@Ralf: Soll selbstverständlich nicht das einzige Zeichen bleiben. Jetzt 
muss ich mal ganz dumm fragen: Wie kann man das schöner machen? Also 
ohne für jedes Zeichen eine eigene Funktion zu schreiben.

von Ralf G. (ralg)


Lesenswert?

David G. schrieb:
> Jetzt
> muss ich mal ganz dumm fragen: Wie kann man das schöner machen? Also
> ohne für jedes Zeichen eine eigene Funktion zu schreiben.

Gar keine Funktion. Bzw. nur eine kurze. Mal ganz grob:

// Array mit Zeichendaten:
char Zeichen[][] = { ... // hier die 'Zeichnungen' rein
                   };

for (uint8_t i=0; i < maxZeichen; i++)
 ZeichenUebertragen(Zeichen[i][0]);

von David G. (ded)


Angehängte Dateien:

Lesenswert?

Ich verzweifel hier noch. Hab mal den gesamten Code angehängt. Kann da
mal bitte jemand drüber schauen und mir sagen warum das nicht
funktioniert? Vielen Dank.

von Ralle (Gast)


Lesenswert?

void set_cursor(int line, int pos){
  RS=0;
  switch(line){
    case 1: send_command(0x00 + 0x80 + pos);  //Anfangsadresse Zeile 1 + 
DB7 high + Position
    break;

    case 2: send_command(p1=0x40 + 0x80 + pos);  //Anfangsadresse Zeile 
2 + DB7 high + Position
    break;

    default:
    return;
  }
}

was ist den p1=0x40 in Case 2

von David G. (ded)


Lesenswert?

Oh...Ist mir gar nicht aufgefallen. Hatte das Display vorher über 
8-Bitmodus angesteuert und den Quelltext nur auf SPI angepasst. Ist ein 
Überbleibsel davon. Geändert, getestet, frustiert. Klappt immer noch 
nicht.

von Ralle (Gast)


Lesenswert?

in LCD_Init

  send_command(0x01);    /Display löschen, Cursor Home

Befehlszeit > 1ms

hast du da die Wartezeit drinnen?

von David G. (ded)


Lesenswert?

Jetzt ja. Gleiches Ergebnis. Nichts

von holger (Gast)


Lesenswert?

for(i=0;i<3;i++){
    for (j=0;j<8;j++){
      send_char(zeichen[i][j]);              //Bitmuster übertragen
    }
  }


Dein i ist global. Wenn du send_char()
aufrufst ist der letzte Wert von i Geschichte.

von David G. (ded)


Lesenswert?

Hi Holger,

es lag wirklich nur an meinem i. Jetzt funktioniert es. Vielen Dank.
Tja. Kleine Ursache, große Wirkung^^

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.