Forum: Mikrocontroller und Digitale Elektronik Probleme mit LCD (ST7066U)


von Olli (Gast)


Lesenswert?

Ich weiß nicht mehr weiter: Ich hab nun schon fast drei Tage mit der 
Fehlersuche verbracht!
Meine Probleme:
1. Das LCD wird nicht richtig initialisiert, wenn ich ein Zeichen 
schreibe(wenn denn eins geschrieben wird!), bleibt meist die erste 
Position frei oder so etwas "|||"erscheint, was in der Zeichentabelle 
gar nicht auftaucht. Wenn ich dann jede sek. ein Zeichen schreibe 
verschwindet der Cursor am Ende des LCD und taucht irgendwann in der 2. 
Zeile wieder auf,.. verschwindet wieder..taucht in der 1. wieder auf
--> ist dann wohl mit 2x16 initialisiert, obwohl ich nur 2x8 hab

2. es erscheint nicht immer ein Zeichen, hab's ausprobiert mit 
0b11001100:
im Display erscheint dann aber das Zeichen aus der Tabelle mit 
0b11001111, sieht aus wie ein chin. Schriftzeichen

auch wenn's unübersichtlich wird: hier der Quelltext
(Für die Daten nutze ich PA0-PA3; PF4=E, PF6=Rs)
======================================================================== 
===
#include "config.h"
#include "lcd.h"
#include <util/delay.h>


#define Lcd_write   PORTF&=0b11011111
#define Lcd_read    PORTF|=0b00100000
#define Lcd_order   PORTF&=0b10111111
#define Lcd_data    PORTF|=0b01000000
#define Lcd_enable  PORTF|=0b00010000
#define Lcd_disable PORTF&=0b11101111



U8 swap(U8 x) {

return ((x >> 4) | (x << 4));

}

void Port_init_lcd(void)
{


DDRA=0xFF;

DDRF|=1<<DDF4;
DDRF|=1<<DDF5;
DDRF|=1<<DDF6;

}

void write_lcd_once(U8 n)
{

  U8 nib;
  nib=n;

  nib&=0x0F;
  Lcd_write;
  PORTA = nib;
  Lcd_enable;
  PORTA = nib;
  Lcd_disable;
}


void write_lcd(U8 d)
{
  U8 dat;
  dat=d;

  dat=swap(dat);
  dat&=0x0F;
  Lcd_write;
  PORTA = dat;
  Lcd_enable;
  PORTA = dat;
  Lcd_disable;
  write_lcd_once(d);
}

void lcd_clear(void)
{

  Lcd_order;
  write_lcd(0b00000001);

}

void lcd_init(void)
{

  _delay_ms(40);
  Lcd_order;
  write_lcd_once(0x03);
  _delay_us(37);
   write_lcd(0x28);
  _delay_us(37);
   write_lcd(0x28);
  _delay_us(37);
   write_lcd(0x0F);
  _delay_us(40);
   write_lcd(0x01);
  _delay_ms(1.52);
   write_lcd(0x06);
  _delay_us(37);


}


void cursor_home(void)
{
  Lcd_order;
  write_lcd(0b00000010);

}

void cursor_set_row2(void)
{
  int i;

  Lcd_order;
  cursor_home();
  for (i=0;i<8;i++) write_lcd(0b00010100);

}
======================================================================== 
===
Ich hoffe jemand kann mir helfen, oder Tipps für die Fehlersuche geben.

MfG Olli

von Roland Z. (r-zimmermann)


Lesenswert?

Hmmm,

welchen Controller hat das Display nen HD oder nen KS? Beim KS ist die 
initsequenz ein klein wenig anderst, das verursacht dann diesen Fehler 
das das LCD nur müll anzeigt (ist mir auch schon passiert).

ST7066U ist das der Controller oder die bez. des LCDs?

Poste mal mehr infos bitte. :)

Roland

von crazy horse (Gast)


Lesenswert?

jo, das wirds sein. Hat mich auch schon mal sinnlos Zeit gekostet. 99,x% 
Kompatibilität reichen eben manchmal nicht.

von Olli (Gast)


Lesenswert?

ST7066U ist der Controller, soll mit HD... auf jeden Fall Pin kompatibel 
sein.

Hab jetz noch ein bißchen rumgespielt mit versch. Zeichen:

Das obere Nibble wird korrekt übertragen, das untere ist immer 1111:
so wird z.B. aus 'W'(ASCII 0x57) im Display "_"(0x5F) oder aus 
'A'(0x41),'B'(0x42).. "O"(0x4F)
Wnn ich dann an PA0-PA3 messe bekomme ich das korrekte unter Nibble, 
also bei 'W' --> 0111


Wenn ich das LCD dranhänge(ohne Datenleitungen) erscheint ein Balken in 
der 1. Zeile, wenn ich das Prog. starte kommen dann 2 Zeilen(sind aber 
etwas heller), dann fängt er meist auch nicht gleich an zu schreiben, 
sondern erst wenn ich dann noch mal ca. 1s Reset(auf dem Board) halte 
...?

Olli

von Olli (Gast)


Lesenswert?

Das würde dann auch erklären, warum Clear Display('0b00000001') nicht 
funktioniert. Gib es eig. bei der Init einen Befehl der aus dem Display 
2x16 macht oder hat es was mit Shift zu tun, dass der Cursor aus dem 
Anzeigebereich läuft? und was könnte die Ursache für das untere Nibble, 
dass immer 1111 ist, sein?

von Christian S. (mueke)


Lesenswert?

Hallo Olli.
Dann ist entweder der Controller kaputt, oder mit deinen Steuersignalen 
stimmt was nicht.

Bei der Init-Sequenz kann man die Größe des Displays mit einem 
bestimmten Befehl festlegen. Da hilft immer das Datenblatt des 
Controllers. Da sind meist besispielroutinen angegeben. Habe danach auch 
eine Headrer-Datei für nen LCD geschrieben und es war kein Problem.
Bevor du aber das Problem mit dem unteren Nibble nicht geklärt hast, 
funktioniert  natürlich auch kein Befehl richtig (Außer er endet aus 
Zuall mit 0xFF).

MfG
Muecke

von Jörg X. (Gast)


Lesenswert?

> 1. Das LCD wird nicht richtig initialisiert, wenn ich ein Zeichen
> schreibe(wenn denn eins geschrieben wird!), bleibt meist die erste
> Position frei oder so etwas "|||"erscheint, was in der Zeichentabelle
> gar nicht auftaucht.
 mach mal ein (oder 2-3)  "asm volatile ("nop");" vor und nach den 
Lcd-disable; vielleicht ist der AVR zu schnell (der E-Takt muss unter 2 
MHz bleiben)
> Wenn ich dann jede sek. ein Zeichen schreibe
> verschwindet der Cursor am Ende des LCD und taucht irgendwann in der 2.
> Zeile wieder auf,.. verschwindet wieder..taucht in der 1. wieder auf
Das ist normal, die  2. Zeile fängt (wahrscheinlich) in der Mitte des 
Kontroller-RAMs an
1
//so kommst du da hin..
2
#define ROW2 0x40
3
lcd_order;
4
//hier waeren Macros fuer die LCD befehle, wie DDRAM_ADR,  nett...
5
write_lcd(0x80 | ROW2);
>2. es erscheint nicht immer ein Zeichen, hab's ausprobiert mit
>0b11001100:
ist, btw. kein ASCII Zeichen ;)
>im Display erscheint dann aber das Zeichen aus der Tabelle mit
>0b11001111, sieht aus wie ein chin. Schriftzeichen
dann gehts doch...
schick mal ein 'A' (genau so eintippen!!)

hth. Jörg

von Olli (Gast)


Lesenswert?

>Dann ist entweder der Controller kaputt, oder mit deinen Steuersignalen
>stimmt was nicht.
Ich denke/hoffe nicht, da ja anscheinend auch ein Nibble richtig ist.

Mit nop hat's leider auch nicht funktioniert, bei 'A' erscheint im LCD 
O.
Hinzu kommt jetzt noch, dass er in den Zeilen springt, obwohl ich weiter 
nichts geändert habe(noch keion ROW2).
3 Zeichen werden geschrieben, Sprung in die andere Zeile, schreibt Zeile 
zu Ende, kommt in der gleichen Zeile wieder, schreibt 3 Zeichen, springt 
zurück in die vorherige Zeile, schreibt zu Ende...

Nach einem HW-Reset läuft's wieder normal!
???

Aber wo kommt 1111 her?

Olli

von Olli (Gast)


Lesenswert?

Habe nochmal ein bißchen gemessen: wenn das Prog. nicht läuft, das Bord 
aber an ist und das LCD auch (Init nach Reset --> ein Balken) sind die 
Datenleitungen alle auf 5V, kann es evtl. damit zusammenhängen?

Olli

von Olli (Gast)


Lesenswert?

Ich weiß nicht mehr weiter,...
Kann mir einer von euch ein LCD 8x2 empfehlen, dass den HD44780 als 
Controller hat. Ich möchte wenigstens erstmal ein LCD richtig 
angesteuert bekommen, dann werd ich mich wohl nochmal an diesem 
versuchen!

MfG Olli

von Jörg X. (Gast)


Lesenswert?

Kannst du nicht mal dein Programm soweit wie nötig zusammenstreichen und 
dann hier anhängen?
Und bitte das Datenblatt vom Display(!) verlinken?
Und die Schaltung NOCH MAL kontrollieren (Kurzschlüsse, Massen 
verbunden...)

gib doch nicht so leicht auf ;)

hth. Jörg

von Olli (Gast)


Lesenswert?

>gib doch nicht so leicht auf ;)

Ist nur das erste mal, dass ich mich an einem LCD versuche und das 
frustet, wenn's nicht funktionieren will, zumal es ja nichts 
weltbewegendes ist so ein 8x2 LCD anzusteuern.

Zum Programm:
cdc_task.c ist die Hauptroutine, habe das Beispiel von Atmel zu CDC 
verwendet.
Vielleicht sollte ich auch mal den 8-bit Modus probieren...

von Olli (Gast)


Angehängte Dateien:

Lesenswert?

Anhang vergessen.
und hier das Datenblatt http://www.farnell.com/datasheets/55564.pdf

von Jörg X. (Gast)


Lesenswert?

Häh? wo ist bei deinem Code denn "main()" ?

SOWAS:
>> PORTD&=10001111; (aus "void Port_init_lcd(void)")
klappt ja (wahrscheinlich ;) nicht.
 evtl. geht's aber so:
> PORTD &= 0b10001111;
obwohl es so lesbarer wäre
1
#define EN 1<<PD4
2
#define RS 1<<PD5
3
#define RW 1<<PD6
4
PORTD &= ~(EN|RW|RS);// loesche alle drei...
Für die Fehlersucher ist der 'Programmers Notepad' (der Editor, der bei 
Winavr dabei ist) deutlich besser geeignet, als das AVR-Studio.

...und mit zusammenstreichen meinte ich eher sowas:
1
//... Header etc.
2
int main(void)
3
{
4
    Port_init_lcd();
5
    lcd_init();
6
    lcd_write_value('A'); /* hab ich geraten - die Funktion fehlt in 
7
             deinem Code , die Funktion muss RS setzen....*/
8
    while(1)
9
        ;
10
    return 0;
11
}
hth. Jörg

von Olli (Gast)


Lesenswert?

>>>PORTD&=10001111; (aus "void Port_init_lcd(void)")

das war keine Absicht, passiert mir aber oft

das main() ist in einer anderen Datei, da steht watchdog und scheduler, 
der dann init etc. aufruft

ich versuch's dann noch mal zusammenzustreichen, das mit dem notepad von 
winavr hab' ich auch noch nicht probiert, werd ich gleich mal machen.

MfG Olli

von Olli (Gast)


Angehängte Dateien:

Lesenswert?

Hab's jetzt auf das wesentliche beschränkt und ein paar Kommentare 
gemacht. Jetzt erscheint im Display nur an erster Position ein 
Zeichen(schwarzer Kasten im DB Zeichen mit 0b11111111) und der Cursor 
läuft durch ohne etwas zu schreiben!?

Olli

von Jörg X. (Gast)


Angehängte Dateien:

Lesenswert?

Der Init-Fehler ist in dem Code aber auch nicht beseitigt :(
> PORTD&=10001111;
es soll doch vermutlich
>> PORTF &= ~((1<<PF6)|(1<<PF5)|(1<<PF4))
heißen
was man NOCH leserlicher schreiben könnte:
1
// "lcd.h"
2
#define LCD_EN (1<<PF4)
3
#define LCD_RW (1<<PF5)
4
#define LCD_RS (1<<PF6)
5
#define LCD_PINS 0x0F
6
//"lcd.c"
7
void Port_init_lcd(void)
8
{
9
    DDRA |= LCD_PINS;
10
    PORTA &= ~LCD_PINS;
11
12
    DDRF |= (LCD_EN|LCD_RW|LCD_RS);
13
    PORTF &= ~(LCD_EN|LCD_RW|LCD_RS);
14
}
Im Prinzip kannst du auch gleich macros für die PORTS  PINS  DDR 
schreiben...

Du hast nirgends erwähnt mit welcher Frequenz der AVR arbeitet -- sieht 
nach USB aus, also nehme ich mal an 12MHz?
Die _delay_Xs()-Funktionen haben ja schließlich ein Limit, was z.B. 
bedeutet, dass du das 40ms delay als 2* _delay_ms(20) schreiben müsstest 
(bei 12MHz).

Ich häng's mal an.

hth. Jörg

von Olli (Gast)


Lesenswert?

Danke.

Ja, ist eine USB-Anwendung bzw. USB als Virtueller ComPort. Der AVR 
arbeitet aber nur mit 8MHz. Gibt man den Takt für delay.h(F_CPU) eig. in 
kHz an, hab ich so gemacht..
#define F_CPU 8000
wenn das falsch ist...

Auf dem LCD tut sich immer noch nix, manchmal passiert gar nix, oder es 
gibt "O" anstatt "A" aus. Ich werd wohl noch vier Leitungen dranhängen 
müssen.

Kann es evtl. auch damit was zu tun haben, dass ich keinen busy-check 
mache wie es im Datenblatt geschrieben ist..irgendwelche timing-Sachen?

Olli

von Karl H. (kbuchegg)


Lesenswert?

Olli wrote:

> arbeitet aber nur mit 8MHz. Gibt man den Takt für delay.h(F_CPU) eig. in
> kHz an, hab ich so gemacht..
> #define F_CPU 8000
> wenn das falsch ist...

Ja, das ist falsch. Der Takt wird in Hz angegeben

#define F_CPU 8000000

Da du hier um einen Faktor 1000 falsch liegst, würde ich mal
nicht darauf wetten, dass die _delay_xx Funktionen überhaupt
irgendwelche sinnvollen Zeiten ermittelt haben.

von Olli (Gast)


Lesenswert?

Jap, das war's! Hab' zwar schon die Leitungen dran, die werd ich aber 
wohl nicht mehr brauchen(hoffentlich, wer weiß was da noch kommt)

So'n Mist. Ich hab das eig. nur in kHz angegeben, weil's in der config.h 
bei meinem Beispielprog auch in kHz angegeben wurde und dachte, dass 
wäre die Standard-Angabe, naja man sollte bei sowas wohl immer auf 
Nummer sicher gehen und noch mal nachlesen.
Vielen Dank an alle für die Hilfe!

MfG Olli

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.