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.
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.
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
HD44780 Datasheet
1 file(s) 278.43 KB
lcd-routines
1 file(s) 4.61 KB
Thank you for the excellent article
detailed-bargraphs = when I download it, the folder is empty = 0 KB