LCD-Routine optimieren (große Zahlen)

Gast #594000
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 ?
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
  }
#594009
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
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 #594131
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
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.
#594144
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.
Gast #594158
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.)
#594165
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.
Gast #594303
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.
Gast #594327
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
#595627
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren