Forum: Projekte & Code HD44780 Hochauflösender Bargraf auf Text-LCD (Beispiel AVR-GCC)


von Dominik (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
animiert durch eine Diskussion zum Thema CGRam, und als Dankeschön, hier 
mal ein CodeSchnipsel mit etwas anderem Ansatz.

Vorwort:
Obwohl mittlerweile grafische und farbige Displays den Text-LCDs den 
Rang ablaufen haben diese durchaus noch eine Daseinsberechtigung durch 
Ihre einfache Ansteuerung und Anschaffung. Mit etwas Geduld hat man ja 
heute innerhalb von 4 Wochen für einen guten Euro ein 16x2 Modell im 
Briefkasten.
Und für kleinere µC-Projekte muss es ja nicht immer Grafik sein... aber 
ganz ohne ist irgendwie auch doof... daher haben alle HD44780 und 
kompatible einen Speicherbereich für 8 eigenen Zeichen (5*8), die man 
beliebig belegen kann, und - da es sich um Ram handelt - auch beliebig 
oft.
Beim "Standardansatz" werden nun diese Zeichen vorbelegt und der Bargraf 
daraus zusammengesetzt.
Das bedeutet man benötigt mindestens 6 Zeichen für einen horizontalen 
und mindestens 9 Zeichen für einen vertikalen Bargraf. Hier kann man 
sich zur Not dann z.B. mit Leerzeichen und Vollzeichen(0xFF) behelfen 
wenn man nicht genügend freie eigene Zeichen zur Verfügung hat, was 
jedoch die Designs wiederum stark einschränkt.
Die Auflösung dieser Bargrafen liegt dann auch in einem überschaubaren 
Bereich:
Horizontal: Spalten*5 (z.B. 16x5=80 Werte)
Vertikal:   Zeilen*8 (z.B. 4x8=32 Werte)

Erweiterte Herangehensweise:
Die eigenen Zeichen werden erst dann belegt oder geändert, wenn der 
anzuzeigende Wert bekannt ist.
Dieser Ansatz erlaubt eine dtl. höhere Auflösung und benötigt weniger 
eigene Zeichen pro Bargraf (hier 3) auch verfügt der Bargraf über einen 
Rand, um dem User zu vermitteln wo dieser endet. Ob horizontal oder 
Vertikal ist hierbei wurscht, das folgende Beispiel ist horizontal, was 
bei den meisten Displays wohl mehr Sinn macht.
(Mit leichter Anpassung im Code wären bis zu 6 solcher Bargrafen in 
horizontal oder vertikal gleichzeitig auf einem LCD möglich, in der 
vorliegenden Variante sind 2 gleichzeitig erlaubt, was für die meisten 
LCDs ausreichen sollte.)
Das Bild im Anhang zeigt die Anwendung beispielhaft auf einem 20x4 LCD, 
die Auflösung beträgt hier 400 Werte. Verzichtet man auf den Rand wären 
800 möglich (bei 20 Spalten). Dargestellt wird dies durch den letzten 
Balken, der -wertabhängig- nur anteilig eingeblendet wird. Benötigt man 
diese Auflösung nicht, hat man mit dem Ansatz zumindest eigene Zeichen 
gespart:

Code kann frei verwendet oder angepasst werden,
von der Anwendung sind 3 Funktionen bereitzustellen:
1
void LCD_setCGRamAddress(uint8_t address);
2
void LCD_goto(column, row); //DDRAM
3
LCD_writeCharacter(uin8_t data); //unsigned char


Viel Spaß damit...
1
#define BAR_LINE_0       0b00000000
2
#define BAR_LINE_5       0b00011111
3
#define BAR_LINES      4      //3 or 4 allowed
4
#define BAR_PIXEL_PER_CHAR   (BAR_LINES*5ul)
5
6
void LCD_drawBarGraphHorizontal(uint8_t column, uint8_t row, uint8_t width, uint16_t value, uint16_t maxValue, uint8_t uCharOffset)
7
{
8
  uint16_t scaledValue=((uint32_t) value)*(((uint32_t) (width)))*BAR_PIXEL_PER_CHAR/((uint32_t) maxValue);
9
  uint8_t scaledValueCharPosition=scaledValue/BAR_PIXEL_PER_CHAR;
10
  uint8_t scaledValueRemainder=scaledValue%BAR_PIXEL_PER_CHAR;
11
12
  LCD_setCGRamAddress(uCharOffset*8);
13
  //Full Element  UDF 0
14
  LCD_writeCharacter(BAR_LINE_5);
15
  LCD_writeCharacter(BAR_LINE_0);
16
  LCD_writeCharacter(BAR_LINE_5);
17
  LCD_writeCharacter(BAR_LINE_5);
18
  LCD_writeCharacter(BAR_LINE_5);
19
  if(BAR_LINES==3)
20
  {
21
    LCD_writeCharacter(BAR_LINE_0);
22
    LCD_writeCharacter(BAR_LINE_5);
23
    LCD_writeCharacter(BAR_LINE_0);
24
  }
25
  else
26
  {
27
    LCD_writeCharacter(BAR_LINE_5);
28
    LCD_writeCharacter(BAR_LINE_0);
29
    LCD_writeCharacter(BAR_LINE_5);
30
  }
31
  //Scaled Element UDF 1
32
  LCD_writeCharacter(BAR_LINE_5);
33
  LCD_writeCharacter(BAR_LINE_0);
34
35
  uint8_t line;
36
  for(int8_t lineId=(BAR_LINES-1); lineId>=0; lineId--)
37
  {
38
    line=BAR_LINE_0;
39
    for(uint8_t digit=0; digit<5; digit++)
40
    {
41
      if(scaledValueRemainder>((digit*BAR_LINES)+lineId))
42
      {
43
        line|=(0b00010000>>digit);
44
      }
45
    }
46
    LCD_writeCharacter(line);
47
  }
48
  if(BAR_LINES==3)
49
  {
50
    LCD_writeCharacter(BAR_LINE_0);
51
    LCD_writeCharacter(BAR_LINE_5);
52
    LCD_writeCharacter(BAR_LINE_0);
53
  }
54
  else
55
  {
56
    LCD_writeCharacter(BAR_LINE_0);
57
    LCD_writeCharacter(BAR_LINE_5);
58
  }
59
  //Empty Element UDF 2
60
  LCD_writeCharacter(BAR_LINE_5);
61
  LCD_writeCharacter(BAR_LINE_0);
62
  LCD_writeCharacter(BAR_LINE_0);
63
  LCD_writeCharacter(BAR_LINE_0);
64
  LCD_writeCharacter(BAR_LINE_0);
65
  LCD_writeCharacter(BAR_LINE_0);
66
  if(BAR_LINES==3)
67
  {
68
    LCD_writeCharacter(BAR_LINE_5);
69
    LCD_writeCharacter(BAR_LINE_0);
70
  }
71
  else
72
  {
73
74
    LCD_writeCharacter(BAR_LINE_0);
75
    LCD_writeCharacter(BAR_LINE_5);
76
  }
77
78
  LCD_goto(column, row);
79
  for(uint8_t charPosition=0; charPosition<width; charPosition++)
80
  {
81
    if(charPosition<scaledValueCharPosition)
82
      LCD_writeCharacter(0);
83
    else if(charPosition==scaledValueCharPosition)
84
      LCD_writeCharacter(1);
85
    else
86
      LCD_writeCharacter(2);
87
  }  
88
}

P.S.: Char 0 und 2 kann man natürlich auch in eine Init-Funktion 
auslagern, falls das restliche Programm diese Zeichen nicht nutzt, damit 
fallen dann wesentlich weniger LCD-Schreibzyklen an.

von Tom (Gast)


Lesenswert?

Nette Idee. Für jeden weiteren Bargraf wird ein weiteres Zeichen fällig 
und trotzdem hat man noch ein paar Zeichen frei :-)

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.