mikrocontroller.net

Forum: Compiler & IDEs LCD-Routine optimieren (große Zahlen)


Autor: Tobias Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
zur Zeit verwende ich folgende Routine um auf einem 4x27char LCD mit 
benutzerdefinierte Zeichen und Sonderzeichen große Zahlen (über alle 4 
Zeilen) auszugeben.
Die Routine funktioniert einwandfrei, belegt jedoch einen großen Teil 
des Speichers meines Tiny26.

Gibt es irgendeine Möglichkeit die 4 switch-Anweisungen so zu 
optimieren, dass sie weniger Speicher benötigen oder gibt es eurer 
Meinung nach keine Möglichkeit mehr die Routine noch sinnvoll zu 
optimieren ?
void lcd_big(uint8_t zahl, uint8_t spalte)
{
  // Zeile 1
  lcd_gotoxy (spalte,0);
  switch (zahl) 
   {
    case 0: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
    case 1: { lcd_putc(0); lcd_putc(1);  lcd_putc(32);    break; }
    case 2: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
    case 3: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
    case 4: { lcd_putc(1); lcd_putc(32); lcd_putc(32);    break; }
    case 5: { lcd_putc(1); lcd_putc(1);  lcd_putc(1);     break; }
    case 6: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
    case 7: { lcd_putc(1); lcd_putc(1);  lcd_putc(1);     break; }
    case 8: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
    case 9: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
  
    case 11: { lcd_putc(0);  lcd_putc(1);   lcd_putc(2);  break; } // °
    case 12: { lcd_putc(0);  lcd_putc(1);   lcd_putc(2);  break; } // C
    case 13: { lcd_putc(32); lcd_putc(32);  lcd_putc(32); break; } // ,
   }

  // Zeile 2
  lcd_gotoxy (spalte,1);
  switch (zahl) 
   {
    case 0: { lcd_putc(255); lcd_putc(32);  lcd_putc(255);  break; }
    case 1: { lcd_putc(32);  lcd_putc(255); lcd_putc(32);   break; }
    case 2: { lcd_putc(0);   lcd_putc(1);   lcd_putc(3);    break; }
    case 3: { lcd_putc(32);  lcd_putc(0);   lcd_putc(3);    break; }
    case 4: { lcd_putc(255); lcd_putc(1);   lcd_putc(255);  break; }
    case 5: { lcd_putc(255); lcd_putc(1);   lcd_putc(2);    break; }
    case 6: { lcd_putc(255); lcd_putc(1);   lcd_putc(2);    break; }
    case 7: { lcd_putc(32);  lcd_putc(0);   lcd_putc(3);    break; }
    case 8: { lcd_putc(255); lcd_putc(1);   lcd_putc(255);  break; }
    case 9: { lcd_putc(255); lcd_putc(1);   lcd_putc(255);  break; }
  
    case 11: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }  // ° 
    case 12: { lcd_putc(255); lcd_putc(32);  lcd_putc(32);  break; }  // C 
    case 13: { lcd_putc(32);  lcd_putc(32);  lcd_putc(32);  break; }  // , 
   }

  // Zeile 3
  lcd_gotoxy (spalte,2);
  switch (zahl) 
   {
    case 0: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }
    case 1: { lcd_putc(32);  lcd_putc(255); lcd_putc(32);  break; }
    case 2: { lcd_putc(255); lcd_putc(32);  lcd_putc(32);  break; }
    case 3: { lcd_putc(32);  lcd_putc(5);   lcd_putc(4);   break; }
    case 4: { lcd_putc(32);  lcd_putc(32);  lcd_putc(255); break; }
    case 5: { lcd_putc(32);  lcd_putc(32);  lcd_putc(255); break; }
    case 6: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }
    case 7: { lcd_putc(32);  lcd_putc(255); lcd_putc(32);  break; }
    case 8: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }
    case 9: { lcd_putc(32);  lcd_putc(32);  lcd_putc(255); break; }
    
    case 11: { lcd_putc(5);   lcd_putc(6);   lcd_putc(7);  break; }   // ° 
    case 12: { lcd_putc(255); lcd_putc(32);  lcd_putc(32); break; }   // C
    case 13: { lcd_putc(32);  lcd_putc(32);  lcd_putc(32); break; }   // , 
   }

  // Zeile 4
  lcd_gotoxy (spalte,3);
  switch (zahl) 
   {
    case 0: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
    case 1: { lcd_putc(6);  lcd_putc(6);  lcd_putc(6);  break; }
    case 2: { lcd_putc(6);  lcd_putc(6);  lcd_putc(6);  break; }
    case 3: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
    case 4: { lcd_putc(32); lcd_putc(32); lcd_putc(6);  break; }
    case 5: { lcd_putc(6);  lcd_putc(6);  lcd_putc(7);  break; }
    case 6: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
    case 7: { lcd_putc(32); lcd_putc(6);  lcd_putc(32); break; }
    case 8: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
    case 9: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
  
    case 11: { lcd_putc(32);  lcd_putc(32);  lcd_putc(32); break; }  // ° 
    case 12: { lcd_putc(5);   lcd_putc(6);   lcd_putc(7);  break; }  // C
    case 13: { lcd_putc(32);  lcd_putc(6);   lcd_putc(32); break; }  // ,
   }
}

void show_temperature (uint8_t temp)
  {
  uint8_t hunderter=0,zehner=0,einer=0;
  while (temp>100)  {temp-=100; hunderter++;}
  while (temp>9)    {temp-=10;  zehner++;}
  einer=temp;
  
  lcd_big (hunderter,2);
  lcd_big (zehner,6);
  lcd_big (13,9); // ,
  lcd_big (einer,12);
  lcd_big (11,18); // °
  lcd_big (12,22); // C
  }

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Unkommentierte Routinen liebe ich (würdige ich keines Blickes).

Erklär erstmal, was das Ganze soll, dann kann man bestimmt optimieren.


Peter



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

Bewertung
0 lesenswert
nicht lesenswert
Tobias Paul wrote:

> Gibt es irgendeine Möglichkeit die 4 switch-Anweisungen so zu
> optimieren, dass sie weniger Speicher benötigen oder gibt es eurer
> Meinung nach keine Möglichkeit mehr die Routine noch sinnvoll zu
> optimieren ?

Ich sach nur: Tabellen
uint8_t Zeile1[14][3] = {
    { 0,  1,  2 },    // 0
    { 0,  1, 32 },    // 1
    { 0,  1,  2 },    // 2
    { 0,  1,  2 },    // 3
    { 1, 32, 32 },    // 4
    { 1,  1,  1 },    // 5
    ... etc ...
};

uint8_t Zeile2[14][3] = {
    .. dasselbe in Grün für die 2. Zeile
};

uint8_t Zeile3[14][3] = {
    .. und nochmal für die 3. Zeile
};

uint8_t Zeile4[14][3] = {
    .. und nochmal für die 4. Zeile
};

void lcd_big(uint8_t zahl, uint8_t spalte)
{
  // Zeile 1
  lcd_gotoxy (spalte,0);
  lcd_putc( Zeile1[zahl][0] );
  lcd_putc( Zeile1[zahl][1] );
  lcd_putc( Zeile1[zahl][2] );

  // Zeile 2
  lcd_gotoxy (spalte,1);
  lcd_putc( Zeile2[zahl][0] );
  lcd_putc( Zeile2[zahl][1] );
  lcd_putc( Zeile2[zahl][2] );

  // Zeile 3
  lcd_gotoxy (spalte,2);
  lcd_putc( Zeile3[zahl][0] );
  lcd_putc( Zeile3[zahl][1] );
  lcd_putc( Zeile3[zahl][2] );
 
  // Zeile 4
  lcd_gotoxy (spalte,3);
  lcd_putc( Zeile4[zahl][0] );
  lcd_putc( Zeile4[zahl][1] );
  lcd_putc( Zeile4[zahl][2] );
}

Die nächste Optimierungsstufe würde darin bestehen, die Tabellen
im Flash zu belassen.

Ein paar Bytes können immer noch eingespart werden, indem
man den eigentlichen Ausgabeteil, der ja 4 mal identisch nur
mit anderen Zahlenwerten auftritt, in eine eigene Funktion
auslagert
void lcd_Zeile(uint8_t zahl, uint8_t reihe, uint8_t spalte, uint8_t Codes[14][3] )
{
  lcd_gotoxy (spalte,reihe);
  lcd_putc( Codes[zahl][0] );
  lcd_putc( Codes[zahl][1] );
  lcd_putc( Codes[zahl][2] );
}

void lcd_big(uint8_t zahl, uint8_t spalte)
{
  lcd_Zeile( zahl, 0, spalte, Zeile1 );
  lcd_Zeile( zahl, 1, spalte, Zeile2 );
  lcd_Zeile( zahl, 2, spalte, Zeile3 );
  lcd_Zeile( zahl, 3, spalte, Zeile4 );
}

Neben der verringerten Codegröße ist auch die gesteigerte
Übersichtlichkeit nicht zu verachten.

Autor: Tobias Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt hab ich zwar mehr Programmspeicher frei.
Die Arrays belegen jetzt allerdings zu viel RAM.

vorher:
AVR Memory Usage:
-----------------
Device: attiny26

Program:    1902 bytes (92.9% Full)
(.text + .data + .bootloader)

Data:          1 bytes (0.8% Full)
(.data + .bss + .noinit)

nachher:
AVR Memory Usage:
-----------------
Device: attiny26

Program:    1474 bytes (72.0% Full)
(.text + .data + .bootloader)

Data:        157 bytes (122.7% Full)
(.data + .bss + .noinit)


Wollte dann das Array mit PROGMEM in den Flash-Speicher verschieben, wie 
hier im Forum beschrieben, allerdings meckert dann mein Compiler:

Compiling: user_io.c
avr-gcc -c -mmcu=attiny26 -I. -gdwarf-2 -DF_CPU=8000000UL  -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall 
-Wstrict-prototypes -Wa,-adhlns=user_io.lst  -std=gnu99 -MD -MP -MF 
.dep/user_io.o.d user_io.c -o user_io.o
user_io.c: In function 'lcd_big':
user_io.c:55: warning: '__progmem__' attribute ignored
user_io.c:70: warning: '__progmem__' attribute ignored
user_io.c:85: warning: '__progmem__' attribute ignored
user_io.c:100: warning: '__progmem__' attribute ignored
void lcd_big(uint8_t zahl, uint8_t spalte)
{

uint8_t zeile1 [13] [3] PROGMEM = {
{ 0,   1,   2  },
{ 0,   1,  32  },
{ 0,   1,   2  },
{ 0,   1,   2  },
{ 1,  32,  32  },
{ 1,   1,   1  },
{ 0,   1,   2  },
{ 1,   1,   1  },
{ 0,   1,   2  },
{ 0,   1,   2  },
{ 0,   1,   2  },   // ° - Zeichen
{ 0,   1,   2  },   // C
{ 32, 32,  32  } }; // , - Zeichen

uint8_t zeile2 [13] [3] PROGMEM = {
{ 255,  32,  255 },
{ 32,  255,   32 },
{ 0,     1,    3 },
{ 32,    0,    3 },
{ 255,   1,  255 },
{ 255,   1,    2 },
{ 255,   1,    2 },
{ 32,    0,    3 },
{ 255,   1,  255 },
{ 255,   1,  255 },
{ 255,  32,  255 },   // ° - Zeichen
{ 255,  32,   32 },   // C
{ 32,   32,   32 } }; // , - Zeichen

uint8_t zeile3 [13] [3] PROGMEM = {
{ 255,  32,  255 },
{ 32,  255,   32 },
{ 255,  32,   32 },
{ 32,    5,    4 },
{ 32,   32,  255 },
{ 32,   32,  255 },
{ 255,  32,  255 },
{ 32,  255,   32 },
{ 255,  32,  255 },
{ 32,   32,  255 },
{ 5,     6,    7 },   // ° - Zeichen
{ 255,  32,   32 },   // C
{ 32,   32,   32 } }; // , - Zeichen

uint8_t zeile4 [13] [3] PROGMEM = {
{ 5,   6,   7   },
{ 6,   6,   6   },
{ 6,   6,   6   },
{ 5,   6,   7   },
{ 32, 32,   6   },
{ 6,   6,   7   },
{ 5,   6,   7   },
{ 32,  6,  32   },
{ 5,   6,   7   },
{ 5,   6,   7   },
{ 32, 32,  32   },   // ° - Zeichen
{ 5,   6,   7   },   // C
{ 32,  6,  32   } }; // , - Zeichen

 
 // Zeile 1
  lcd_gotoxy (spalte,0);
  lcd_putc( pgm_read_byte(&( zeile1[zahl][0] )) );
  lcd_putc( pgm_read_byte(&( zeile1[zahl][1] )) );
  lcd_putc( pgm_read_byte(&( zeile1[zahl][2] )) );

  // Zeile 2
  lcd_gotoxy (spalte,1);
  lcd_putc( pgm_read_byte(&( zeile2[zahl][0] )) );
  lcd_putc( pgm_read_byte(&( zeile2[zahl][1] )) );
  lcd_putc( pgm_read_byte(&( zeile2[zahl][2] )) );

  // Zeile 3
  lcd_gotoxy (spalte,2);
  lcd_putc( pgm_read_byte(&( zeile3[zahl][0] )) );
  lcd_putc( pgm_read_byte(&( zeile3[zahl][1] )) );
  lcd_putc( pgm_read_byte(&( zeile3[zahl][2] )) );
 
  // Zeile 4
  lcd_gotoxy (spalte,3);
  lcd_putc( pgm_read_byte(&( zeile4[zahl][0] )) );
  lcd_putc( pgm_read_byte(&( zeile4[zahl][1] )) );
  lcd_putc( pgm_read_byte(&( zeile4[zahl][2] )) );
  
}


void show_temperature (uint8_t temp)
  {
  uint8_t hunderter=0,zehner=0,einer=0;
  while (temp>100)  {temp-=100; hunderter++;}
  while (temp>9)    {temp-=10;  zehner++;}
  einer=temp;
  
  lcd_big (hunderter,2);
  lcd_big (zehner,6);
  lcd_big (13,9); // ,
  lcd_big (einer,12);
  lcd_big (11,18); // °
  lcd_big (12,22); // C
  
  }


@ Peter Dannegger:
Das ganze dient dazu auf einem normalen Text LCD (HD44780) übergroße 
Zahlen, die über 4 Zeilen gehen anzuzeigen.
Die Ziffern selbst bestehen dabei aus Sonderzeichen und 
benutzerdefinierten Zeichen.

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

Bewertung
0 lesenswert
nicht lesenswert
Tobias Paul wrote:

> Wollte dann das Array mit PROGMEM in den Flash-Speicher verschieben,
> wie hier im Forum beschrieben, allerdings meckert dann mein Compiler:

Wenn du mal genau mein Beispiel anschaust, dann wirst
du feststellen, dass ich die Arrays global angelegt habe
und nicht in die Funktion hinein gezogen habe.

Autor: Tobias Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt sieht mein Speicherverbrauch schon wesendlich besser aus,

Program:    1444 bytes (70.5% Full)
(.text + .data + .bootloader)

Data:          1 bytes (0.8% Full)
(.data + .bss + .noinit)

ABER jetzt habe ich allerdings Probleme mit der Darstellung der 
einzelnen
Zeichen. Obwohl ich in der Funktion show_temperature();, die die 
Formatierung und Ausrichtung auf dem Display bestimmt, nicht verändert 
hab, sind die Zeichen plötzlich leicht verschoben.
Anstatt 22.5°C steht jetzt 22$5 C. da.
(Wobei das $ für ein misratenes Zeichen stehen soll.)

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

Bewertung
0 lesenswert
nicht lesenswert
Du musst in den Tabellen einen Dummy Eintrag
für den Index 10 machen!
In deinem switch-case hast du den Fall zahl==10
ausgelassen.
In der Tabelle muss er aber vorhanden sein!

Genau aus dem Grund waren meine ursprünglichen
Tabellen auch 14 Einträge gross, weil du Code Zahlen
0 bis 13 verwendest und das sind nun mal 14 Stück.

Autor: Tobias Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohh mein Fehler. Ich vergas was wichtiges.

vorher hatte ich 11,12,13 für die ° , C , . -Zeichen
jetzt durch das Array hab ich 10,11,12.

Jetzt gehts wieder, danke für die Hilfe.

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo  Tobias,

wenn man sich deine Tabellen so anschaut, gibt es da nur
19 verschiedene Eintraege ( statt jetzt 52):
  0   1   2
  0   1   3
  0   1  32
  1   1   1
  1  32  32
  5   6   7
  6   6   6
  6   6   7
 32   0   3
 32   5   4
 32   6  32
 32  32   6
 32  32  32
 32  32 255
 32 255  32
255   1   2
255   1 255
255  32  32
255  32 255

da liesse sich dann auch noch etwas einsparen:

--> 1 Tabelle mit 19x3 und 52 Zeiger auf den jeweiligen Index.

gruss
       horst.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Horst (Gast)

>wenn man sich deine Tabellen so anschaut, gibt es da nur
>19 verschiedene Eintraege ( statt jetzt 52):

>da liesse sich dann auch noch etwas einsparen:

>--> 1 Tabelle mit 19x3 und 52 Zeiger auf den jeweiligen Index.

52 Zeiger brauchen weniger Platz?

MFG
Falk

Autor: Horst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk

ich meinte natuerlich 52 (unsigned char) Indexeintraege,
die in die Tabelle mit 19x3 Bytes weisen.

horst.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle 4 Tabellen können in einer zusammengefasst werden, das vereinfacht 
die Routinen von Karl Heinz
uint8_t Font[13] [3*4] PROGMEM = {
{ 0, 1, 2,     255, 32, 255,   255, 32, 255,   5, 6, 7},
... usw.

void lcd_big(uint8_t zahl, uint8_t spalte)
{
  uint8_t* font = &Font[zahl];
  for (uint8_t i = 0; i < 4; i++) {
    lcd_gotoxy (spalte, i);
    for (uint8_t j = 0; j < 3; j++) 
      lcd_putc(pgm_read_byte(font++));
  } 
}

Font[] besteht nacheinander aus den Werten von Zeile1[] bis Zeile[4]

Gruß Hagen

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.