www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik LCD 0 anzeigen uint16_t


Autor: Elias B. (bouni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Allerseits,

Ich habe folgendes Problem und nach langer Suche im Forum bin ich immer 
noch nicht hinter mein Problem gekommen.

Ich habe ein Grafik LCD von Pollin:
http://www.pollin.de/shop/suchergebnis.html?S_TEXT...

Das funktioniert auch wunderbar.
Da dieses Teil einen Touchscreen hat les ich den auch aus, was ebenfalls 
funktioniert.

Ich bin leider gerade auf Arbeit und hab deswegen den Code nicht hier, 
aber ich versuche es so gut es geht zu beschreiben:

Ich lasse die X und Y Werte der AD Wandlungen auf dem Display anzeigen.
Diese speichere ich heirzu in einem uint16_t und wandle sie mit hilfe 
von itoa() in einen char. (char string[10])
Dieses lass ich auf dem Display ausgeben wenn der Touch gedrückt ist, 
was auch geht, wenn nicht habe Ich eine funktion die eine AD Wandlung 
macht und wenn der Wert > 1000 ist (bei nichtberühren ist er ca. 1020) 
die uint16_t Variable mit 0 beschreibt.

Wenn ich die Variable aber in diesem Fall ausgeben lasse, dann erhalte 
ich eine solche Anzeige _0_12: die unterstriche sind leerzeichen, die 12 
eine zahl die ab und zu schwankt.

Ich habe schon alles mögliche probiert, komme aber nicht hinter das 
Problem :/

Ich vermute das es etwas mit danit zu tun hat das die Variable eine 
16bit breite ist.
hab auch schon versucht mit 0x0000 zu beschreiben, aber ohne erfolg :(

Wenn wer ne lösung hat, ich bin für jede Hilfe dankbar!!

Gruss an alle

Elias

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist sehr wahrscheinlich ein Problem der Ausgabefunktion, die einfach 
eine feste Anzahl Zeichen ausgibt, statt sich am Stringende zu 
orientieren.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und ich habe eben versucht, in deinem Quelltext den Fehler zu
finden, leider auch ohne Erfolg.

Autor: Elias B. (bouni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

erst mal Dnake für die Antworten.

Ich sitze wie gesagt auf Arbeit und habe den Quelltext nicht hier.
Werd Ihn heute Abend posten sobald ich daheim bin.

Ich habe mir auch schon den Wert der 16bit Variable mittels itoa(a,b,2)
binär wandeln lassen und den ausgegeben, und auch dort steht nicht 0 
drin.

Ich denke der Fehler liegt irgendwo auf der Strecke von 0 in die 
Variable schreiben bis zum ausgeben aufs Display.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Elias B. schrieb:

> Ich habe mir auch schon den Wert der 16bit Variable mittels itoa(a,b,2)
> binär wandeln lassen und den ausgegeben, und auch dort steht nicht 0
> drin.

Vorsicht.
Bei einer binären Ausgabe einer 16-Bit Zahl, kann der entstehende String 
logischerweise auch 16 Zeichen lang werden. Du brauchst dann klarerweise 
ein

  char string[17];

10 ist dann zuwenig.

Und noch ein Fehler (aber der erklärt jetzt nicht dein Problem).

itoa:   man beachte das i am Anfang. Das steht für I wie INT
        (also signed int)

Du hast aber keinen signed int. Du hast einen unsigned int. Dafür 
brauchst du die Funktion utoa. u wie 'unsigned'

Ich denke auch, dass die wahrscheinlichste Stelle für einen Fehler die 
Ausgabefunktion ist.
Es könnte auch sein (auch ein beliebter Fehler), dass du übersehen hast, 
dass eine neue Ausgabe die alte überschreibt. Ist die neue Ausgabe 
kürzer als die alte, dann bleibt klarerweise von der alten Ausgabe etwas 
übrig.
Wenn man die Zahl 1018 mit 99 überschreibt, dann steht am Display 9918 
und das kann schnell mal zu Konfusion führen.

Autor: Elias B. (bouni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Habs wohl ein wenig dürftig beschrieben.
Der cah string[20] war 20 Zeichen lang für den versuch mit dem Binär :)

ok, das mit dem utoa leuchtet ein :) -> werd ich auf jeden Fall mal 
ändern.

Mal sehen was der Abend bringt.

Wenn ich einen
uint16_t test;
mit
test = 0;

Mit nul beschreibe müsste er doch komplett null sein oder? Ich meine das 
so nicht nur die untern 8 bit oder so beschrieben werden!?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Elias B. schrieb:

> Wenn ich einen
>
uint16_t test;
> mit
>
test = 0;
>
> Mit nul beschreibe müsste er doch komplett null sein oder? Ich meine das
> so nicht nur die untern 8 bit oder so beschrieben werden!?

Das passt schon so.

Autor: Elias B. (bouni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

Hier der Code mit dem ich den Touch auswerte:
// touch.c

#include "touch.h"
#include "adc.h"

uint8_t touchispressed()
  {
  uint16_t   adc_value = 0;  
  DDRA |=  (1 << PA0) | (1 << PA1); // PA0 auf Ausgang Y1 und PA2 auf Ausgang Y2
  
  DDRA &= ~(1 << PA2); // PA1 auf Eingang X1
  DDRA &= ~(1 << PA3); // PA1 auf Eingang X1

  PORTA |=  (1 << PA0); // PA0 HIGH Y1
  PORTA &= ~(1 << PA1); // PA2 LOW  Y2

  _delay_us(10);

  adc_value = readADC(PA2); // PA1 ADC lesen
  
  if(adc_value > 1000)
    {
    return 0; // Touch ist NICHT gedrückt
    }
  else
    {
    return 1; // Touch ist gedrückt
    }
  }

uint16_t readTouchX() 
  {
  uint16_t   adc_value = 0;  
  if(touchispressed())
    {
    DDRA |=  (1 << PA0) | (1 << PA1); // PA0 auf Ausgang Y1 und PA1 auf Ausgang Y2
  
    DDRA &= ~(1 << PA2); // PA2 auf Eingang X1
    DDRA &= ~(1 << PA3); // PA3 auf Eingang X2

    PORTA |=  (1 << PA0); // PA0 HIGH Y1
    PORTA &= ~(1 << PA1); // PA2 LOW  Y2

    _delay_us(10);

    adc_value = readADC(PA2); // PA2 X1 ADC lesen

    return adc_value; // Touch Wert zurück geben
    }
  else
    {
    return 0; // 0 Zurückgeben    
    }  
  }

uint16_t readTouchY() 
  {
  uint16_t   adc_value = 0;  
  if(touchispressed())
    {
    DDRA |=  (1 << PA2) | (1 << PA3); // PA2 auf Ausgang X1 und PA3 auf Ausgang X2
  
    DDRA &= ~(1 << PA0); // PA0 auf Eingang Y1
    DDRA &= ~(1 << PA1); // PA1 auf Eingang Y2

    PORTA |=  (1 << PA2); // PA0 HIGH X1
    PORTA &= ~(1 << PA3); // PA2 LOW  X2

    _delay_us(10);

    adc_value = readADC(PA0); // PA0 Y1 ADC lesen

    return adc_value; // Touch Wert zurück geben
    }
  else
    {
    return 0; // 0 Zurückgeben        
    }  
  }

Mit dem gebe Ich das ganze auf's Display aus:
void lcd_writechar(unsigned char b)

{  unsigned char i,j,c;

  if (lcd_xpos+5>=160)

  {  lcd_xpos=0;

    if (lcd_ypos+7>=80)

      lcd_ypos=0;

  }

  for (i=0; i<8; i++)

  {  c=pgm_read_byte(&font[ b ][ i ]);

    for (j=0; j<6; j++)

    {  if (c&(32>>j))

        lcd_setpixel(lcd_xpos+j,lcd_ypos+i);

      else

        lcd_clrpixel(lcd_xpos+j,lcd_ypos+i);

    }

  }

  lcd_xpos+=6;

}

void lcd_writestring(const char *string)
{
    do
    {
        lcd_writechar(*string);
    }
    while (*string++);
}

Und hier noch die main.c wo ich das ganze aufrufe:

#define F_CPU 3686400UL

#include <avr/io.h>

#include <avr/interrupt.h>

#include <avr/pgmspace.h>

#include <util/delay.h>
#include <stdlib.h>

#include <portbits.h>


#include "lc7981.h"
#include "adc.h"
#include "touch.h"


int main(void)

{

  lcd_init();  // LCD Controller initialisieren

  uint16_t x_value; // Varaiable für den X Wert
  uint16_t y_value; // Varaiable für den Y Wert
  char string_x[8]; // Varaiable für den X Wert gewandelt in char
  char string_y[8]; // Varaiable für den Y Wert gewandelt in char
  for(;;)
  {
    x_value = readTouchX();     // X Touch Wert lesen
    utoa(x_value, string_x, 10);     // INT in STRING wandeln
    lcd_gotoxy(1,50);      // Auf LCD Position springen
    lcd_writestring(string_x);    // X Wert schreiben
    lcd_gotoxy(32,50);      // Auf LCD Position springen
    lcd_writestringP(PSTR(": X Wert"));  // String dahinter schreiben
    
    y_value = readTouchY();      // X Touch Wert lesen
    utoa(y_value, string_y, 10);     // INT in STRING wandeln
    lcd_gotoxy(1,60);      // Auf LCD Position springen
    lcd_writestring(string_y);    // X Wert schreiben
    lcd_gotoxy(32,60);      // Auf LCD Position springen
    lcd_writestringP(PSTR(": Y Wert"));  // String dahinter schreiben

  }

}

Ich hoffe das hilft weiter.

Den Fehler habe Ich immer noch nicht gefunden :/

Mfg Elias

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ist es das hier:

Karl heinz Buchegger schrieb:
> Es könnte auch sein (auch ein beliebter Fehler), dass du übersehen hast,
> dass eine neue Ausgabe die alte überschreibt. Ist die neue Ausgabe
> kürzer als die alte, dann bleibt klarerweise von der alten Ausgabe etwas
> übrig.
> Wenn man die Zahl 1018 mit 99 überschreibt, dann steht am Display 9918
> und das kann schnell mal zu Konfusion führen.

Ich sehe nämlich nur lauter lcd_gotoxy/lcd_writestring-Kombinationen, 
ohne dass mal irgendwo irgendetwas auf dem LCD gelöscht würde.

Übrigens:
Dein lcd_writestring gibt auch immer die Null-Terminierung mit aus.

Autor: Elias B. (bouni)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,

Der Tipp mit dem LCD löschen hat mich schon entscheidend weitergebracht 
:)

Die 0 funktioniert jetzt.
Aber dafür flackert das Display :/

Hab aber n Work around :) Nicht schön aber selten :D
  for(;;)
  {
    x_value = readTouchX();       // X Touch Wert lesen
    if(x_value > 0)
      {
      utoa(x_value, string_x, 10);     // INT in STRING wandeln
      lcd_gotoxy(1,50);      // Auf LCD Position springen
      lcd_writestring(string_x);    // X Wert schreiben
      }
    else
      {
      lcd_gotoxy(1,50);      // Auf LCD Position springen
      lcd_writestring("0   ");    // X Wert schreiben
      lcd_gotoxy(32,50);      // Auf LCD Position springen
      lcd_writestringP(PSTR(": X Wert"));  // String dahinter schreiben
      }    
    y_value = readTouchY();        // X Touch Wert lesen
    if(y_value > 0)
      {
      utoa(y_value, string_y, 10);     // INT in STRING wandeln
      lcd_gotoxy(1,60);      // Auf LCD Position springen
      lcd_writestring(string_y);    // X Wert schreiben
      }
    else
      {
      lcd_gotoxy(1,60);      // Auf LCD Position springen
      lcd_writestring("0   ");    // X Wert schreiben
      lcd_gotoxy(32,60);      // Auf LCD Position springen
      lcd_writestringP(PSTR(": Y Wert"));  // String dahinter schreiben
      }

  }

Du hast ausserdem geschrieben das:
"Übrigens:
Dein lcd_writestring gibt auch immer die Null-Terminierung mit aus."

Wie kann ich das umgehen ?


Gruss Elias

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Elias B. schrieb:
> Hallo Karl Heinz,
>
> Der Tipp mit dem LCD löschen hat mich schon entscheidend weitergebracht
> :)
>
> Die 0 funktioniert jetzt.
> Aber dafür flackert das Display :/

Das wundert mich nicht gerade.
Deine Routinen werden ziemlich langsam sein, wenn du keine Optimierung 
machst sondern ständig alles auf Pixelebene runterbrichst. Aber das soll 
jetzt (noch) nicht das Problem sein :-)

> Hab aber n Work around :) Nicht schön aber selten :D

Und nicht wirklich zielführend :-)

Aber eins nach dem anderen

> Du hast ausserdem geschrieben das:
> "Übrigens:
> Dein lcd_writestring gibt auch immer die Null-Terminierung mit aus."
>
> Wie kann ich das umgehen ?

Indem du die writeString Funktion so veränderst, dass sie das 
abschliessende '\0' Zeichen eines jeden Strings nicht mit ausgibt.
void lcd_writestring(const char *string)
{
  while (*string)
    lcd_writechar(*string++);
}

Zu deinem Problem.
Was ist denn eigentlich das Problem?

Auf dem LCD steht zb 1023
Jetzt gehst mit dem gotoxy wieder auf den Anfang an dieser Stelle und 
schreibst 78 drüber.
Was steht dann am LCD? Nein da steht nicht 78. Da steht 7823. Dies 
deshalb, weil ja niemand dafür gesorgt hat, dass auch die 23 von 1023 
überschrieben werden.

-> Die einfachste Lösung ist es, für Zahlenausgaben eine Feldbreite 
einzuführen. Also: Die Zahl wird immer in einem Feld der Breite 4 
ausgegeben. Ist die Textdarstellung einer Zahl kleiner als dieses Feld, 
dann wird mit Leerzeichen aufgefüllt. Man kann links auffüllen oder auch 
rechts auffüllen. Füllt man links auf, dann hat man den Vorteil, dass 
die Einerstelle der Zahl immer an der gleichen Position an der 
Ausgabestelle erscheint. Das ist insofern gut, als es beim Lesen hilft, 
wenn die Zahl nicht konstant ist und sich ständig ein wenig ändert. Die 
Zahl springt dann nicht am Display hin und her, wenn sie zb ständig 
zwischen 102 und 99 pendelt.

Wie kannst du auffüllen?
Ganz einfach: Stell die Stringlänge fest und gib die fehlende Anzahl an 
Leerzeichen vorher aus.

Und damit sind wir beim nächsten Punkt:
Eine Zahlenausgabe ist in einem Progamm meistens eine zentrale 
Operation. So wie es auch eine Stringausgabe ist. Es ist daher 
vernünftig sich dafür eine Funktion zu schreiben und nicht den Code 
dafür über das komplette Program x-mal zu verstreuen
void lcd_writeuint( uint16_t Number, uint8_t fieldWidth )
{
  char Buffer[10];
  int8_t Missing, i;

  utoa( Number, Buffer, 10 );

  Missing = fieldWidth - strlen( Buffer );
  for( i = 0; i < Missing; ++i )
    lcd_writechar( ' ' );

  lcd_writestring( Buffer );
}

Damit vereinfacht sich deine Hauptschleife zu
  for(;;)
  {
    x_value = readTouchX();       // X Touch Wert lesen
    lcd_gotoxy(1,50);      // Auf LCD Position springen
    lcd_writeuint(x_value,4);
    lcd_gotoxy(32,50);      // Auf LCD Position springen
    lcd_writestringP(PSTR(": X Wert"));  // String dahinter schreiben

    y_value = readTouchY();        // X Touch Wert lesen
    lcd_gotoxy(1,60);      // Auf LCD Position springen
    lcd_writeuint(y_value,4);
    lcd_gotoxy(32,60);      // Auf LCD Position springen
    lcd_writestringP(PSTR(": Y Wert"));  // String dahinter schreiben
  }

Und noch eine Anmerkung:
Schau dir deine Kommentare noch einmal an.
Und dann beantworte mal die Frage:
Was erzählt mir eigentlich der Kommentar, was ich Quelltext nicht auch 
so sehe?

    lcd_gotoxy(32,50);      // Auf LCD Position springen

Super. Der Funktionsaufruf heisst lcd_gotoxy. Das dieser Funktionsaufruf 
die Ausgabeposition irgendwo hinstellt, weis ich auch so. Was steht im 
Kommentar? Da steht, dass die Ausgapeposition irgendwo hin gestellt 
wird. Was hat mir also der Kommentar erzählt, was ich nicht auch im Code 
sehe? Gar nichts.

    lcd_writestringP(PSTR(": Y Wert"));  // String dahinter schreiben

Selbiges. Der Funktionsaufruf heißt lcd_writestringP. Selbst wenn ich 
nichts über die Funktion wüsste, was würde ich wohl ohne groß 
nachzudenken annehmen was die Funktion macht? Der Name fängt mit lcd_ 
an, es wird sich also um eine Funktion handeln, die irgendwas mit dem 
LCD macht. Dann kommt writestring. Gut da muss ich eine Weile optisch 
suchen um zu erkennen dass es sich um 2 Wörter handelt. writeString wäre 
leichter zu lesen, aber was solls. write ... also eine Ausgabe. 
...String, also ein String. Die Funktion wird als einen String auf das 
LCD schreiben. Das schiesst mir in 2 Zehntelsekunden durch den Kopf wenn 
ich lcd_writeString lese. Und was erzählt mir der Kommentar "String 
dahinter schreiben". Also genau dasselbe!
Wozu dann der Kommentar?
Das einzige was ich mir eventuell nicht beim Lesen des Funktionsaufrufs 
erklären kann ist das P im Funktionsnamen. Aber das erklärt mir auch der 
Kommentar nicht, was es damit auf sich hat.

Erkläre in einem Kommentar nicht das 'Wie'. Erkläre das 'Warum'! Und 
wenn du der Ansicht bist, dass das 'Warum' aus dem Programmflus an 
dieser Stelle selbsterklärend ist, dann lass den Kommentar weg! Denn 
dann kann er auch nicht falsch sein, wie zb hier
    PORTA |=  (1 << PA2); // PA0 HIGH X1
    PORTA &= ~(1 << PA3); // PA2 LOW  X2

Hier erklärst du wiederrum das 'Wie', aber nicht das 'Warum'. 
Blöderweise ist das 'Wie' auch noch falsch kommentiert.

Autor: Bouni (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,

erst einaml Danke für deine sehr aufschlussreiche Antwort!!

Zum Thema Kommentare:
Aller Anfang ist schwer, ich hab so of schon gelesen "Kommentier 
gefälligst deinen Code" und dachte viel hilft viel.
Aber deine Kritik leuchtet ein und ich gelobe besserung :)

Gruss Elias

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bouni schrieb:

> Zum Thema Kommentare:
> Aller Anfang ist schwer,

Ich weiß.
Sinnvoll kommentieren ist eines der schwersten Dinge.

> ich hab so of schon gelesen "Kommentier
> gefälligst deinen Code"
... und niemand sagt einem was sinnvoll ist :-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.