HD44780 – Balkendiagramme

In diesem Artikel geht es um die Darstellung von detaillierten Balkendiagrammen auf HD44780 LC-Displays. Der Fokus liegt auf der Programmierung. Die Verdrahtung hängt von Display und Controller ab. Falls du nicht weißt, wie du dein Display in Betrieb nehmen kannst, siehe hier. Der folgende Code verwendet diese Bibliothek.

Der HD44780 Controller hat keine integrierte Funktion um Balkendiagramme zu erstellen, man kann nur die im CGROM vordefinierten Zeichen verwenden. Diese Zeichen sind abhängig von der Version des HD44780 Controllers. In dem häufigsten Fällen ist die „European standard font“ vorhanden. Du kannst im Datenblatt genauere Informationen zu deinem eigenen Controller finden. Das Datenblatt steht am Ende dieser Seite zum Download.

Aber wie erstellt man nun Balkendiagramme?

Der Trick ist das interne CGRAM des LCD Controllers zu verwenden. Der CGRAM ist ein Zeichenspeicher der Platz für 8 benutzerdefinierte Zeichen hat. Innerhalb dieses Speichers werden eigene Zeichen abgelegt, mit denen man Balkendiagramme darstellen kann.

Mit den folgenden 3 Zeichen kann man pro LCD Zeile 2 Balkendiagramme darstellen. Da diese Zeichen immer gleich sein werden, können diese am Start des Programmes in den CGRAM geschrieben werden.

Dieses Zeichen wird verwendet, wenn beide Balkendiagramme dargestellt werden sollen.
Dieses Zeichen wird verwendet, wenn nur noch das erste Balkendiagramm weiter läuft.
Dieses Zeichen wird verwendet, wenn nur noch das 2. Balkendiagramm weiter läuft.

Um diese 3 Zeichen in im HD44780 abzulegen habe ich diese folgende Funktion geschrieben:

void lcd_add_static_chars() {
  uint8_t char10[8] = {0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000},// first row
          char01[8] = {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111},// seconds row
          char11[8] = {0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111};// both
  lcd_generatechar(5, char10);
  lcd_generatechar(6, char01);
  lcd_generatechar(7, char11);
}

 

Mit diesen 3 Zeichen kannst du jetzt Balkendiagramme darstellen. Die Auflösung beträgt 16 Schritte von 0% bis 100% bei einem normalen 2×16 LCD. Also erhält man eine Schrittweite von 6,25%.

 

Für manche Projekte reicht diese Auflösung aus, aber für eine genauere Darstellung sollte man jede Pixelspalte innerhalb eines Zeichens verwenden. Dadurch könnte man eine Auflösung von 16 * 5 Schritte von 0% bis 100% erreichen, was einer Schrittweite von 1,25% entspricht. Das ist absolut ausreichend für Balkendiagramme dieser Art!

Um das hinzubekommen, müssen die End-Zeichen jedes Balkens „on the fly“ generiert werden. Wenn man 4 unterschiedliche Balken darstellt, braucht man 4 unterschiedliche Zeichen für jedes Ende.

Unterschiedliche Zeichen für jedes Ende

Da bisher nur 3 Zeichen des CGRAMs mit den „Balken-Zeichen“ von oben belegt sind, sind noch 5 weitere Speicherplätze frei. Also genug um noch 4 weitere dynamische Zeichen zu speichern.

Ich habe einen kleinen Algorithmus geschrieben, um die Endzeichen zu generieren. Dieser ist integriert in der Funktion „lcd_display_bars“.

  • Der Prarameter „*tmpValues“ ist ein Array mit den Werten der Balken (0 = 0%; 80 = 100%)
  • Der Parameter „rows“ gibt die Anzahl der verwendeten Zeilen des Displays an (1 = 2 Balken; 2 = 4 Balken)
void lcd_display_bars(uint8_t *tmpValues, uint8_t rows) {
  uint8_t endChars[4][8] = {0}, currentEndChar = 0;
  for(uint8_t lcd_row = 0; lcd_row < rows; lcd_row++) {
    for(uint8_t i = 1; i <= 16; i++) { if((tmpValues[0 + 2 * lcd_row] > (i - 1) * 5 && tmpValues[0 + 2 * lcd_row] < i * 5) || tmpValues[1 + 2 * lcd_row] > (i - 1) * 5 && tmpValues[1 + 2 * lcd_row] < i * 5) {
        for(uint8_t c = 0; c < 6; c++) { if(tmpValues[0 + 2 * lcd_row] >= ((i - 1) * 5) + c)
            for(uint8_t r = 0; r < 3; r++)
              endChars[currentEndChar][r] |= (1 << 4 - c + 1); if(tmpValues[1 + 2 * lcd_row] >= ((i - 1) * 5) + c)
            for(uint8_t r = 5; r < 8; r++)
              endChars[currentEndChar][r] |= (1 << 4 - c + 1); } lcd_generatechar(currentEndChar, endChars[currentEndChar]); lcd_setcursor(i - 1, lcd_row + 1); lcd_data(currentEndChar); currentEndChar++; } else { lcd_setcursor(i - 1, lcd_row + 1); if(tmpValues[0 + 2 * lcd_row] >= i * 5 && tmpValues[1 + 2 * lcd_row] >= i * 5) lcd_data(uint8_t(7));
        else if(tmpValues[0 + 2 * lcd_row] >= i * 5 && tmpValues[1 + 2 * lcd_row] < i * 5) lcd_data(uint8_t(5));
        else if(tmpValues[0 + 2 * lcd_row] < i * 5 && tmpValues[1 + 2 * lcd_row] >= i * 5) lcd_data(uint8_t(6));
        else lcd_data(' ');
      }
    }
  }
}

Beispiel code

Dieser Beispielcode aktualisiert 4 Balkendiagramme alle 2 Sekunden mit Zufallszahlen. An diesem Code kann man sehen wie simpel die Verwendung der 2. Funktionen ist.

#include 
#include "lcd-routines.h"
#include "detailed-bargraphs.h"

int main(void)
{
    lcd_init(); // display initialisieren
    lcd_add_static_chars(); // die 3 statischen Zeichen in den CGRAM schreiben
    uint8_t values[4];
    
    while(1)
    {
        for(uint8_t i = 0; i < 4; i++) {
            values[i] = rand() % (5 * 16); // Zufallszahlen generieren
        }

        lcd_display_bars(&values[0], 2); // Balkendiagramme aktualisieren

        _delay_ms(2000); // 2 Sekunden warten
    }
}

 

Downloads

 

 

About the Author: Hauke Marquardt

Student Elektrotechnik & Informatik

2 Comments

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert