attiny2313, LCD, 4-Bit, C, Einzelne Zeichen falsch

OP #1788078
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.
OP #1788147
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.
Gast #1788166
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.
OP #1788219
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.
Angehängte Dateien:
OP #1788251
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.
#1788308
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?
OP #1788345
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.
#1788416
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.
OP #1788490
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...:(
#1788494
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.
#1788591
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!)
OP #1788635
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 ?
#1788675
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?
Gast #1788688
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.
OP #1788698
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.
Moderator Persönliche Seite #1788916
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
OP #1789134
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
Angehängte Dateien:
Gast #1789161
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
}
OP #1789398
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren