Forum: Mikrocontroller und Digitale Elektronik Serielles Display


von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

Hallo:)
ich habe mir selber jetzt ein serielles LCD-Display zusammengebaut das 
über 3 Anschlüsse mit dem Microcontroller angeschlossen wird. Nur die 
CLK, Enable und der Datenbus sind mit dem Microcontroller verbunden. 
Zwischen dem Microcontroller habe ich ein Schieberegister angeschloessen 
dass die Daten an das LCD-Display leiten soll.
Den Schaltplan habe ich im Anhang auch hinzugefügt.
Hab auch mein programm auf dem Microcontroller draufgespielt und die 
einzelnen Pinnen mit dem Oszilloskop überprüft. Signale bekamme ich an 
den jeweiligen Pins wenn z.b clock auf high schaltete setze der datenbus 
auch auf high und das umgekehrt.

Ich habe glaube ich bei der Initialisierung bestimmt ein Fehler gemacht 
nur ich weiss nicht wo genau:(. Bei einer bestimmten steigenden 
Clock-flanke schaltet sich die Hintergrundbeleuchtung meiens Displays 
aus:(

Hoffe könnt mir was weiter helfen^^

von Uwe (de0508)


Lesenswert?

Hi Adrian,

so wie Du das beschreibst, fehlt die Masse - Gnd Verbindung.

von Adrian (Gast)


Lesenswert?

dass macht er nur wenn ich mein programmm draufspiele, dann wird das 
display dunkel. Außerdem zeigt mir dann dieses display nichts an was ich 
programmiert habe :(

von Rudolph (Gast)


Lesenswert?

DB0 bis DB3 gehören eher nicht fest auf GND verdrahtet.

von Adrian (Gast)


Lesenswert?

also ist der plan selber schonmal falsch oder wie darf ich das jetzt 
verstehen? hab diesen plan von ulrich radig gefunden. Dies wurde mir 
auch empfohlen.

von Karl H. (kbuchegg)


Lesenswert?

Lass die 4 Datenleitungen offen. Das LCD kümmert sich selbst um die.


Das hier
1
void lcd_init (void)
2
{  
3
4
  //Set Port Direction Register
5
  //LCD_DDR = 0x07;
6
  DDR_LCD_DATA_ENABLE  |= (1<<LCD_DATA_ENABLE);
7
  DDR_LCD_CLOCK |= (1<<LCD_CLOCK);
8
  DDR_LCD_DATA |= (1<<LCD_DATA);
9
  PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE);
10
11
  //Wait a short Time afer Power on
12
  
13
  WAIT(10);
14
  
15
  
16
  for (unsigned char a=0;a<3;a++)
17
  {
18
    lcd_write (0x22,0);  //Init in 4 Bit Mode
19
    lcd_write (0x80,0);  //Set DD-Ram Adresse = 0
20
  }
hat der Radig Ulli geschrieben?
Das kann ich nicht glauben. Das ist ein kompletter Unsinn.

von Adrian (Gast)


Lesenswert?

leider ja mir ist nicht im klaren wieso er eine for schleife für die 
initialisierung des 4 bit und der DD-Ram benutzt. Ich würde dies 
komplett weg lassen und nur die beiden Initialisierungen aufschreiben. 
Hab den code etwas geändert genau so:
void lcd_init (void)
{

  //Set Port Direction Register
  DDR_LCD_DATA_ENABLE  |= (1<<LCD_DATA_ENABLE);
  DDR_LCD_CLOCK |= (1<<LCD_CLOCK);
  DDR_LCD_DATA |= (1<<LCD_DATA);
  PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE);

  //Wait a short Time afer Power on

  WAIT(10);


    lcd_write (0x22,0);  //Init in 4 Bit Mode
    lcd_write (0x80,0);  //Set DD-Ram Adresse = 0
    lcd_write (0x40,0);  //1 Zeilen
    lcd_write (0xD0,0);  //Display On
} sofern dies richtig jetzt nun ist. Dies habe ich so aus dem Datenblatt 
entnommmen hoffe habe alles wichtige in meiner lcd_init enthalten.

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:
> leider ja mir ist nicht im klaren wieso er eine for schleife für die
> initialisierung des 4 bit und der DD-Ram benutzt.



Eben.

Die korrekte Sequenz, die funktioniert lautet:

Du präsentierst dem LCD an den Datenbits D4 bis D7 erst mal eine 3 (d.h 
D4 auf 1, D5 auf 1). Und das 3 mal hintereinander, wobei jedesmal RS auf 
0 bleibt und natürlich so wie immer die Enable Leitung gepulst wird.

Aber Achtung: du musst zwischen den Enable Pulsen Wartezeiten einhalten!

Erst dann ist sicher gestellt, dass das LCD auf jeden Fall im 8-Bit 
Modus ist, egal was vorher passiert ist.

Und erst dann präsentierst du ihm einmalig eine 2 an den Datenleitungen 
D4 bis D7 (also D5 auf 1).
WIeder: Rs muss auf 0 bleiben und auf Enable wird ein Puls erzeugt.

Und erst dann ist das LCD im 4-Bit Modus und du kannst erstmals die 
Funktion lcd_write benutzen.


PS: Du kannst ein LCD beliebig langsam ansteuern. D.h. wenn du die 
Möglichkeit dazu hast, dann kannst du an die Ausgangsleitungen vom 
Schieberegister, bzw an die Enable Steuerleutung etwas zusätzlich 
anschliessen, womit du die Pegel erkennen kannst und somit siehst, ob da 
die Pegel rauskommen, so wie sie eigentlich sein sollten.
Du darfst die Pulse, die zeitlichen Abstände etc. beliebig langsam 
machen, so dass du als Mensch da noch mitkommst. Nur zu schnell darf es 
nicht sein. Es gibt da minimal einzuhaltende Wartezeiten. Insbesondere 
die ersten Initialisierungsschritte sind da kritisch.

AVR-Tutorial: LCD

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

ich weiss gerade nicht ob das so richtig ist wie dues mir gerade gesagt 
hast

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

snayer2311 schrieb:
> ich weiss gerade nicht ob das so richtig ist wie dues mir gerade gesagt
> hast
So wie Karl Heinz es gesagt hat, ist es richtig. So wie du es machst, 
ist es falsch. Lies einfach mal das Datenblatt zum Display und überleg, 
ob die Zeiten und Abläufe, die darin auftauchen auch in deinem Programm 
auftauchen. Du musst gerade zu Beginn der Initialisierung (Datenbreite) 
das Timing unbedingt einhalten.
1
    lcd_write (0x22,0);  //Init in 4 Bit Mode
Dass du da über einen Trick schnell hintereinander eine 0x2 sendest 
hilft da nicht weiter und Kommentare kann das Display auch nicht 
lesen...


1
           goto ConversionLoop;
> weiss gerade nicht ob das so richtig ist
Ist das C?
Dann ist es falsch: ein Anfänger braucht sicher kein GOTO in einem Stück 
C-Code...


> Nibbel
Noch so einer: ein halbes Byte ist ein Nibble, der mit einem Nippel 
nun so gar nichts zu tun hat...

: Bearbeitet durch Moderator
von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:

>
1
>     lcd_write (0x22,0);  //Init in 4 Bit Mode
2
>
> Dass du da über einen Trick schnell hintereinander eine 0x2 sendest

Ja, das ist mir auch aufgefallen. Das könnte vielleicht sogar 
funktionieren. Glücklich bin ich damit trotzdem nicht.

@snayer2311

Der springende Punkt ist, dass du zum Umschalten in den 4 Bit Modus die 
Funktion lcd_write noch nicht benutzen kannst!
Genau das hab ich versucht dir klar zu machen.
du kannst die shift_out benutzen, denn die gibt im Grunde ja ein Nibble 
kontrolliert an das Schieberegister aus. Allerdings ist das Interface 
für diese Funktion etwas 'unhandlich', weil der Aufrufer die Bits 
zurecht schieben muss und nicht die Funktion das selber macht. Eventuell 
würde ich mir da eine eigene Funktion shift_out_nibble machen, die den 
Zurechtschiebeteil an die Datenbits erledigt, damit ich in lcd_init den 
Teil nicht habe (den das ist beim Fehlersuchen in der lcd_init eher 
unpraktisch, wenn man an dieser Stelle laufend um die Ecke denken muss)

Aber da musst du durch. Genau deswegen hab ich es angesprochen, dass du 
den ganzen Vorgang beliebig langsam machen darfst. Nutze das tatsächlich 
aus! Häng meinetwegen ein paar LED an die Leitungen, die zum LCD gehen 
und sieh dir an, welche Pegel wann da am LCD ankommen. Du MUSST die 
angegebene Sequenz dort aufleuchten sehen. 3 mal hintereinander das 
Bitmuster für 3 an den Datenleitungen und dann einmalig das Bitmuster 
für 2 an den Datenleitungen. Wenn du langsam machst, dann überfährst du 
auch ganz sicher nicht das LCD.

Sorry. Aber solche 'Spezialsachen' kann man nun mal nicht machen, wenn 
man nicht gewillt ist, sich mit der Materie zu beschäftigen. Daher geb 
ich dir auch nur Tips und sag dir, was du letzten Endes an den Ausgängen 
vom Schieberegister sehen musst. Aber machen .. musst DU es.

: Bearbeitet durch User
von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

Habe ich soweit gemacht jetzt meckert, eine eigene Funktion geschreiben 
die den Zurechtschiebeteil macht ohne die lcd_write Funktion 
zuschreiben. Jetzt meckert er über einen Fehler den ich nicht verstehe. 
Irgendein zeichen fehlt aber entdecke den Fehler nicht

Error  1  expected ';', ',' or ')' before '=' token  F:\Hauptprojekt 
serielle Displaysteuerung\SeriellesDisplay\SeriellesDisplay\lcd.c  20 
27  SeriellesDisplay
er

von snayer2311 (Gast)


Lesenswert?

Fehler gefunden:)

von snayer2311 (Gast)


Lesenswert?

Anscheinend soll das Programm so von Ulrich Radig funktionieren ohne 
dass man da was ändern sollte. Wieso solle ich da eine neue Funktion 
schreiben wenn lcd_write ja nur dass alles in dem Schieberegister 
schreibt und die Funktion shift_data out eigentlich das was in dem 
Schieberegister steht ins display aufnimmt. Am ende dieser Funktion ist 
ja dieses enable dass die alle daten des Displays im Schieberegister 
aufnimmt.

Hab auf seiner Seite genau mir das gleiche serielle Display 
zusammengebaut.
hmm dann hab ich i-wie ein anders Problem mache gerade eine Fehler 
analyse und möchte mal sowie es ulrich radig gemacht hatte meine pins am 
portC anschließen.

von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:

> Wieso solle ich ....

Weil Ulli 2007 mit der damailgen Compilergeneration wusste was er tat. 
Er hatte das Wissen und das Können, das durchzuziehen.

Du hingegen sträubst dich seit Tagen, dir eine simple Hilfsfunktion zu 
schreiben, so dass du die Grund-Initialisierung ...
1
void lcd_init()
2
{
3
  //Set Port Direction Register
4
  //LCD_DDR = 0x07;
5
  DDR_LCD_DATA_ENABLE  |= (1<<LCD_DATA_ENABLE);
6
  DDR_LCD_CLOCK |= (1<<LCD_CLOCK);
7
  DDR_LCD_DATA |= (1<<LCD_DATA);
8
  PORT_LCD_DATA_ENABLE &= ~(1<<LCD_DATA_ENABLE);
9
10
  _delay_ms( 50 );    // 16 sollten eigentlich reichen
11
12
  shift_out_nibble( 0x03 );
13
  _delay_ms( 10 );    // minimum 4.1 ms
14
  shift_out_nibble( 0x03 );
15
  _delay_ms( 1 );     // minimum 0.1 ms
16
  shift_out_nibble( 0x03 );
17
  _delay_ms( 1 );
18
19
  shift_out_nibble( 0x02 );
20
  _delay_ms( 1 );
21
22
  // ab jetzt sind wir im 4-Bit Modus und lcd_write kann benutzt werden
23
24
  lcd_write (0x0C,0);  //Display On
25
}

... schreiben kannst bzw. anstelle der NOP da einfach mal ein paar 
längere _delay_xx einzufügen und mit ein paar LED oder einem Voltmeter 
nachzusehen ob auch alles richtig angeschlossen ist. (und mit 'längere' 
meine ich nicht Millisekunden, sondern durchaus Zeiten im 
Sekundenbereich oder noch länger)

Aber es ist ok. Die Funktion shift_out_nibble wäre zwar in 5 Minuten 
geschrieben (vor allen Dingen deshalb weil man sich an lcd_write 
orientieren kann, aber lediglich ein Nibble ausgibt und nicht ein ganzes 
Byte) und die Zeitsteuerung von NOP auf _delay_xx umgestellt, du rödelst 
dafür lieber tagelang rum und klebst an Code fest, den du nicht 
verstehts bzw. an einem Übertragungsmechanismus den du nicht verstehst, 
bzw. an Code dessen Details du nicht verstehst.


Vereinfacht gesagt und auf einen Punkt gebracht.

: Bearbeitet durch User
von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

habs jetzt soweit alles geändert wies mir beschrieben wurde hoffe das 
stimmt zumindest. hab ein problem beim debuggen und zwar stoppt er bei 
schon beim ersten delay und bleibt dann bei running fest hängen. was 
kann ich da machen?

von snayer2311 (Gast)


Lesenswert?

hab die zeiten was runtergeschraubt um zu testen ob der dann aus dem 
running schneller herausspringt aber ohne erfolg

von snayer2311 (Gast)


Lesenswert?

Hallo:) Ich bin mir nicht gerade sicher ob diese Funktion die Daten auch 
richtig in das schieberegister reinstellt
1
void shift_out_nibble (char data)
2
{
3
  unsigned h_nibble;
4
  unsigned l_nibble;
5
  
6
  h_nibble = (data&0xF0)>>1;
7
  
8
  _delay_ms(450);
9
  
10
  l_nibble |= (data&0x0F)<<3;
11
  
12
  _delay_ms(450);
13
  
14
//Schreiben der 1. 4Bit an das LCD Display
15
shift_data_out(h_nibble);
16
  
17
//Schreiben der 1. 4Bit an das LCD Display
18
shift_data_out(l_nibble);
19
20
}
21
void shift_data_out (char byte)
22
{
23
  for (unsigned char a=4; a>0; a--)
24
  {  
25
    if ( (byte & (1<<(a-1))) != 0)
26
    {
27
      PORT_LCD_DATA |= (1<<LCD_DATA); //Data PIN (High)
28
      enable();
29
    }
30
    else
31
    {
32
      PORT_LCD_DATA &= ~(1<<LCD_DATA); //Data PIN (LOW)
33
      enable();
34
    }
35
    Clock();
36
  }
37
  
38
  enable();
39
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:
> Hallo:) Ich bin mir nicht gerade sicher ob diese Funktion die Daten auch
> richtig in das schieberegister reinstellt


Was heißt du bist dir nicht sicher?

Schreib dir ein Testprogramm
1
int main()
2
{
3
  ...
4
5
  shift_data_out( 0x01 << 3);
6
7
  while( 1 )
8
    ;
9
}

und sieh nach (Voltmeter oder LED), ob am Pin DB4 vom LCD eine 1 anliegt 
und alle anderen auf 0 sind.
Dasselbe probierst du mit 0x02, 0x04 und 0x08 und den Pins DB5, DB6 und 
DB7 am LCD, die jeweils auf 1 liegen müssen und die jeweils anderen auf 
0. Wenn du dann noch ein bischen spielen willst, dann probierst du das 
noch mit anderen Kombinationen der 'Zahlenwerten' bzw. der RS Leitung.

Dann bist du sicher.

Das ganze geht schneller, als hier eine Frage einzutippen und so ganz 
nebenbei erhöht das auch noch deine Programmierpraxis und deine 
Fähigkeiten  dir selbst zu helfen, indem du dir überlegst, wie man etwas 
testen kann.

Dein Problem: du sitzt da wie der Hase vor der Schlange, weil dein LCD 
nicht reagiert. Gut.
Was du übersiehst: damit ein LCD funktioniert, muss eine komplexe Kette 
von Aktionen korrekt sein. Und die kann man alle einzeln testen und 
sicherstellen, dass sie funktionieren. Das beginnt mit der Verkabelung, 
führt über die korrekte Ansteuerung der dazwischen liegenden IC (in 
deinem Fall das Schieberegister) und endet erst zum Schluss in der 
korrekten Initialisierungssequenz. Aber jeder Schritt ist für sich 
einzeln testbar. Und dieses Prinzip der aufeinander aufbauenden Tests 
vom einfachen zum immer komplexeren ist ein allgemeines Prinzip. Daher 
ist es gut darin eine gewisse Praxis zu haben. Das wird dir auch in 
Zukunft noch so manches mal aus der Patsche helfen, wenn du dich 
überwindest und in diese Einzeltests ein wenig Zeit investierst.

: Bearbeitet durch User
von snayer2311 (Gast)


Lesenswert?

Soweit habe ich das verstanden nur mein problem ist gerade welche 
schleife ich für die funktion shift_data_out verwenden soll. hab gerade 
diese schleife genommmen

 for (unsigned char a=4; a>0; a--)
 {
   if ( (data & (1<<(a-1))) != 0)
   {
     PORT_LCD_DATA |= (1<<LCD_DATA); //Data PIN (High)
   }
   else
   {
     PORT_LCD_DATA &= ~(1<<LCD_DATA); //Data PIN (LOW)
   }
   Clock();
 }

 enable();
}
Beim Compilieren ist immer die lcd leitung null und ich messe an 
ausgängen nichts. Dann wie erreiche ich zum beispiel dass ich an db4 
eine 1 bekomme wenn meine schleife 4 mal durchläuft?

von snayer2311 (Gast)


Lesenswert?

hab es hinbekommen die Initialiserung funktioniert soweit :) hab jetzt 
auch den quelltext verstanden :)

von snayer2311 (Gast)


Lesenswert?

Soweit funktioniert bei mir die Initialisierung. Ich sehe einen blinken 
Curser und kann ihn beliebig switchen wie ich es gerne möchte. Aber wenn 
ich ein Wort ausgeben möchte funktioniert das mit der funktion 
lcd_print(0,0,"Hallo"); irgendwie nicht. Ich bekomme dann links nur 
zwei große striche etwa so || und ein komisches Zeichen heraus und der 
kurser bleibt dann stehen.

Was muss da umstellen in meiner Funktion?

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

Hier ist mein Projekt zu der Seriellen Display-Ansteuerung. Hat alles 
jetzt wunderbar funktioniert. Ich hab mein Fehler gefunden warum es 
nicht funktioniert hatte. Der Fehler lag an der Compilierung meines 
AVR-Dragons. Er hat meinen Programmtext anders Programmiert als der 
AVR-Burn Compiler.
Ich nehme jetzt in Zukunft AVR-Burn um mein Programmtext zu compilieren.

von spess53 (Gast)


Lesenswert?

Hi

>Der Fehler lag an der Compilierung meines AVR-Dragons.

Der Dragon compiliert überhaupt nichts.

>Er hat meinen Programmtext anders Programmiert als der AVR-Burn Compiler.

Der Dragon sieht gar nichts von deinem Programmtext. AVR-Burn (falls das 
so heißt) dürfte auch kein Compiler sein.

MfG Spess

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.