Forum: Mikrocontroller und Digitale Elektronik Cursor positionieren?


von Harley (Gast)


Lesenswert?

Hallo.

Ich habe ein DOGM 162 (2x16 Zeichen) und möchte gerne den Cursor 
beliebig positionieren. Aus dem Datenblatt des verwendeten ST7036 werde 
ich nicht richtig schlau. Habe mir auch verschiedene Programme angesehen 
in denen der Cursor z.B. über "set_cursor(pos y, pos x)" gesetzt wird.

Das bekomme ich nicht vernünftig bzw. gar nicht hin. Kann mir jemand 
weiterhelfen?

von Eumel (Gast)


Lesenswert?

Harley schrieb:
> set_cursor(pos y, pos x)

Hast du dir dann auch die entsprechende Funktion angeschaut?

von Harley (Gast)


Lesenswert?

Im Kopf meines Programms steht folgendes:

#ifndef x
#define x    0x10 //16
#endif

#ifndef y
#define y    0x2 //Zeile
#endif

weiter:

void set_cursor(unsigned char pos_y, unsigned char pos_x)
{

  SENDEN(y + pos_y * x + pos_x);

}

von Karl H. (kbuchegg)


Lesenswert?

Harley schrieb:
> Im Kopf meines Programms steht folgendes:
>
> #ifndef x
> #define x    0x10 //16
> #endif
>
> #ifndef y
> #define y    0x2 //Zeile
> #endif
>
> weiter:
>
> void set_cursor(unsigned char pos_y, unsigned char pos_x)
> {
>
>   SENDEN(y + pos_y * x + pos_x);
>
> }


* und wo ist da jetzt das Commando für "Cursor Positionen"
  verschlüsselt? Du kannnst ja nicht einfach dem LCD irgednein
  Byte schicken und das sucht sich dann selber raus, dass du
  "Cursor positionieren" meinst.

* Im Datenblatt steht doch eindeutig, dass die erste Zeile bei 0 und
  bei einem 2-zeiligen LCD bei 0x40 beginnt.


(Cursor Positionieren heißt im Befehlssatz des LCD "Set DDRAM Address"

von Harley (Gast)


Lesenswert?

#ifndef x
#define x    0x80 //Zeichen
#endif

#ifndef y
#define y    0x40 //Zeile
#endif


void set_cursor(unsigned char pos_y, unsigned char pos_x)
{
    SENDEN(y + pos_y * x + pos_x);
}

set_cursor(0,8); //Cursor soll in Zeile 1 auf Position 8 sein


Aber wenn ich das richtig verstehe muss ich für Zeile 1 
set_cursor(0x40,00);
eingeben und für Zeile 2 set_cursor(0x80,40) eingeben oder?

von Karl H. (kbuchegg)


Lesenswert?

* was genau macht die Funktion SENDEN

  gibt die ein Datenbyte (ein Zeichen) ans LCD
  oder setzt die die Steuerleitungen so, dass das LCD auch
  weiß, dass es das nächste Byte als Kommando auffasen muss

* wo hast du die Formel

   y + pos_y * x + pos_x

  her. Die ist ziemlicher Unsinn.


Wenn du eine 2-dimensionale Anordnung hast ...

   +---+---+---+---+---+---+
   |   |   |   |   |   |   |
   +---+---+---+---+---+---+
   |   |   |   |   |   |   |
   +---+---+---+---+---+---+
   |   |   |   |   |   |   |
   +---+---+---+---+---+---+
   |   |   |   |   |   |   |
   +---+---+---+---+---+---+
   |   |   |   |   |   |   |
   +---+---+---+---+---+---+

deren Felder der Reihe nach durchnummeriert sind

   +---+---+---+---+---+---+
   | 0 | 1 | 2 | 3 | 4 | 5 |
   +---+---+---+---+---+---+
   | 6 | 7 | 8 | 9 | 10| 11|
   +---+---+---+---+---+---+
   | 12| 13| 14| 15| 16| 17|
   +---+---+---+---+---+---+
   | 18| 19| 20| 21| 22| 23|
   +---+---+---+---+---+---+
   | 24| 25| 26| 27| 28| 29|
   +---+---+---+---+---+---+

und wenn wir da einfach mal den Zeilen und Spalten ebenfalls Nummern 
verpassen

         0   1   2   3   4   5      ... Spaltennummer

       +---+---+---+---+---+---+
    0  | 0 | 1 | 2 | 3 | 4 | 5 |
       +---+---+---+---+---+---+
    1  | 6 | 7 | 8 | 9 | 10| 11|
       +---+---+---+---+---+---+
    2  | 12| 13| 14| 15| 16| 17|
       +---+---+---+---+---+---+
    3  | 18| 19| 20| 21| 22| 23|
       +---+---+---+---+---+---+
    4  | 24| 25| 26| 27| 28| 29|
       +---+---+---+---+---+---+
    .
    . Zeilennummer

Welche Zahl steht dann im Schnittpunkt der Zeile y und Spalte x? 
Beispielsweise in der Zeile 3 und Spalte 4


                         *
                         *
                         *

         0   1   2   3   4   5      ... Spaltennummer

       +---+---+---+---+---+---+
    0  | 0 | 1 | 2 | 3 | 4 | 5 |
       +---+---+---+---+---+---+
    1  | 6 | 7 | 8 | 9 | 10| 11|
       +---+---+---+---+---+---+
    2  | 12| 13| 14| 15| 16| 17|
       +---+---+---+---+---+---+
*** 3  | 18| 19| 20| 21| 22| 23|
       +---+---+---+---+---+---+
    4  | 24| 25| 26| 27| 28| 29|
       +---+---+---+---+---+---+
    .
    . Zeilennummer


Da steht die 22.
So. WEnn du jetzt das Diagramm nicht hast, wie kannst du diese 22 
errechnen, wenn du nur die Zeilennummer und die Spaltennummer hast?

(hinweis: Zeile 3 bedeutet - weil die erste Zeile ja die Nummer 0 hatte 
- dass vor dieser Zeile 3 komplette Zeilen waren. Jede einzelne dieser 3 
kompletten Zeilen besteht aus 6 Feldern. D.h. die Zeilen 0 bis 2 
zusammengenommen sind 18 Felder und in dieser Zeile 3 kommen dann noch 4 
dazu, weil ja das Feld in der Spalte 4 gefragt war. 18 + 4 ergibt wieder 
die 22.
Wie lautet also die allgemeine Formel in diesem Fall?

Wenn du also diesem gedachten LCD mitteilen willst, dass es den Cursor 
in Zeile 3, Spalte 4 setzen soll, dann musst du ihm das Commando "Set 
DDRAM Address" mit einer Adresse von 22 schicken. Und zwar als 
Kommando(!) und nicht als Datenbyte.


Wie lautet die Formel in deinem Fall, wenn eine Zeile nicht 6 Spalten 
breit ist sondern 0x40 (also 64 Spalten) (auch wenn das LCD von diesen 
64 Spalten nur die ersten 16 anzeigt).

von Karl H. (kbuchegg)


Lesenswert?

> muss ich für Zeile 1 set_cursor(0x40,00);
> eingeben und für Zeile 2 set_cursor(0x80,40) eingeben oder?

gewöhn dir ganz schnell an, dass wir bei 0 anfangen zu zählen!

Und nein, das willst du ja gerade nicht.
Du willst die Zeilennummer bzw. die Spaltennummer beim Funktionsaufruf 
so angeben können, wie es für dich am angenehmsten ist. Die 0x40 
interessieren dich nicht, die muss die Funktion selber ins Spiel 
bringen. Im obigen Beispiel: du rufst auf

     set_cursor( 3, 4 )

und die Funktion muss sich selber ausrechnen, welche DDRAM Adresse es 
ans LCD weitergeben muss, damit der Cursor dorthin springt.

von Harley (Gast)


Lesenswert?

void Zeile1()
{
  PORTB&=~(1<<PORTB2); //RS für Kommandoabgabe setzen
  SENDEN(0x80);  // 0x80 = 128 -> Anfang der ersten Zeile
  _delay_us(40);  //Zeit zur Verarbeitung
}

void Zeile2()
{
  PORTB&=~(1<<PORTB2); //RS für Kommandabgabe
  SENDEN(0xC0);  //0xC0 = 192 -> Anfang der zweiten Zeile
  _delay_us(40);  //Zeit zur Verarbeitung
}

Habe mein Problem wie oben gelöst. Wollte jeweils nur am Anfang der 
jeweiligen Zeile anfangen.

Vielen Dank für die Hilfe!!!

von Karl H. (kbuchegg)


Lesenswert?

Harley schrieb:
> void Zeile1()
> {
>   PORTB&=~(1<<PORTB2); //RS für Kommandoabgabe setzen
>   SENDEN(0x80);  // 0x80 = 128 -> Anfang der ersten Zeile
>   _delay_us(40);  //Zeit zur Verarbeitung
> }
>
> void Zeile2()
> {
>   PORTB&=~(1<<PORTB2); //RS für Kommandabgabe
>   SENDEN(0xC0);  //0xC0 = 192 -> Anfang der zweiten Zeile
>   _delay_us(40);  //Zeit zur Verarbeitung
> }
>
> Habe mein Problem wie oben gelöst.

Gut!
Jetzt kann man guten Gewissens sagen: Jetzt hast du es verstanden.

> Wollte jeweils nur am Anfang der
> jeweiligen Zeile anfangen.

:-)
Das sagen sie alle. Bis sich dann die Anforderungen ändern.

void set_cursor( uint8_t zeile, uint8_t spalte )
{
  PORTB &= ~(1<<PORTB2); //RS für Kommandabgabe
  SENDEN( 0x80 + zeile * 0x40 + spalte );
  _delay_us(40);  //Zeit zur Verarbeitung
}

oder wenn dir die Multiplikation zu 'lastig' ist (obwohl es wohl keine 
große Rolle spielen dürfte. Du wartest danach ja sowieso eine gewisse 
Zeit ab)

void set_cursor( uint8_t zeile, uint8_t spalte )
{
  PORTB &= ~(1<<PORTB2); //RS für Kommandabgabe
  if( zeile == 1 )
    SENDEN( 0xC0 + spalte );
  else
    SENDEN( 0x80 + spalte );
  _delay_us(40);  //Zeit zur Verarbeitung
}


Und zur Ausgabe von Kommandos solltest du dir eine eigene Funktion 
machen. Du brauchst ja zb auch noch Kommandos zum Clear Screen etc. Das 
ist nicht wirklich schön, wenn du da in jeder einzelnen Funktion erneut 
am PORTB2 rumpfriemelst. Die kann dann auch gleich den PORTB2 nach der 
Ausgabe des Kommandos wieder auf Datenmodus zurückstellen.
1
void SendCommand( uint8_t Command )
2
{
3
  PORTB &= ~(1<<PORTB2); //RS für Kommandabgabe
4
  SENDEN( Command );
5
  PORTB |= (1<<PORTB2);  //zurückschalten auf Daten
6
}
7
8
void set_cursor( uint8_t zeile, uint8_t spalte )
9
{
10
  if( zeile == 1 )
11
    SendCommand( 0xC0 + spalte );
12
  else
13
    SendCommand( 0x80 + spalte );
14
  _delay_us(40);  //Zeit zur Verarbeitung
15
}
16
17
void clr_lcd()
18
{
19
  SendCommand( ... );
20
}
21
22
void cursor_on()
23
{
24
  SendCommand( .... );
25
}
26
27
....

Wird schon! Weiter so.

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.