Forum: Mikrocontroller und Digitale Elektronik C++ Simple Funktion um Änderungen auf Display zu schreiben, geht nicht?


von Matthias (Gast)


Lesenswert?

Hallo zusammen,

ich habe ein 2x16-Display und möchte nur die Änderungen neu aufs Display 
schreiben. Statt es immer komplett neu zu beschreiben.
Dies scheint aber nicht so wie erwartet möglich zu sein, ich vermute 
stark dass es mit der Übergabe der char-Arrays zu tun hat. Kann aber 
kein Problem sehen. Eventuell habt ihr eine Idee?
1
int main(void)
2
{
3
  char line0[16];
4
  char line1[16];
5
  InitUC();      //Init Ports(I/O), Sei()
6
  LCD_init();      //Init LCD
7
  strcpy(line0,"uc / LCD-INIT   ");
8
  strcpy(line1,"INA219/ADC-INIT ");
9
  while (1)
10
  {
11
    write_changes_2_disp(0,&line0[0]);
12
    write_changes_2_disp(1,&line1[0]);
13
    _delay_ms(1000);    
14
  }
15
}
Es sollen also die beiden Strings line0 und line1 immer wieder aufs 
display geschrieben werden, allerdings nur deren Änderungen, nicht immer 
die kompletten Strings.
Dann habe ich die Ändrungs-Erkenn-Funktion:
1
void write_changes_2_disp(uint8_t line_sel, char *line)
2
{
3
  static char line0_old[16];
4
  static char line1_old[16];
5
  if (line_sel == 0)
6
  {
7
    //Write data to line 0
8
    for(uint8_t i = 0; i < 16 ; i++)
9
    {
10
      if (line0_old[i] /= line[i])
11
      {  //Write changes
12
        line0_old[i] = line[i];
13
        LCD_WriteString(&line0_old[i],0,i,1);
14
      }
15
    }
16
  }
17
  else
18
  {
19
    //Write data to line 1
20
    for(uint8_t i = 0; i < 16 ; i++)
21
    {
22
      if (line1_old[i] /= line[i])
23
      {  //Write changes
24
        line1_old[i] = line[i];
25
        LCD_WriteString(&line1_old[i],1,i,1);
26
      }
27
    }
28
  }
29
  return;
30
}
Diese Funktion bekommt also einen zeiger auf das Element 0, der zu 
schreibenden zeile, die Zeile selbst besteht immer aus 16Zeichen.
Insofern sollte mit einem vergleich "line1_old[i] /= line[i]" der Inhalt 
der übergebenen mit dem Static-Inhalt der ehemaligen Zeile verglichen 
werden und bei einem Unterschied der neue Inhalt an dieser Stelle auf 
das LCD geschrieben werden. Ich vermute dass hier ein fataler Irrtum 
vorliegt, kann ihn selbst aber nicht sehen...
Aufgerufen wird dann die Funkion:
1
void LCD_WriteString(char *str, uint8_t line ,uint8_t base_addr, uint8_t len)
2
{  //Function does work for 4-Line-Displays
3
  uint8_t i=0;
4
  if (line == 1)
5
  {
6
    i=0x40;
7
  }
8
  else if (line == 2)
9
  {
10
    i=0x14;
11
  }
12
  else if (line == 3)
13
  {
14
    i=0x54;
15
  }
16
  len=len+i;
17
  for(uint8_t y = 0; i < len;i++, y++)
18
  {
19
    LCD_Send_ADDR(i+base_addr);
20
    LCD_Send(str[y]);
21
  }
22
}
Welche bisher immer den kompletten text einer Zeile neu geschrieben hat. 
Jedoch wird nun niemals mehr etwas geschrieben.

Vielleicht hat jemand von euch eine Idee, wo mein Denkfehler liegt?
Grüße und vielen Dank,
Matthias

: Verschoben durch Moderator
von foobar (Gast)


Lesenswert?

> vergleich "line1_old[i] /= line[i]"

Du meinst wohl "!=", "/=" ist eine Division.

von N. M. (mani)


Lesenswert?

Was passiert mit deiner String Terminierung wenn du dein Char Array bis 
oben hin mit Zeichen ungleich 0 voll schreibst?

von Matthias (Gast)


Lesenswert?

foobar schrieb:
>> vergleich "line1_old[i] /= line[i]"
>
> Du meinst wohl "!=", "/=" ist eine Division.

Danke ;)
Ich mach auch viel VHDL... da ist es das Ungleich!

von Matthias (Gast)


Lesenswert?

N. M. schrieb:
> Was passiert mit deiner String Terminierung wenn du dein Char
> Array bis
> oben hin mit Zeichen ungleich 0 voll schreibst?

Ist ja kein String, und ich gehe davon aus dass es maximal 16Zeichen 
sind.
Wo siehst du ein Problem?

-->Nun geht es auch, ist Pfeilschnell und sieht gut aus!
-->Danke euch :)

von beo bachta (Gast)


Lesenswert?

Matthias schrieb:
> -->Nun geht es auch, ist Pfeilschnell und sieht gut aus!

Naja, Character LCD und pfeilschnell, da kann man unter-
schiedlicher Meinung sein. Für's Auge ist es auf jeden Fall
schnell genug ....

von N. M. (mani)


Lesenswert?

Matthias schrieb:
> Wo siehst du ein Problem?

Dein String "INA219/ADC-INIT " hat 16 Nutz-Zeichen. Die Funktion strcpy 
wird folgendermaßen beschrieben:
1
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).

Sprich, es werden 17 Zeichen in ein Array kopiert wo nur 16 Zeichen 
reserviert wurden.
Du machst also einen Out of Bound Zugriff und überschreibst anderen 
Speicher.

Deshalb auch der folgende Satz in der Doku von strcpy:
1
To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.

von Joachim B. (jar)


Lesenswert?

Matthias schrieb:
> 2x16-Display
Matthias schrieb:
> static char line0_old[16];
>   static char line1_old[16];

[17]
mit 0 Terminator 17 Byte wenn du str Funktionen nutzen willst!

Matthias schrieb:
> for(uint8_t i = 0; i < 16 ; i++)
>     {
>       if (line0_old[i] /= line[i])
>       {  //Write changes
>         line0_old[i] = line[i];
>         LCD_WriteString(&line0_old[i],0,i,1);
>       }
>     }

gedacht hattest du nur die Zeichen zu tauschen die sich ändern, ich 
bezweifel ob sich das lohnt.

statt Zeichen einzeln zu kopieren kannst du gleich memcpy für 16 Zeichen 
nutzen. Du leitest auch für JEDE Zeichenänderung einen LCD 
Schreibvorgang ein anstatt alle Zeichen einmal zu schreiben!

PS.
memcpy(&menu[akt_screen][COHE_LINE-1][0], s_out_str, 14); // Nokia5110 
hat 14 Zeichen/Zeile

: Bearbeitet durch User
von N. M. (mani)


Lesenswert?

N. M. schrieb:
> Dein String "INA219/ADC-INIT " hat 16 Nutz-Zeichen.

Der andere String ist auch zu lang.

von Joachim B. (jar)


Lesenswert?

statt so zu vergleichen

Matthias schrieb:
> if (line1_old[i] /= line[i])

nutze memcmp! und vergleiche die ganze Zeile!

von W.S. (Gast)


Lesenswert?

Matthias schrieb:
> ich habe ein 2x16-Display und möchte nur die Änderungen neu aufs Display
> schreiben. Statt es immer komplett neu zu beschreiben.

Überlege doch mal den Aufwand. Entweder mußt du 2x16 Bytes im RAM 
vorhalten mußt, um dein Display immer komplett neu zu beschreiben, oder 
du mußt 2x16 Bytes vorhalten, um sie ggf. zu schreiben und dazu nochmal 
2x16 Bytes zum Vergleichen. Dazu noch die ganze Vergleichsroutine, 
Schreibstelle setzen usw.

Wozu also ein derartiger Aufwand für 2x16 Zeichen? Gibt es da 
irgendwelche Gründe, die du nur nicht genannt hast?

W.S.

von Joachim B. (jar)


Lesenswert?

W.S. schrieb:
> Dazu noch die ganze Vergleichsroutine,
> Schreibstelle setzen usw.

bei LCD ist jedes Ansprechen erst mal im µs Bereich soweit ich mich 
erinnere, was spart also 16x µs LCD Routine gegenüber 16 Byte im RAM zu 
vergleichen ns die mindestens 100x schneller ist.

: Bearbeitet durch User
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.