Forum: Mikrocontroller und Digitale Elektronik lcd_write Fehlersuche


von grundschüler (Gast)


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)


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)


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)


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)


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)


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)


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)


Lesenswert?

Du könntest ja mal das ganze Programm zeigen..

von Nop (Gast)


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


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)


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)


Lesenswert?

grundschüler schrieb:
> while(*str>31)

und was soll das bitte abfangen?

von grundschüler (Gast)


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


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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.

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.