Forum: Mikrocontroller und Digitale Elektronik lcd_write Fehlersuche


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
ich habe ein programm das alle 20sec Daten von einem controller auf 
einen anderen überträgt. Auf einem tft werden Text und Zahlenwerte 
angezeigt. Nach etwa einem Tag fällt die Übertragung des Textes aus - 
Zahlenwerte werden weiter angezeigt obwol Zahlen und text die gleiche 
Funktion benutzen. lcd_write("123test456"); wird nicht mehr angezeigt. 
Woran kann das liegen?

Das sind die Funktionen:
1
//==================================================
2
void lcd_write(uint8_t* str)
3
{
4
  uint8_t TempChar;
5
    do
6
    {
7
        TempChar = *str++;
8
        if(TempChar<' '||TempChar>130)return;
9
10
        lcd_char(TempChar);
11
12
           curposx =curposx+ f_width;
13
       if(frame)curposx++;
14
    }
15
    while ( *str != 0 );
16
}
17
18
//=============================================
19
void lcd_int3(uint16_t int1){
20
  uint8_t dum[4]={' ',' ',48,'\0'};
21
  u8 s1=0;
22
23
    if (int1>99){
24
        dum[0]=(int1/100+48);
25
    s1=1;
26
    }
27
        int1=int1%100;
28
29
    if (int1>9 || s1){
30
        dum[1]=(int1/10+48);
31
    }
32
        int1=int1%10;
33
        
34
        dum[2]=int1+48; 
35
   
36
        
37
     lcd_write(dum);
38
}
39
//==================================================

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:

> void lcd_write(uint8_t* str)
> {
>   uint8_t TempChar;
>     do
>     {
>         TempChar = *str++;
>         if(TempChar<' '||TempChar>130)return;
>
>         lcd_char(TempChar);
>
>            curposx =curposx+ f_width;
>        if(frame)curposx++;
>     }
>     while ( *str != 0 );
> }

Was passiert, wenn diese Funktion jemals einen Leerstring übergeben 
bekommt?

von Thomas (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Direkt in dem Code sehe ich keinen Fehler (abgesehen von den 
überflüssigen Zeilen mit curposx). Hast du irgendwo einen Überlauf, der 
sich erst nach einem Tag beobachtbar macht? Oder läuft der Speicher 
voll? Sind die Texte auch immer mit '\0' abgeschlossen?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Thomas schrieb:
> Sind die Texte auch immer mit '\0' abgeschlossen?

Nein, das ist der einzige Unterschied zu Ziffernfolgen:

lcd_write("123test456");
./.
 uint8_t dum[4]={' ',' ',48,'\0'};
lcd_write(dum);

Aber durch '\' wird doch nur das Ende des strings angezeigt. Nach dem 
letzten Zeichen ist der string doch ohnehin zu Ende?




> Was passiert, wenn diese Funktion jemals einen Leerstring übergeben
> bekommt?

Weiß ich nicht, passiert eigentlich nicht.

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:

> lcd_write("123test456");

Bei einem solchen String-Literal ist die Null am Ende automatisch mit 
drin.

> Nach dem letzten Zeichen ist der string doch ohnehin zu Ende?

Nein. In C sind Strings zuende, wenn eine Null kommt. Wenn keine Null 
kommt, liest die Routine solange zufällig im Speicher weiter, bis eine 
kommt. Der Cursor wird dann natürlich sonstwohin gestellt.

> > Was passiert, wenn diese Funktion jemals einen Leerstring übergeben
> > bekommt?
> Weiß ich nicht

Dann geh der Frage mal nach. Ein bißchen Knobelei muß für Dich ja auch 
noch übrig bleiben. :-)

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Bei einem solchen String-Literal ist die Null am Ende automatisch mit
> drin.

Das ist natürlich richtig, wusste ich früher auch mal.

Ich such ja erstmal eine Erklärung.

die lcd_write - Funktion müsste grundsätzlich in Ordnung sein.


"123test456" wird zur Laufzeit irgendwo in den RAM geschrieben. kann es 
sein dass sich der Ram dadurch verbraucht und irgendwann kein Platz für 
weiteren Text vorhanden ist?


Macht es Sinn, für solchen Text festen Speicher - u8 dum[] - anzulegen?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
habe jetzt auf
1
u8 tst[]="wzb vl  rl  t0  t1  thm  elt  az ";
2
    lcd_goto(25,1);lcd_write(tst);
geändert.

Der im Ram abgelegte String wird korrekt geschrieben.

Es ist also kein Problem mit der Funktion lcd_write, sondern ein 
Speicherüberlaufproblem. Durch das ständige Schreiben von Text aus dem 
Programmcode entsteht ein Speicherüberlauf. Ist das normal oder ein 
Fehler in meinem Programm???????

von Pete K. (pete77)


Bewertung
0 lesenswert
nicht lesenswert
Du könntest ja mal das ganze Programm zeigen..

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:

> Ist das normal oder ein Fehler in meinem Programm???????

Wenn auch nur ein einziges mal irgendwo durch Umkopieren oder so ein 
Leerstring übergeben wird, knallt es sowieso, weil lcd_write das nicht 
abfängt.

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> do
>     {
>         ....
>     }
>     while ( *str != 0 );

Das Problem mit dem Leerstring lässt sich leicht lösen, indem man 
stattdessen schreibt:
1
  while ( *str != '\0' )
2
  {
3
    ....
4
  }

Man sollte beim "Durchwandern" eines C-Strings immer eine while- und 
keine do-while-Schleife nehmen.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> immer eine while- und
> keine do-while-Schleife nehmen.

Danke für den Hinweis. Habe jetzt stark vereinfacht:
1
void lcd_write(uint8_t* str)
2
{
3
  while(*str>31)
4
    {
5
        lcd_char(*str++);
6
        curposx =curposx+ f_width;
7
    if(frame)curposx++;
8
    }
9
}

Bin gespannt, ob der Fehler jetzt weg ist.

von ui (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> while(*str>31)

und was soll das bitte abfangen?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
ui schrieb:
> grundschüler schrieb:
>> while(*str>31)
>
> und was soll das bitte abfangen?

lcd_char holt Daten aus einem font. Der Font fängt mit ' '=32 an. Unter 
32 findet lcd_char im font nichts.

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> Unter 32 findet lcd_char im font nichts.

Trotzdem würde ich da nicht abbrechen. Daher:
1
void lcd_write (uint8_t * str)
2
{
3
    while (*str)
4
    {
5
        if (*str >= ' ') // printable character?
6
        {
7
            lcd_char (*str);
8
            curposx = curposx + f_width;
9
10
            if (frame)
11
            {
12
                curposx++;
13
            }
14
        }
15
        str++;           // next character
16
    }
17
}

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn im String ein Zeichen <' ' ist, ist irgendwas schief gelaufen. Dann 
ist der Abbruch gewollt. Kann aber eigentlich nicht passieren.

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> Wenn im String ein Zeichen <' ' ist, ist irgendwas schief gelaufen. Dann
> ist der Abbruch gewollt. Kann aber eigentlich nicht passieren.

Wieso?
Hast du dir mal das Character-Set eines HD44780 angeschaut?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn es mit dem Speicherplatz knapp wird kannst du aus den Fonts jede 
Menge Code herauslöschen der ohnehin nicht gebraucht wird.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Bin - trotz geänderter lcd_write() - immer noch auf der Fehlersuche:
1
void test(u8 *str){
2
u8 tmp[]="xxx ";
3
u8 i;
4
5
for(i=0;i<3;i++){
6
  tmp[i]=*str++;
7
}
8
9
lcd_write(tmp);
10
}
11
12
.....
13
14
    lg(21,20);test("vl ");
15
    lcd_int4(owx_rx_buffer[17]);
16
    
17
    lg(22,20);lw("elt ");
18
    lcd_int4(kw_elt);
19
    
20
    lg(23,20);lw(thm);//u8 thm[]="thm ";
21
    lcd_int4(kw_therm);


nach ca. 2h wird nur noch die Variante thm angezeigt. Ich kann den code 
jetzt entsprechend ändern, würde aber gerne wissen, was falsch läuft.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> nach ca. 2h wird nur noch die Variante thm angezeigt.

Du hast ein Speicherproblem, z.B. einen wildgewordenen Pointer, der Dir 
Teile des SRAM überschreibt.
Das Umstellen des Codes ändert nur die Stelle, wo Du den Fehler 
bemerkst.

Den Code, der den Fehler enthält, hast Du bisher nicht gezeigt.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> wildgewordenen Pointer

das muss es sein. Kann eigentlich nur die onewire-empfangsroutine sein:
1
in der main:
2
...
3
while(1){
4
//================= owx polling ======================
5
6
if(owx_signal){//
7
led1_on;
8
//sub_owx_slave_polling();
9
u8 ret=  owx_empfangen(owx_rx_buffer);
10
...
11
12
13
volatile uint8_t owx_rx_buffer[30]={0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};
14
//-------------------------------------------
15
uint8_t  owx_rx_byte(void){
16
uint8_t dat=0,i=0,abfr;
17
//u32 timeout;
18
  for(i=0;i<8;i++){
19
    dat=dat<<1;
20
    dly_med;
21
      if(owx_signal)
22
        abfr=0;
23
        else
24
        abfr=1;
25
    dly_short;
26
      if(owx_signal){
27
        if(abfr)dat++;
28
        while(owx_signal);
29
      }
30
      /*
31
      else{
32
      //???? error
33
      return;
34
      }
35
      */  
36
  }
37
return(dat);
38
}
39
40
41
42
43
//-------------------------------------------
44
uint8_t owx_empfangen(  
45
  uint8_t *buff    /* Pointer to data buffer */
46
){
47
uint8_t len,adr=0;
48
uint8_t  crc=0;
49
while(owx_signal);//Anfangssynchronisierung durch Master
50
dly_short;
51
 //adr
52
  *buff = owx_rx_byte();
53
  adr=*buff;
54
  crc=crc+1+*buff;
55
  *buff++;
56
  
57
//len
58
  *buff = owx_rx_byte();
59
  len=*buff-2;
60
  crc=crc+1+*buff;
61
  *buff++;
62
63
//4xheader + payload
64
do{
65
  *buff = owx_rx_byte();
66
  crc=crc+1+*buff;
67
  *buff++;
68
  } while (--len);
69
70
//crc
71
  *buff = owx_rx_byte();
72
  
73
 return crc;

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Sicher, daß Du *buff++ meinst und nicht (*buff)++?

*buff++ liefert das zurück, worauf buff zeigt (was dann aber nicht 
verwendet wird) und erhöht dann den Zeiger buff.

Außerdem ist die Schleife bei 4xheader + payload schon wieder 
fußgesteuert und wird nicht klappen, wenn die empfangene Länge 0 ist.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Sicher, daß Du *buff++ meinst und nicht (*buff)++?

Das werd ich in Ruhe prüfen. Allerdings werden die Daten ja korrekt 
übertragen. Da ist es unwahrscheinlich, dass der Fehler in der 
Berechnungsroutine steckt. Eher pointer - aber ich finde keinen 
undefinierten.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Wenn Du len = 2 empfängst, muß buff mindestens 258 Byte groß sein, ist 
das der Fall?
Wenn nicht, dann mußt Du len abtesten, damit buff nicht überläuft.

: Bearbeitet durch User
von Stefan E. (sternst)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Sicher, daß Du *buff++ meinst und nicht (*buff)++?

Nein, er meint eigentlich nur buff++.

grundschüler schrieb:
> Kann eigentlich nur die onewire-empfangsroutine sein:

In die Funktion würde ich auf jeden Fall mal einen Überlaufschutz 
einbauen. In ihrer jetzigen Form ist die in den Puffer geschriebene 
Menge von äußeren Einflüssen abhängig. Was ist z.B. wenn das Paket 
defekt ist und die Längeninfo im Paket daher zu groß ist?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> len = 2

Das könnte der Fehler sein. len ist das 2.Feld und gibt die Anzahl der 
zu übertragenden bytes an. len-2 weil 2 bytes schon gelesen sind. Wenn 
da durch Übertragungsfehler ein Überlauf und damit ein Wert größer als 
der buffer steht, kann es zu Fehlern kommen. Ich werde da einen Abbruch 
einbauen für den Fall, dass len größer als der buffer wird.

Wer denkt denn an so was...

von Dieter F. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
grundschüler schrieb:
> Wer denkt denn an so was...

Rate mal mit Rosenthal :-)

Die Salami-Taktik beim Code-Zeigen hat sich wieder mal bewährt ...

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Stefan E. schrieb:
> einen Überlaufschutz einbauen

über 24h ohne Fehler, das wars dann wohl. Alleine hätte ich das nicht 
gefunden. Danke für alle Beiträge.

von Dieter F. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
grundschüler schrieb:
> Danke für alle Beiträge.

Dieter F. schrieb:
> Die Salami-Taktik beim Code-Zeigen hat sich wieder mal bewährt ...

Gerne :-)

von grundschüler (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Dieter F. schrieb:
> Die Salami-Taktik beim Code-Zeigen

naja, ohne Eingrenzug des Problems wärs bei umfangreichem Code 
wahrscheinlich auch nicht gegangen.

von Dieter F. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> naja, ohne Eingrenzug des Problems wärs bei umfangreichem Code
> wahrscheinlich auch nicht gegangen.

Eingrenzung ja - auf lauffähigen Minimal-Code, der den Fehler beinhaltet 
und nicht auf irgendwelche Fragmente - aber nur irgendwelche Teile 
zeigen ist nicht nett.

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]
  • [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.