LCD-Routine optimieren (große Zahlen)

Gast #594000
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 ?
1
void lcd_big(uint8_t zahl, uint8_t spalte)
2
{
3
  // Zeile 1
4
  lcd_gotoxy (spalte,0);
5
  switch (zahl) 
6
   {
7
    case 0: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
8
    case 1: { lcd_putc(0); lcd_putc(1);  lcd_putc(32);    break; }
9
    case 2: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
10
    case 3: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
11
    case 4: { lcd_putc(1); lcd_putc(32); lcd_putc(32);    break; }
12
    case 5: { lcd_putc(1); lcd_putc(1);  lcd_putc(1);     break; }
13
    case 6: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
14
    case 7: { lcd_putc(1); lcd_putc(1);  lcd_putc(1);     break; }
15
    case 8: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
16
    case 9: { lcd_putc(0); lcd_putc(1);  lcd_putc(2);     break; }
17
  
18
    case 11: { lcd_putc(0);  lcd_putc(1);   lcd_putc(2);  break; } // °
19
    case 12: { lcd_putc(0);  lcd_putc(1);   lcd_putc(2);  break; } // C
20
    case 13: { lcd_putc(32); lcd_putc(32);  lcd_putc(32); break; } // ,
21
   }
22

23
  // Zeile 2
24
  lcd_gotoxy (spalte,1);
25
  switch (zahl) 
26
   {
27
    case 0: { lcd_putc(255); lcd_putc(32);  lcd_putc(255);  break; }
28
    case 1: { lcd_putc(32);  lcd_putc(255); lcd_putc(32);   break; }
29
    case 2: { lcd_putc(0);   lcd_putc(1);   lcd_putc(3);    break; }
30
    case 3: { lcd_putc(32);  lcd_putc(0);   lcd_putc(3);    break; }
31
    case 4: { lcd_putc(255); lcd_putc(1);   lcd_putc(255);  break; }
32
    case 5: { lcd_putc(255); lcd_putc(1);   lcd_putc(2);    break; }
33
    case 6: { lcd_putc(255); lcd_putc(1);   lcd_putc(2);    break; }
34
    case 7: { lcd_putc(32);  lcd_putc(0);   lcd_putc(3);    break; }
35
    case 8: { lcd_putc(255); lcd_putc(1);   lcd_putc(255);  break; }
36
    case 9: { lcd_putc(255); lcd_putc(1);   lcd_putc(255);  break; }
37
  
38
    case 11: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }  // ° 
39
    case 12: { lcd_putc(255); lcd_putc(32);  lcd_putc(32);  break; }  // C 
40
    case 13: { lcd_putc(32);  lcd_putc(32);  lcd_putc(32);  break; }  // , 
41
   }
42

43
  // Zeile 3
44
  lcd_gotoxy (spalte,2);
45
  switch (zahl) 
46
   {
47
    case 0: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }
48
    case 1: { lcd_putc(32);  lcd_putc(255); lcd_putc(32);  break; }
49
    case 2: { lcd_putc(255); lcd_putc(32);  lcd_putc(32);  break; }
50
    case 3: { lcd_putc(32);  lcd_putc(5);   lcd_putc(4);   break; }
51
    case 4: { lcd_putc(32);  lcd_putc(32);  lcd_putc(255); break; }
52
    case 5: { lcd_putc(32);  lcd_putc(32);  lcd_putc(255); break; }
53
    case 6: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }
54
    case 7: { lcd_putc(32);  lcd_putc(255); lcd_putc(32);  break; }
55
    case 8: { lcd_putc(255); lcd_putc(32);  lcd_putc(255); break; }
56
    case 9: { lcd_putc(32);  lcd_putc(32);  lcd_putc(255); break; }
57
    
58
    case 11: { lcd_putc(5);   lcd_putc(6);   lcd_putc(7);  break; }   // ° 
59
    case 12: { lcd_putc(255); lcd_putc(32);  lcd_putc(32); break; }   // C
60
    case 13: { lcd_putc(32);  lcd_putc(32);  lcd_putc(32); break; }   // , 
61
   }
62

63
  // Zeile 4
64
  lcd_gotoxy (spalte,3);
65
  switch (zahl) 
66
   {
67
    case 0: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
68
    case 1: { lcd_putc(6);  lcd_putc(6);  lcd_putc(6);  break; }
69
    case 2: { lcd_putc(6);  lcd_putc(6);  lcd_putc(6);  break; }
70
    case 3: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
71
    case 4: { lcd_putc(32); lcd_putc(32); lcd_putc(6);  break; }
72
    case 5: { lcd_putc(6);  lcd_putc(6);  lcd_putc(7);  break; }
73
    case 6: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
74
    case 7: { lcd_putc(32); lcd_putc(6);  lcd_putc(32); break; }
75
    case 8: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
76
    case 9: { lcd_putc(5);  lcd_putc(6);  lcd_putc(7);  break; }
77
  
78
    case 11: { lcd_putc(32);  lcd_putc(32);  lcd_putc(32); break; }  // ° 
79
    case 12: { lcd_putc(5);   lcd_putc(6);   lcd_putc(7);  break; }  // C
80
    case 13: { lcd_putc(32);  lcd_putc(6);   lcd_putc(32); break; }  // ,
81
   }
82
}
83

84
void show_temperature (uint8_t temp)
85
  {
86
  uint8_t hunderter=0,zehner=0,einer=0;
87
  while (temp>100)  {temp-=100; hunderter++;}
88
  while (temp>9)    {temp-=10;  zehner++;}
89
  einer=temp;
90
  
91
  lcd_big (hunderter,2);
92
  lcd_big (zehner,6);
93
  lcd_big (13,9); // ,
94
  lcd_big (einer,12);
95
  lcd_big (11,18); // °
96
  lcd_big (12,22); // C
97
  }
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
1
uint8_t Zeile1[14][3] = {
2
    { 0,  1,  2 },    // 0
3
    { 0,  1, 32 },    // 1
4
    { 0,  1,  2 },    // 2
5
    { 0,  1,  2 },    // 3
6
    { 1, 32, 32 },    // 4
7
    { 1,  1,  1 },    // 5
8
    ... etc ...
9
};
10

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

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

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

23
void lcd_big(uint8_t zahl, uint8_t spalte)
24
{
25
  // Zeile 1
26
  lcd_gotoxy (spalte,0);
27
  lcd_putc( Zeile1[zahl][0] );
28
  lcd_putc( Zeile1[zahl][1] );
29
  lcd_putc( Zeile1[zahl][2] );
30

31
  // Zeile 2
32
  lcd_gotoxy (spalte,1);
33
  lcd_putc( Zeile2[zahl][0] );
34
  lcd_putc( Zeile2[zahl][1] );
35
  lcd_putc( Zeile2[zahl][2] );
36

37
  // Zeile 3
38
  lcd_gotoxy (spalte,2);
39
  lcd_putc( Zeile3[zahl][0] );
40
  lcd_putc( Zeile3[zahl][1] );
41
  lcd_putc( Zeile3[zahl][2] );
42
 
43
  // Zeile 4
44
  lcd_gotoxy (spalte,3);
45
  lcd_putc( Zeile4[zahl][0] );
46
  lcd_putc( Zeile4[zahl][1] );
47
  lcd_putc( Zeile4[zahl][2] );
48
}

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
1
void lcd_Zeile(uint8_t zahl, uint8_t reihe, uint8_t spalte, uint8_t Codes[14][3] )
2
{
3
  lcd_gotoxy (spalte,reihe);
4
  lcd_putc( Codes[zahl][0] );
5
  lcd_putc( Codes[zahl][1] );
6
  lcd_putc( Codes[zahl][2] );
7
}
8

9
void lcd_big(uint8_t zahl, uint8_t spalte)
10
{
11
  lcd_Zeile( zahl, 0, spalte, Zeile1 );
12
  lcd_Zeile( zahl, 1, spalte, Zeile2 );
13
  lcd_Zeile( zahl, 2, spalte, Zeile3 );
14
  lcd_Zeile( zahl, 3, spalte, Zeile4 );
15
}

Neben der verringerten Codegröße ist auch die gesteigerte
Übersichtlichkeit nicht zu verachten.
Gast
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
1
void lcd_big(uint8_t zahl, uint8_t spalte)
2
{
3

4
uint8_t zeile1 [13] [3] PROGMEM = {
5
{ 0,   1,   2  },
6
{ 0,   1,  32  },
7
{ 0,   1,   2  },
8
{ 0,   1,   2  },
9
{ 1,  32,  32  },
10
{ 1,   1,   1  },
11
{ 0,   1,   2  },
12
{ 1,   1,   1  },
13
{ 0,   1,   2  },
14
{ 0,   1,   2  },
15
{ 0,   1,   2  },   // ° - Zeichen
16
{ 0,   1,   2  },   // C
17
{ 32, 32,  32  } }; // , - Zeichen
18

19
uint8_t zeile2 [13] [3] PROGMEM = {
20
{ 255,  32,  255 },
21
{ 32,  255,   32 },
22
{ 0,     1,    3 },
23
{ 32,    0,    3 },
24
{ 255,   1,  255 },
25
{ 255,   1,    2 },
26
{ 255,   1,    2 },
27
{ 32,    0,    3 },
28
{ 255,   1,  255 },
29
{ 255,   1,  255 },
30
{ 255,  32,  255 },   // ° - Zeichen
31
{ 255,  32,   32 },   // C
32
{ 32,   32,   32 } }; // , - Zeichen
33

34
uint8_t zeile3 [13] [3] PROGMEM = {
35
{ 255,  32,  255 },
36
{ 32,  255,   32 },
37
{ 255,  32,   32 },
38
{ 32,    5,    4 },
39
{ 32,   32,  255 },
40
{ 32,   32,  255 },
41
{ 255,  32,  255 },
42
{ 32,  255,   32 },
43
{ 255,  32,  255 },
44
{ 32,   32,  255 },
45
{ 5,     6,    7 },   // ° - Zeichen
46
{ 255,  32,   32 },   // C
47
{ 32,   32,   32 } }; // , - Zeichen
48

49
uint8_t zeile4 [13] [3] PROGMEM = {
50
{ 5,   6,   7   },
51
{ 6,   6,   6   },
52
{ 6,   6,   6   },
53
{ 5,   6,   7   },
54
{ 32, 32,   6   },
55
{ 6,   6,   7   },
56
{ 5,   6,   7   },
57
{ 32,  6,  32   },
58
{ 5,   6,   7   },
59
{ 5,   6,   7   },
60
{ 32, 32,  32   },   // ° - Zeichen
61
{ 5,   6,   7   },   // C
62
{ 32,  6,  32   } }; // , - Zeichen
63

64
 
65
 // Zeile 1
66
  lcd_gotoxy (spalte,0);
67
  lcd_putc( pgm_read_byte(&( zeile1[zahl][0] )) );
68
  lcd_putc( pgm_read_byte(&( zeile1[zahl][1] )) );
69
  lcd_putc( pgm_read_byte(&( zeile1[zahl][2] )) );
70

71
  // Zeile 2
72
  lcd_gotoxy (spalte,1);
73
  lcd_putc( pgm_read_byte(&( zeile2[zahl][0] )) );
74
  lcd_putc( pgm_read_byte(&( zeile2[zahl][1] )) );
75
  lcd_putc( pgm_read_byte(&( zeile2[zahl][2] )) );
76

77
  // Zeile 3
78
  lcd_gotoxy (spalte,2);
79
  lcd_putc( pgm_read_byte(&( zeile3[zahl][0] )) );
80
  lcd_putc( pgm_read_byte(&( zeile3[zahl][1] )) );
81
  lcd_putc( pgm_read_byte(&( zeile3[zahl][2] )) );
82
 
83
  // Zeile 4
84
  lcd_gotoxy (spalte,3);
85
  lcd_putc( pgm_read_byte(&( zeile4[zahl][0] )) );
86
  lcd_putc( pgm_read_byte(&( zeile4[zahl][1] )) );
87
  lcd_putc( pgm_read_byte(&( zeile4[zahl][2] )) );
88
  
89
}
90

91

92
void show_temperature (uint8_t temp)
93
  {
94
  uint8_t hunderter=0,zehner=0,einer=0;
95
  while (temp>100)  {temp-=100; hunderter++;}
96
  while (temp>9)    {temp-=10;  zehner++;}
97
  einer=temp;
98
  
99
  lcd_big (hunderter,2);
100
  lcd_big (zehner,6);
101
  lcd_big (13,9); // ,
102
  lcd_big (einer,12);
103
  lcd_big (11,18); // °
104
  lcd_big (12,22); // C
105
  
106
  }


@ 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.
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.
Gast
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.)
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.
Gast
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.
Gast
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.
Gast
@ 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
Alle 4 Tabellen können in einer zusammengefasst werden, das vereinfacht 
die Routinen von Karl Heinz
1
uint8_t Font[13] [3*4] PROGMEM = {
2
{ 0, 1, 2,     255, 32, 255,   255, 32, 255,   5, 6, 7},
3
... usw.
4

5
void lcd_big(uint8_t zahl, uint8_t spalte)
6
{
7
  uint8_t* font = &Font[zahl];
8
  for (uint8_t i = 0; i < 4; i++) {
9
    lcd_gotoxy (spalte, i);
10
    for (uint8_t j = 0; j < 3; j++) 
11
      lcd_putc(pgm_read_byte(font++));
12
  } 
13
}

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

Gruß Hagen

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 19 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.