Forum: Compiler & IDEs Seltsamer "LCD Fehler"


von Teo D. (teoderix)


Lesenswert?

Hi,

spiel hier grad mit nem PIC18F25K22 rum.
[laber]
Bei der Gelegenheit wollte ich der bisher hervorragend funktionierenden 
LCD-Routine, das dämliche 2ms warten austreiben. Ergebnis Display tot. 
Ziemlich dumm auf den wahrscheinlich funktionierenden Code gestarrt... 
OK alles retoure (Backup), noch mehr blöd guck... Als der Hamster wieder 
auf dem Rad war, hab ich das fehlende Häkchen im Codeconfigurator 
eindeckt... grr.. Erst mal'n Pfeif... ähh ne Zigarette angezündet.
So ab nu wird's lustig. Alles, bis auf eine Kleinigkeit, funktioniert 
alles wie vorher.
[/laber]

Folgender Code produziert nicht wie gehabt die Ausgabe:
"xx.x°C"
Sondern:
"xx.x°B"
Also ASCII+1. Alle anderen Ausgaben auf dem LCD, sind Korrektor.

Ich habe nicht die geringste Idee wo ich da den Fehler suchen sollte?
1
void Temp_LCD_Ausgabe(char tab) {
2
    char PBuff[5], buffer, n;
3
4
    temperatur = Temp_messen();
5
    utoa(PBuff, temperatur, 10);
6
    n = strlen(PBuff) - 1;
7
    buffer = PBuff[n];
8
    PBuff[n] = '.';
9
    PBuff[++n] = buffer;
10
    PBuff[++n] = 0xdf; // "°"
11
    PBuff[++n] = 'C';
12
    PBuff[++n] = NULL;
13
    LCD_Tab(tab);
14
    LCD_Print(PBuff);
15
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Teo D. schrieb:
> char PBuff[5]

Wie viele Zeichen möchtest du da gleich ausgeben, einschließlich
des terminierenden Nullzeichens?

> PBuff[++n] = NULL;

NULL ist per Konvention ein Zeiger, aber kein Nullzeichen.  Das heißt
entweder einfach 0, oder wenn du's kompliziert magst, '\0'.

von Teo D. (teoderix)


Lesenswert?

Jörg W. schrieb:
> Wie viele Zeichen möchtest du da gleich ausgeben, einschließlich
> des terminierenden Nullzeichens?

3(char) + 2(.,C) + 1(NULL) = 6
...°
Naja, die Rechnung stimmt wenigstens :(
DANKE
(kann mich garnicht erinnern da rumgepfuscht zu haben. Zeiger... hat 
wahrscheinlich bisher nur zufällig funktioniert)

Jörg W. schrieb:
> NULL ist per Konvention ein Zeiger, aber kein Nullzeichen.  Das heißt
> entweder einfach 0, oder wenn du's kompliziert magst, '\0'.

Hmm... laut Manual vom XC8 ist das auch (?) der Nullterminator für 
"Strings"

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Teo D. schrieb:
> Hmm... laut Manual vom XC8 ist das auch (?) der Nullterminator für
> "Strings"

Dann benutz' das Manual zum Entzünden des nächsten Lagerfeuers.
Vielleicht eignet es sich ja wenigstens dafür. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Teo D. schrieb:

> Hmm... laut Manual vom XC8 ist das auch (?) der Nullterminator für
> "Strings"

Ja. Numerisch sind NULL, 0, '\0' alles dasselbe. Eine binäre 0.

Aber die Intention von NULL ist es, einen ungültigen Pointer Wert 
anzuzeigen. Die Betonung liegt auf Pointer. NULL wird also per 
Konvention im Umfeld von Pointern verwendet. Niemand klopft dir auf die 
Finger, wenn du es in einem anderen Umfeld benutzt. Aber die Verwirrung 
ist gross. Denn was hat denn der Inhalt einer char Variablen mit einem 
Pointer zu tun? Gar nichts.

Das ist ungefähr so, wie wenn du schreibst
1
  double radius = 'a';
2
  double umfang = 2 * radius * 3.1415926;

kannst du machen. Als Character hat 'a' einen Ascii Code, diese Codezahl 
wird zu einem double gewandelt und zugewiesen. Syntaktisch ist da nichts 
falsch drann.
Trotzdem ist es wohl in den meisten Fällen verwirrend.

Solche Dinge fallen unter den Oberbegriff der 'aktiven 
Arbeitsplatzsicherung'.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Da hab ich wohl zu sehr den Ausdruck "null terminated" mit "#define NULL 
'\0'" assoziiert :)

OK, also lieber "=0" oder "='\0'".

von Karl H. (kbuchegg)


Lesenswert?

Teo D. schrieb:
> Da hab ich wohl zu sehr den Ausdruck "null terminated" mit "#define NULL
> '\0'" assoziiert :)
>
> OK, also lieber "=0" oder "='\0'".

Probier mal, ob dein System ein #define für NUL (mit 1 L) hat. Das wäre 
dafür gedacht, den 0-Character auszudrücken.

von Teo D. (teoderix)


Lesenswert?

Nö, hat er nich. Egal, schreib den Mist ja eh nur für mich.

Momentan nervt mich mehr daß mir das,
1
bool LCD_Bussy(void) {
2
    bool x;
3
    LCD_D3_SetDigitalInput();
4
    LCD_RS_LAT = 0;
5
    LCD_RW_LAT = 1;
6
//        __delay_us(25);
7
    x = LCD_D3_PORT;
8
    LCD_D3_SetDigitalOutput();
9
    return (x);
10
  }
scheinbar kein BussyFlag aus dem LCD entlockt. Liest ständig Hi ein!
Nicht mein Tag Heute, steh sicher wiedermal nur auf'm Schlauch :(

PS:Dabla nach Besonderheiten der Pins durchforstet! Nix.
Morgen mal den "Code Configurator" überprüfen, ob der auch wirklich 
alles so wie gewollt generiert hat. Wär nicht das erste mal das nicht.

: Bearbeitet durch User
von neuer PIC Freund (Gast)


Lesenswert?

Müsste es nicht

3(char) + 3(.,C,°) + 1(NULL) = 7

heißen?

von Teo D. (teoderix)


Lesenswert?

neuer PIC Freund schrieb im Beitrag #4295017:
> Müsste es nicht
>
> 3(char) + 3(.,C,°) + 1(NULL) = 7
>
> heißen?

Jup und dank Jörg W. ist's mir auch aufgefallen das da was fehlt.
Lustig ist halt, das das mehrere Tage problemlos funktioniert hat (trotz 
ständigen Programmänderungen).

von Karl H. (kbuchegg)


Lesenswert?

Teo D. schrieb:

> Jup und dank Jörg W. ist's mir auch aufgefallen das da was fehlt.
> Lustig ist halt, das das mehrere Tage problemlos funktioniert hat (trotz
> ständigen Programmänderungen).

Merke.
Nicht jeder Fehler führt sofort zu einem Problem.
Durch Testen kann man immer nur die Anwesenheit von Fehlern feststellen. 
Nie die Abwesenheit.

von beric (Gast)


Lesenswert?

Teo D. schrieb:
> Hmm... laut Manual vom XC8 ist das auch (?) der Nullterminator für
> "Strings"

Ich wette da steht "NUL" und nicht "NULL".

Teo D. schrieb:
> Momentan nervt mich mehr daß mir das,
>   bool LCD_Bussy(void) {
>     bool x;
>     LCD_D3_SetDigitalInput();
>     LCD_RS_LAT = 0;
>     LCD_RW_LAT = 1;
>   //        __delay_us(25);
>     x = LCD_D3_PORT;
>     LCD_D3_SetDigitalOutput();
>     return (x);
>   }
> scheinbar kein BussyFlag aus dem LCD entlockt. Liest ständig Hi ein!

Busy schreibt mal üblicherweise mit nur einem s.

Funktioniert es wenn das 25us Delay NICHT ausgeklammert ist? Ich kenne 
zwar dein uC nicht, aber kann mir vorstellen das er sich ein bisschen 
Zeit nehmen möchte um die Port-Richtung zu ändern.

von Teo (Gast)


Lesenswert?

beric schrieb:
> Busy schreibt mal üblicherweise mit nur einem s.
Ubs, (danke)


Klar hab ich das getestet, deshalb steht das ja auch noch da. Kommt zum 
weiter testen aber wieder rein. Hab kein original Dabla, nur 
Pinbelegung, Spannungen und "kompatibel mit HD47...". Pollin Zeugs halt. 
Wer weiß wie lang das teil zum umladen der Gatekapazität braucht.

von Karl H. (kbuchegg)


Lesenswert?

beric schrieb:

Ich weis ja nicht, welches LCD du benutzt, aber das kommt mir komisch 
vor
1
bool LCD_Bussy(void) {
2
    bool x;
3
    LCD_D3_SetDigitalInput();
4
    LCD_RS_LAT = 0;
5
    LCD_RW_LAT = 1;
6
//        __delay_us(25);
7
    x = LCD_D3_PORT;
8
...

kein Übernahmepuls? Oder sonst irgendeine Benachrichtigung nach dem 
Muster 'jetzt gilts'?
Einfach nur R/S auf 0 setzen, RW auf 1 und das wars?
Kann ich mir nicht vorstellen.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:
> beric schrieb:
>
> Ich weis ja nicht, welches LCD du benutzt, aber das kommt mir komisch
> vor
>
1
> bool LCD_Bussy(void) {
2
>     bool x;
3
>     LCD_D3_SetDigitalInput();
4
>     LCD_RS_LAT = 0;
5
>     LCD_RW_LAT = 1;
6
> //        __delay_us(25);
7
>     x = LCD_D3_PORT;
8
> ...
9
>
>
> kein Übernahmepuls? Oder sonst irgendeine Benachrichtigung nach dem
> Muster 'jetzt gilts'?
> Einfach nur R/S auf 0 setzen, RW auf 1 und das wars?
> Kann ich mir nicht vorstellen.

Schaun wir mal, wie Grossmeister Fleury das macht
1
static uint8_t lcd_waitbusy(void)
2
3
{
4
    register uint8_t c;
5
    
6
    /* wait until busy flag is cleared */
7
    while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) {}

ok. also die Funktion lcd_read macht das.
1
static uint8_t lcd_read(uint8_t rs) 
2
{
3
    uint8_t data;
4
    
5
    
6
    if (rs)
7
        lcd_rs_high();                       /* RS=1: read data      */
8
    else
9
        lcd_rs_low();                        /* RS=0: read busy flag */
10
    lcd_rw_high();                           /* RW=1  read mode      */
11
12
bla bla bla
13
    
14
        lcd_e_high();
15
        lcd_e_delay();        
16
        data = PIN(LCD_DATA0_PORT) << 4;     /* read high nibble first */
17
        lcd_e_low();
18
19
...

AHA!!!
Also doch einmalig mit dem E-Pin wackeln.
Ist auch logisch so.
Woher soll denn das LCD wissen, wann du fertig bist mit dem Einstellen 
der Steuerleitungen.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl H. schrieb:
> Ich weis ja nicht, welches LCD du benutzt

Er schrob: „kompatibel mit HD44780“, dann wird es schon einen Impuls
an E brauchen.

von Teo D. (teoderix)


Lesenswert?

Karl H. schrieb:
> AHA!!!
> Also doch einmalig mit dem E-Pin wackeln.

Davon steht aber in meinem Dabla nix :(
OK, sorry, ist kein original HD47... Hat wohl etwas gelitten, beim 
abschreiben und übersetzen. Sieht aber dem Original zum verwechseln 
ähnlich. Werd das mal genauer vergleichen.

Werd's später mal wackeln lassen :)


> Ist auch logisch so.
> Woher soll denn das LCD wissen, wann du fertig bist mit dem Einstellen
> der Steuerleitungen.

Ich dachte, das hat wohl nichts direkt mit dem Prozessor zu tun, sondern 
da antwortet ein einfaches Logikgatter.

von Teo D. (teoderix)


Lesenswert?

Ach ja....

beric schrieb:
> Ich wette da steht "NUL" und nicht "NULL".

VERLOREN ;P
Da steht was von "Nullterminator, null terminated" und '\0'. "NUL" oder 
"NULL" wird da nirgends erwähnt.

"NUL" ist im xc8 nicht definiert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Teo D. schrieb:
> Ich dachte, das hat wohl nichts direkt mit dem Prozessor zu tun, sondern
> da antwortet ein einfaches Logikgatter.

Das Datenblatt ist da etwas seltsam.  Zum einen suggeriert es das,
was du da rausgelesen hast, andererseits siehe Bild, die read operation
bekommt in den Timing-Diagrammen ganz normal ihre Timing-Werte.

Ich hab' sie jedenfalls bisher auch immer als kompletten Buszyklus
(mit E-Impuls und allem) behandelt, und das hat funktioniert. ;-)

von W.S. (Gast)


Lesenswert?

Ach, ihr streitet euch mal wieder um des Kaisers Bart.
Offenbar geht es darum, daß der TO eine Art Dezimalpunkt in seine 
Zeichenfolge haben möchte, aber sich scheut, deswegen auf float 
umzusteigen. Nun ja, dann eben so:
1
void CharInsert (char* Buffer, int maxlen, int pos, char was)
2
{ int i;
3
  char a, b;
4
  i = 0;
5
  while (i<pos)
6
  { if (Buffer[i]==0) return;
7
    ++i;
8
  }
9
  a = was;
10
  while (i<maxlen)
11
  { b = Buffer[i];
12
    Buffer[i] = a;
13
    if (a==0) return;
14
    a = b;
15
    ++i;
16
  }
17
}
Hab's mal aus einem steinalten Projekt herausgekramt.

Aber nochwas: Der Titel des Threads ist voll daneben. Sowas hat mit 
LCD's überhaupt nichts zu tun, sondern nur mit des TO's Problem beim 
Einfügen eines Zeichens. Besser: "wie füge ich ein Zeichen in eine 
Zeichenkette ein?"

W.S.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Offenbar geht es darum, daß der TO eine Art Dezimalpunkt in seine
> Zeichenfolge haben möchte, aber sich scheut, deswegen auf float
> umzusteigen.

Nein, das war geklärt.  Mittlerweile geht's um das Busy-Flag eines
HD44780.

von Teo D. (teoderix)


Lesenswert?

W.S. schrieb:
> Ach, ihr streitet euch mal wieder um des Kaisers Bart.
Äh.. NÖ
> Offenbar geht es darum, daß der TO eine Art Dezimalpunkt in seine
> Zeichenfolge haben möchte,
Nein, ging es NIE!
> aber sich scheut, deswegen auf float umzusteigen.
NUR um da einen Dezimalpunkt zu erhalten und dann doch noch die zwei 
extra Zeichen dazu pfuschen? NEIN, da stell ich mich doch lieber 
neben's LCD und pinsle das mit der Hand drauf ;)

W.S. schrieb:
> Aber nochwas: Der Titel des Threads ist voll daneben.
Ämmm... JA.

> Besser: "wie füge ich ein Zeichen in eine
> Zeichenkette ein?"
NEIN, darum ging's hier NIE



Jörg W. schrieb:
> Teo D. schrieb:
>> Ich dachte, das hat wohl nichts direkt mit dem Prozessor zu tun, sondern
>> da antwortet ein einfaches Logikgatter.
>
> Das Datenblatt ist da etwas seltsam.  Zum einen suggeriert es das,
> was du da rausgelesen hast, andererseits siehe Bild, die read operation
> bekommt in den Timing-Diagrammen ganz normal ihre Timing-Werte.

Dazu kommt noch die Angabe von 0µs als Antwortzeit!? Ist aber sicher 
ein Fehler in meinem Ausdruck, da hat sich wohl ne Zahl verflüchtigt 
:)

Alles wackeln am Enable-Pin, auf die eine o. andren Art, hat erst mal 
nix genutzt.

Werde da erstmal ein vertrauenswürdigeres LCD dranhängen.

von Teo D. (teoderix)


Lesenswert?

Hier das verwendete Display:
http://www.pollin.de/shop/dt/NzczOTc4OTk-/Bauelemente_Bauteile/Aktive_Bauelemente/Displays/LCD_Modul_C0802_04.html
Falls da einer Erfahrung damit hat und es eventuell doch Abweichungen 
zum HD4780 gibt. Glaub ich zwar nicht, der eigentliche Fehler hat sich 
sicher über die Tastatur eingeschlichen aber die Hoffnung stirbt 
zuletzt. Da wird's sicher noch einen geben, dem ich das in die Schuhe 
schieben kann :)

von Teo D. (teoderix)


Angehängte Dateien:

Lesenswert?

Hab obiges noch im Original gefunden.
Ergibt bei mir sicher >7µs. Da bisher nicht beachtet, haut das natürlich 
in meinem Progrämmchen nicht hin (höchstens 2-4µs).

Übrigens lässt mich der Original Dabla wieder glauben das da nicht am 
Enable gewackelt werden muss. Da ist noch ein Blockschaltbild zu sehen, 
in dem die Enable-Funktion als gesonderter Block dargestellt wird!?
http://www.alldatasheet.com/datasheet-pdf/pdf/63673/HITACHI/HD44780.html

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Teo D. schrieb:
> Hab obiges noch im Original gefunden.

Das ist aber nur der Update des Adresszählers, falls du ihn
abfragen willst.

Eine Seite davor ist die interessante Stelle (ich bin jetzt gerade
anderweitig drüber gestolpert):
1
Table 6       Instructions
2
                                                                                     Execution Time
3
                                 Code                                                (max) (when f cp or
4
Instruction RS  R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0  Description                     f OSC is 270 kHz)
5
6
Read busy    0    1  BF  AC  AC  AC  AC  AC  AC  AC  Reads busy flag (BF)            0 µs
7
flag &                                               indicating internal operation
8
address                                              is being performed and
9
                                                     reads address counter
10
                                                     contents.

Das heißt, dass das Lesen des Busy-Flags (und des Adresszählers)
ein ganz normaler Befehl wie jeder andere ist, also RS = 0 (da Befehl
und nicht Daten), R/W = 1 (da gelesen werden soll).  Implizit ist
dabei wie bei jeder anderen Aktion ein Impuls an E.  Wesentlicher
Unterschied gegenüber allen anderen Befehlen ist, dass er keine
eigene Ausführungszeit benötigt, d. h. es darf sofort danach ein
neuer Befehl gesendet werden.

Aber einfach nur RW auf 1 setzen und RS auf 0 genügt nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

So, inzwischen läuft meine eigene Implementierung auch auf dem SAMD20.

Da ich sowieso zum Vergleich noch das Diagramm meiner älteren
AVR-Implementierung auf dem LA hatte, hier dieses mal zur Illustration.
Es wird zuerst das Zeichen 'A' (0x41) ausgegeben, jeweils beide
Halbbytes.  Danach werden immer zwei Halbbytes gelesen, die das Busyflag
sowie den aktuellen Adresszähler beinhalten.  Man sieht gut, wie das
von anfangs 0x84 auf danach 0x05 weitergeht.

: Bearbeitet durch Moderator
von Teo D. (teoderix)


Lesenswert?

Danke für die Infos :)

Hatte bisher keinen Bock mich mit dem Mist zu beschäftigen.
Tabelle 6 klärt fast alles auf. Auf Grund meiner bisherigen 
Versuche, stellt sich mir noch die Frage:
Welches Nibble purzelt den da zuerst raus?
Ich bin bisher davon ausgegangen das es das Hi-Nbble ist. Das Dabla 
schweigt sich darüber leider aus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Teo D. schrieb:
> Ich bin bisher davon ausgegangen das es das Hi-Nbble ist.

Wenn du dir den LA-Trace oben ansiehst, kannst du recht gut erkennen,
dass es genau so auch ist.  Da kommt eine 4 gefolgt von einer 1 (0x41
für den Buchstaben 'A'), danach 8 - 4, 8 - 4, 0 - 5.

Ich hab' nochmal rote Striche an die relevanten Zeitpunkte gezeichnet.

von Teo D. (teoderix)


Lesenswert?

Jörg W. schrieb:
> Da kommt eine 4 gefolgt von einer 1 (0x41
> für den Buchstaben 'A'), danach 8 - 4, 8 - 4, 0 - 5.

Jup, Danke.
(Die 1 dazwischen kommt sicher von deinem Prozi (letztes Write))

So, genug gelöchert, nu wird's Zeit mich da mal wieder selber zu 
bemühen. Hab schon einen Verdacht, wo noch so ein "ich dachte", 
zugeschlagen hat. Aber was will man sonst auch tun, wenn das Dabla nicht 
mehr hergibt :(
Muss nur noch alle größeren Werkzeuge, explizit die Hämmer, verräumen :)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Teo D. schrieb:
> (Die 1 dazwischen kommt sicher von deinem Prozi (letztes Write))

Ja, der schaltet ja anschließend die Pins wieder auf Ausgang, damit
sie nicht „in der Luft hängen“.  In dem Moment wird dann wieder das
auf den Bus gelegt, was als letztes ausgegeben worden war.

Entscheidend ist immer nur, was zum Zeitpunkt des E-Impules passiert.

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.