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


von Tobias Paul (Gast)


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
  }

von Peter D. (peda)


Lesenswert?

Unkommentierte Routinen liebe ich (würdige ich keines Blickes).

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


Peter



von Karl H. (kbuchegg)


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.

von Tobias Paul (Gast)


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.

von Karl H. (kbuchegg)


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.

von Tobias Paul (Gast)


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.)

von Karl H. (kbuchegg)


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.

von Tobias Paul (Gast)


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.

von Horst (Gast)


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.

von Falk (Gast)


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

von Horst (Gast)


Lesenswert?

@Falk

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

horst.

von Hagen R. (hagen)


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

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.