Forum: Mikrocontroller und Digitale Elektronik attiny2313, LCD, 4-Bit, C, Einzelne Zeichen falsch


von Andreas P. (andreasp)


Lesenswert?

Hallo,

Ich versuche mit einem Attiny2313, ein Pollin-LCD TC1602A im 4-Bit-Modus 
anzusprechen.
Direkt mal vorneweg: Ich sehe Text !
Verwendet habe ich (nach zig eigenen Tests) den SourceCode aus dem 
GCC-Tutorial. Angepaßt auf meine Pins (Port B).

Mein Problem liegt nun darin, das bestimmte Zeichen nicht richtig 
angezeigt werden, allerdings in seltsamen Konstellationen.

Das hier ist mein Hauptprogramm

int main(void)
{  // Initialisierung des LCD
  int z=1,s=0,c=0;

  lcd_init();
  // Teil 1
  lcd_data(0x30);
  lcd_data('0');
  lcd_string("0@P0@P0@P0@P");
  _delay_ms(1000);
  lcd_clear();

  // Teil 2
  while(1)
  {
  if (s==16) {
        s=0;
  z++;
  if (z==3) z=1;
        lcd_setcursor(s,z);
        }
  lcd_data(c);
  _delay_ms(500);
  c++; s++;
  }
  return 0;
}

Die Ausgabe nach dem ersten Teil sieht absolut sauber aus. Es erscheinen 
genau die Zeichen auf dem Display.

Jetzt das Problem:
Die Ausgabe im zweiten Teil produziert bei jedem Zeichen, das im unteren 
Nibble eine 0 hat ein falsches Zeichen.
Mittlerweile habe ich auch raus, was schief läuft:
0x30 - 0xf3 (Befehl - Anzeige)
0x40 - 0xf4
0x50 - 0xf5
usw.
D.h. in den Fällen wo das untere Nibble 0 ist, sendet der Controller das 
entsprechend falsche Zeichen. Sieht für mich so aus, als ob in dem Fall 
das Verschieben der Nibbles nicht hinhaut.
Ich verstehe nur nicht WARUM ?

Das ausgeben von Hex 30 vor der Schleife funktioniert, in der Schleife 
nicht mehr.

Ich dachte an Optimierungen und habe es mit allen Einstellungen 
probiert. Bei allen das gleiche Ergebnis. Der attiny läuft mit 8 MHz, 
Fuses sind korrekt, Nutze AVR Studio mit Atmel MKII.

Bin für Tips dankbar.

von spess53 (Gast)


Lesenswert?

Hi

>lcd_data(c);

Welchen Datentyp erwartet denn 'lcd_data'? Mit Sicherheit kein 'int'.

MfG Spess

von L. J. (luke1)


Lesenswert?

Hm, wie wär es mit der itoa-Funktion?
Außerdem hast du bei if(z==3) eine Klammer vergessen.

von Andreas P. (andreasp)


Lesenswert?

L. J. schrieb:
> Außerdem hast du bei if(z==3) eine Klammer vergessen.
Ups ja, die Klammer ist beim kopieren da rausgerutscht, sorry.

> Welchen Datentyp erwartet denn 'lcd_data'? Mit Sicherheit kein 'int'.
Ist definiert als UINT8_T

Die Funktion und die Übergabe funktionieren ja generell bei fast allen 
Zeichen.. Wenn ich jetzt den String in der Schleife unten ausgebe, 
produziert der auch Müll bei allen Zeichen die auf 0x?0 enden.
Dieses "Rundschreiben" aller Zeichen hatte ich zum Debuggen eingebaut. 
Aufgefallen ist es, als ich in einer Schleife wechselweise zwei Strings 
ausgeben wollte.

von L. J. (luke1)


Lesenswert?

Hm..was hast du denn jetzt genau geändert?

von Andreas P. (andreasp)


Lesenswert?

L. J. schrieb:
> Hm..was hast du denn jetzt genau geändert?

Meinst du im letzten Beitrag ? Da hab ich nur die Zeile eingefügt mit 
dem Bezug zu deinem Eintrag und itoa ;)

von L. J. (luke1)


Lesenswert?

Nein nein. Ich meine schon im Code :)

von Tom M. (Gast)


Lesenswert?

Beschränk dich doch erstmal auf gängige druckbare Zeichen (ASCII 
0x20..0x7F). Könnte ja gut sein, dass andere Zeichen als Steuerzeichen 
interpretiert werden.

> lcd_data(c);

Für Variable "c" den Wertebereich einschränken.

von Peter D. (peda)


Lesenswert?

Andreas Peters schrieb:
> Verwendet habe ich (nach zig eigenen Tests) den SourceCode aus dem
> GCC-Tutorial. Angepaßt auf meine Pins (Port B).

Dann zeige ihn auch (komplettes compilierbares Programm als 
Dateianhang).

Wie soll man denn sonst den Fehler finden?


Peter

von Andreas P. (andreasp)


Angehängte Dateien:

Lesenswert?

> Dann zeige ihn auch (komplettes compilierbares Programm als
> Dateianhang).
Hängt jetzt hier dran

> Beschränk dich doch erstmal auf gängige druckbare Zeichen (ASCII
> 0x20..0x7F). Könnte ja gut sein, dass andere Zeichen als
> Steuerzeichen interpretiert werden.
Damit habe ich ja angefangen. Ich hatte einen String mit großem 'P' und 
raus kam ein kleines 'ü', alle anderen Buchstaben waren in Ordnung. Dann 
habe ich die Schleife eingebaut und festgestellt, das bei jedem 
Buchstaben, der in Hex auf 0 endet dieses Verschiebeproblem auftritt.
0 = 0x30 -> 0xf3 wird ausgegeben
@ = 0x40 -> 0xf4 wird ausgegeben
P = 0x50 -> 0xf5 wird ausgegeben.

von Vlad T. (vlad_tepesch)


Lesenswert?

Andreas Peters schrieb:
> Hängt jetzt hier dran

Naja, die verwendete LCdD-Lib wird wohl hoffentlich fehlerfrei sein.

Was wahrscheinlich viel interessanter wäre, ist dein Code

PS: verscuhs mal mit Peter Fleurys lcd lib. Die funktioniert auf jeden 
Fall.

von Andreas P. (andreasp)


Lesenswert?

Vlad Tepesch schrieb:
> Naja, die verwendete LCdD-Lib wird wohl hoffentlich fehlerfrei sein.
Das hatte ich gehofft :)

> Was wahrscheinlich viel interessanter wäre, ist dein Code
Der ist wenig spektakulär, siehe oben.

> PS: verscuhs mal mit Peter Fleurys lcd lib. Die funktioniert auf jeden
> Fall.
Das probiere ich heute abend mal aus.

von L. J. (luke1)


Lesenswert?

Die hier aus dem Forum funktioniert aber auch. Ich benutze die auch 
immer. Ich glaub es liegt eher an seinem Code.

von Andreas P. (andreasp)


Lesenswert?

L. J. schrieb:
> Die hier aus dem Forum funktioniert aber auch. Ich benutze die auch
> immer. Ich glaub es liegt eher an seinem Code.
Davon würde ich generell auch ausgehen. Blöd ist nur, das die gleiche 
Routine für alle möglichen Zeichen funktioniert, nur keine mit 
Low-Nibble == 0 wenn der Aufruf aus einer Schleife kommt.
Darum hatte ich vermutet, das es irgendwas mit Optimierungen & Compiler 
zu tun hat.

von L. J. (luke1)


Lesenswert?

Naja, da ich mir nicht sicher bin, was du in deinem Code geändert hast 
und was nicht, gehe ich von dem obigen aus. Im zweiten Teil treten die 
Probleme auf? So wie ich das sehe versuchst du den Wert der Variablen c 
auszugeben oder? Und danach inkrementierst du c. Und das ausgeben von c 
funktioniert dann nicht oder wie?

von Karl H. (kbuchegg)


Lesenswert?

Schränk dich mal den Laufbereich von c ein, bzw. vereinfache dein 
Testprogramm weiter.

von hierundda (Gast)


Lesenswert?

Du gibst Steuerzeichen aus. Versuche es mal mit c='0' statt c=0 in der 
ersten Zeile. Und dann vielleicht ein delay zwischen dem Setzen des 
cursors und der Ausgabe.

von L. J. (luke1)


Lesenswert?

Probier doch mal, ob das funktioniert:

char c=5;
lcd_data(c);

Da müsstest du ja dann eigentlich die 5 sehen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

L. J. schrieb:
> Probier doch mal, ob das funktioniert:
>
> char c=5;
> lcd_data(c);
>
> Da müsstest du ja dann eigentlich die 5 sehen.

Das bezweifle ich doch stark.

Gruß,

Frank

von Andreas P. (andreasp)


Lesenswert?

L. J. schrieb:
> char c=5;
> lcd_data(c);
> Da müsstest du ja dann eigentlich die 5 sehen.
? Ne, das ist ja 0x05 -> Steuerzeichen. Das Zeichen '5' wäre 0x35.

Stört euch mal nicht an der Schleife mit dem c. Damit bin ich nur auf 
die Schliche gekommen, welche Zeichen alle nicht funktionieren.
Die gleiche Routine (lcd_data) klappt ja, wenn sie außerhalb der while 
Schleife aufgerufen wurde.

Vorher hatte ich da mal stehen:
while (1)
{
lcd_string("Peters");
}

und auf dem Display stand:
"üeters"

Ich probiere heute Abend mal die andere lib aus.

von L. J. (luke1)


Lesenswert?

Wow dann müsste da aber oft üeters stehen^^.

von Andreas P. (andreasp)


Lesenswert?

L. J. schrieb:
> Wow dann müsste da aber oft üeters stehen^^.
(Die Schleife war jetzt nur sinngemäß wiedergegeben, da ich den Code 
gerade nicht kopieren kann).
Alternativ wird ein '@' durch Omega-Zeichen ersetzt und die 0 durch ein 
Durchschnittssymbol.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Peters schrieb:

> Stört euch mal nicht an der Schleife mit dem c. Damit bin ich nur auf
> die Schliche gekommen, welche Zeichen alle nicht funktionieren.
> Die gleiche Routine (lcd_data) klappt ja, wenn sie außerhalb der while
> Schleife aufgerufen wurde.

Hä?

Ich denke, die Schleife ist wichtiger Bestandteil des Fehlers?

  wenn du

  lcd_data( 'P' );

machst, funktioniert alles,
wenn du

  while( 1 )
    lcd_data( 'P' );

machst, kriegst du 'ü'

Oder wie, oder was?


Ich tippe da auch erst mal auf ein Timingproblem. Das sich der Compiler 
da verhaut ... so recht glaub ich da nicht daran.

von L. J. (luke1)


Lesenswert?

Frank M. schrieb:
> Das bezweifle ich doch stark.

Oh jetzt habe ich selber den Fehler gemacht. Es sollte char c='5' 
heißen. Sorry.

von Andreas P. (andreasp)


Lesenswert?

Karl heinz Buchegger schrieb:
>   lcd_data( 'P' );
> machst, funktioniert alles,
> wenn du
>   while( 1 )
>     lcd_data( 'P' );
> machst, kriegst du 'ü'
> Oder wie, oder was?
Genau das ist es. Und die Regelmäßigkeit betrifft alle Zeichen, die in 
Hex 0x20, 0x30, 0x40, 0x50 sind. Diese kommen als 0xf2, 0xf3, 0xf4, 0xf5 
auf dem Display an.

> Ich tippe da auch erst mal auf ein Timingproblem. Das sich der Compiler
> da verhaut ... so recht glaub ich da nicht daran.
Es werden ja immer die gleiche Routinen durchlaufen...:(

von Karl H. (kbuchegg)


Lesenswert?

Andreas Peters schrieb:
> Karl heinz Buchegger schrieb:
>>   lcd_data( 'P' );
>> machst, funktioniert alles,
>> wenn du
>>   while( 1 )
>>     lcd_data( 'P' );
>> machst, kriegst du 'ü'
>> Oder wie, oder was?
> Genau das ist es. Und die Regelmäßigkeit betrifft alle Zeichen, die in
> Hex 0x20, 0x30, 0x40, 0x50 sind. Diese kommen als 0xf2, 0xf3, 0xf4, 0xf5
> auf dem Display an.
>
>> Ich tippe da auch erst mal auf ein Timingproblem. Das sich der Compiler
>> da verhaut ... so recht glaub ich da nicht daran.
> Es werden ja immer die gleiche Routinen durchlaufen...:(

OK , Test
1
#include "lcd_routines.h"
2
3
int main(void)
4
{
5
  lcd_init();
6
7
  lcd_data( 'P' );
8
  lcd_data( 'P' );
9
  lcd_data( 'P' );
10
11
  _delay_ms( 1000 );
12
  lcd_clear();
13
14
  while( 1 )
15
  {
16
    lcd_data( 'P' );
17
    _delay_ms(500);
18
  }
19
20
  return 0;
21
}

welche dieser 'P' werden als 'ü' ausgegeben.

von Andreas P. (andreasp)


Lesenswert?

Karl heinz Buchegger schrieb:
> welche dieser 'P' werden als 'ü' ausgegeben.
Na, das ist doch in genau das, was in meinem Eingangspost ganz oben 
steht. Die ersten P's tauchen sauber auf, die dann erscheinenden P's 
werden als ü's ausgegeben. Ich hatte das mit "0@P" ausprobiert.

Werde heute Abend den Sourcecode exakt so einmal eingeben und austesten.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Peters schrieb:

> Werde heute Abend den Sourcecode exakt so einmal eingeben und austesten.

Ich bitte darum.
In deinem Code taucht nämlich auch noch SetCursor etc auf.

Ausserdem ist ein Aufruf von lcd_string nicht unbedingt mit einem 
mehrfach hintereinander erfolgtem Aufruf von lcd_data zu vergleichen.

c ist bei dir int, etc.

Da gibt es schon ein paar Unterschiede, die sich zb auswirken wenn du 
lcd_routines.h nicht inkludiert hast. (Hast du doch, oder?   -> immer 
kompletten Source Code posten!)

von Andreas P. (andreasp)


Lesenswert?

Karl heinz Buchegger schrieb:
> Da gibt es schon ein paar Unterschiede, die sich zb auswirken wenn du
> lcd_routines.h nicht inkludiert hast. (Hast du doch, oder?   -> immer
> kompletten Source Code posten!
Ja, habe ich, ich hatte dann irgendwann die kompletten Beispiele aus dem 
Tutorial übernommen.

Beim stöbern gerade habe ich widersprüchliche Aussagen zu DB0-DB3 
gefunden -> Offen lassen oder grounden ?

von spess53 (Gast)


Lesenswert?

Hi

>Offen lassen oder grounden ?

Die Pins haben interne Pullups.

MfG Spess

von Patrick B. (p51d)


Lesenswert?

Andreas Peters schrieb:
> Karl heinz Buchegger schrieb:
>> welche dieser 'P' werden als 'ü' ausgegeben.
> Na, das ist doch in genau das, was in meinem Eingangspost ganz oben
> steht. Die ersten P's tauchen sauber auf, die dann erscheinenden P's
> werden als ü's ausgegeben. Ich hatte das mit "0@P" ausprobiert.

In meinen Augen sieht das auch, wie schon erwähnt nach einem 
Timing-Problem aus.
Ich hatte solche Probleme auch schon, aber da wars weil ich Speed-halber 
an den Delay-Zeiten rumgebastelt habe.

Ich würde so vorgehen:
1) Überprüfe ob für die Delay-Funktion die Quarzfrequenz stimmt
2) erhöhe mal sämtliche delays im Header-File (z.B doppelt so gross).

was hat das anschliessend für ein Effekt?

von Andreas P. (andreasp)


Lesenswert?

spess53 schrieb:
> Die Pins haben interne Pullups.
Hmm, d.h. bei der Übertragung des High-Nibbles liegt dann z.B. für 0x40 
('@')
0b11110100 = 0xf4 an, würde man dabei kurz im 8-Bit Modus lesen.
Aber das das Display dabei hin- und herschaltet kann eigentlich nicht 
sein, oder ?

von spess53 (Gast)


Lesenswert?

Hi

>Hmm, d.h. bei der Übertragung des High-Nibbles liegt dann z.B. für 0x40
>('@') 0b11110100 = 0xf4 an,

Nein. Wenn schon dann $4F. Deine Datenleitungen liegen an D4...D7.

MfG Spess

von g457 (Gast)


Lesenswert?

Ist das ein HD44780(-kompatibler) Chip? Falls ja dann könntest Du 
Timing-Probleme recht einfach bestätigen (und beheben) indem Du das 
busy-Flag zurückliest. Winzigster Hardwareaufwand und wenig 
Softwareaufwand. Die Details dazu stehen im Datenblatt.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Ich würde vorallem mal prüfen das die Ports korrekt auf Ausgang 
konfiguriert sind.

von Andreas P. (andreasp)


Lesenswert?

Patrick B. schrieb:
> In meinen Augen sieht das auch, wie schon erwähnt nach einem
> Timing-Problem aus.
Da hatte ich auch schonmal vermutet.

> 1) Überprüfe ob für die Delay-Funktion die Quarzfrequenz stimmt
Ich nutze den internen Oszillator. Den hatte ich per Fuse schonmal auf 1 
MHz und auf 8 MHz gesetzt, in beiden Varianten das gleiche. Die Frequenz 
habe ich grob geprüft, durch die Verzögerung in der Ausgabe (500ms), die 
passte.

> 2) erhöhe mal sämtliche delays im Header-File (z.B doppelt so gross).
Hatte ich ebenfalls schonmal gemacht, brachte keine Besserung, wieder 
zurückgebaut.

Allerdings habe ich gestern Nacht an soviele Stellen geschraubt, das ich 
nicht ausschließen will, irgendwas verschlimmbessert zu haben.

von L. J. (luke1)


Lesenswert?

Hilfreich wäre jetzt der komplette Source Code, sonst raten wir nur rum.

von Andreas P. (andreasp)


Lesenswert?

L. J. schrieb:
> Hilfreich wäre jetzt der komplette Source Code, sonst raten wir nur rum.
Ich mache heute abend 3 Sachen:
1. Komplett neues Projekt anlegen, alle 3 Files aus dem Tutorial neu 
kopieren und einfügen
2. Hauptprogramm anpassen an den String den ich will -> gucken.
3. Lib von Fleury ausprobieren.

von Karl H. (kbuchegg)


Lesenswert?

Andreas Peters schrieb:

> 3. Lib von Fleury ausprobieren.


Die Fleury Lib benötigt eine Beschaltung des R/W Pins vom LCD. Nicht 
dass du da dann lang rumsuchst.

von Andreas P. (andreasp)


Lesenswert?

Karl heinz Buchegger schrieb:
> Die Fleury Lib benötigt eine Beschaltung des R/W Pins vom LCD. Nicht
> dass du da dann lang rumsuchst.
Nene, das ist schnell gemacht ;)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Andreas Peters schrieb:
> Nene, das ist schnell gemacht ;)

Naja, bei einem KS0066U (der ist (fast) "kompatibel") handelt man sich 
beim Auswerten des Busy-Flags neue Probleme ein:

Beitrag "LCD-Kontroller KS0066U, HD44780, Timing bei Busy-wait"
http://www.sprut.de/electronic/lcd/index.htm#ks0066u
Beitrag "Re: LCD (HD44780) timing extrem träge"

Ich selbst benutze das Busy-Flag schon lange nicht mehr, macht nur 
Ärger.

Gruß,

Frank

von Andreas P. (andreasp)


Angehängte Dateien:

Lesenswert?

So, es wird irgendwie immer seltsamer.
Neues Projekt angelegt für 2313. Alle 3 Beispieldateien aus dem Tutorial 
1:1 kopiert.
Anpassungen für CPU & Ports gemacht, sonst NICHTS.

Laut Anweisungen sollte erscheinen:
"Test            "
"Hello World!    "

Erschienen ist:
"Test            "
"HelloRWoWld!    "

Ich habe daraufhin das Display gewechselt. Vorher weiße/blau, jetzt blau 
schwarz, auch T1602A. Ausgabe:
"Test            "
"Hello*Wo*ld!    "
(Die beiden * sind dabei 2 chinesische Hyroglyphen.)

Zum Testaufbau:
Pollin Eval Board 2.01, IDE-Flachbandkabel, Add On Board V1.0, alle 
Jumper runter, Drahtbrücken zwischen PortB und LCD, Display gesteckt auf 
der Platine, programmiert über AVR MKII original mittels ISP Anschluss, 
8MHz intern per RC und extern per crystal.

Zu guter letzt Programm wie folgt abgeändert:
int main(void)
{
  lcd_init();
  lcd_data( 'r' );
  lcd_data( 'r' );
  lcd_data( 'r' );
  lcd_data( 'r' );
  lcd_string("Hello World!");
  while(1)
  {
  }
  return 0;
}
Erwartet: "rrrrHello World!"
erhalten: "rrrrHello*Wo*ld!
* = Hieroglyphen.

Ich probier jetzt mal die Fleury Lib aus... kopfschüttel

von holger (Gast)


Lesenswert?

>IDE-Flachbandkabel

Wie lang ist das Teil?

von Andreas P. (andreasp)


Lesenswert?

holger schrieb:
> Wie lang ist das Teil?
ca. 12 cm g

von holger (Gast)


Lesenswert?

Versuchs mal so:
1
////////////////////////////////////////////////////////////////////////////////
2
// Erzeugt einen Enable-Puls
3
static void lcd_enable( void )
4
{
5
    LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
6
    _delay_us( LCD_ENABLE_US );  // kurze Pause
7
    LCD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
8
    _delay_us( LCD_ENABLE_US );  // kurze Pause
9
}

von Andreas P. (andreasp)


Lesenswert?

holger schrieb:
> Versuchs mal so:
Brachte keine Besserung. Probiere gerade nochwas aus.

von Andreas P. (andreasp)


Lesenswert?

Andreas Peters schrieb:
> Brachte keine Besserung. Probiere gerade nochwas aus.
Ich glaube, ich habe das Rätsel gelöst.
Problem ist: Sobald ein Zeichen ausgegeben wird, das im Low-Nibble ein 
0x?F hat, wird beim nächsten Zeichen das Low-Nibble als High-Nibble 
verwendet.
1
#include <avr/io.h>
2
#include "lcd-routines.h"
3
#include <util/delay.h>
4
 
5
int main(void)
6
{
7
  lcd_init();
8
 
9
  // Text in einzelnen Zeichen ausgeben
10
  // Vermutung -> Wenn das letzte Zeichen auf Hex 0x?f endete,
11
  // Wird das Nächste Zeichen aus Low Nibble alt und HighNibble Neu Falsch gebildet
12
  lcd_data( 0x48 );// H
13
  lcd_data( 0x65 );// e
14
  lcd_data( 0x6c );// l
15
  lcd_data( 0x6c );// l
16
  lcd_data( 0x6f );// o
17
  lcd_data( 0x48 );// H (Hier wird Omega angezeigt 0xf4
18
  lcd_data( 0x6f );// o
19
  lcd_data( 0x50 );// P (Hier wird ein kleines ü angezeigt (0xf5
20
  lcd_data( 0x50 );// P Dieses P ist einwandfrei
21
  lcd_data( 0x3f );// ? (endet auch auf f)
22
  lcd_data( 0x40); // @ 
23
  // Soll: HelloHoPP?@
24
  // Ist:  Hello*oüP?*     // * = Omega 
25
  // Falsch     ^ ^  ^ 
26
  while(1)
27
  {
28
  }
29
 
30
  return 0;
31
}

Habe das Display dann von Port B auf Port D umgedrahtet auf dem 
Evaluationsboard.
Und schon werden alle Zeichen einwandfrei sauber angezeigt.
Ich habe den MC auf der Eval-Platine mit dem Atmel ISP und Buchsenleiste 
programmiert. Das Evaluationsboard hat aber noch einen serielle ISP aus 
diskreten Bauteilen. Der hängt fest an den Leitungen.
Ich vermute jetzt das die Bauteile da Streß machen und irgendwie ein 
Enable-Signal verschleifen, woraufhin das neu reingeschobene Nibble 
nicht übernommen wird.

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.