Software: LCD Display und Tasten

Jetzt sind Anforderungen und Spezifikationen erstellt. Probleme, die Entstehen könnten, sind identifiziert und berücksichtigt. Dann kann es endlich mit der Software losgehen. Für den Anfang starte ich mal mit dem User Interface, dem LCD Display mit den Tasten.

Nach Spezifikation sind die beiden Zeilen belegt mit:
1. Zeile mit Datum und Uhrzeit, die auch von Hand eingestellt werden können.
2. Zeile mit den Messwerten für Luftfeuchte und Temperatur nur Anzeigen

Die Herausforderung hier ist die Einstellung der verschiedenen Werte mit Berücksichtigung der Maximal- und Minimalwerte, die jeweils möglich sind. So hat ein Monat maximal 31 Tage und beginnt immer mit dem Tag 1. Das macht die Software etwas unübersichtlich, dafür die Eingabe etwas einfacher. Das einzige, was später noch eingefügt werden muss, ist die unterschiedliche Länge der Monate in Tagen. Des weiteren soll die Eingabe stabil erfolgen, ohne das die Tasten anfangen zu rennnnnnnen. Bei der Eingabe muss also darauf geachtet werden, das die Taste erst wieder losgelassen wird, bevor ein gültiger Wert eingelesen werden kann.

Der DEBUG Compilerswitch wird als Debughilfe eingesetzt. Es werden Meldungen über die serielle (USB) Schnittstelle zum „seriellen Monitor“ gesendet.

Hier der Sketch:

[code]
/****************************************************************************
* Projekt – Messtechnik 1
* (c) 2017 softwareentwicklung-als-prozess.de
* Dokumentation s. Blog
***************************************************************************/
// Includes —————————————————————–
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <DS1302RTC.h>
// Defines —————————————————————–
// To set the backlight color
#define OFF 0x0
#define ON 0x1
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7

// Fuer DEBUGging
#define DEBUG

// Fuer Wartezeiten
#define MINUTE 60000

// Fuer Cursorposition
#define CURSORMARGINLEFT 0
#define CURSORMARGINRIGHT 13

// RTC Pins
// DS1302: CE pin -> Arduino Digital 27
// I/O pin -> Arduino Digital 29
// SCLK pin -> Arduino Digital 31
// VCC pin -> Arduino Digital 33
// GND pin -> Arduino Digital 35
#define DS1302_GND_PIN 35
#define DS1302_VCC_PIN 33

// Variablen —————————————————————–
// Zeitangaben
byte tag = (byte)0;
byte monat = (byte)0;
byte jahr = (byte)0;
byte stunde = (byte)0;
byte minut = (byte)0;
// Fallback falls keine Änderung gewünscht
byte fb_tag = (byte)0;
byte fb_monat = (byte)0;
byte fb_jahr = (byte)0;
byte fb_stunde = (byte)0;
byte fb_minut = (byte)0;

// messwerte DHT11
byte temperatur = (byte)0; // 0 – 50 Grad Celsius
byte feuchte = (byte)0; // 20 – 90 Prozent relative Luftfeuchte

// Wartezeiten
unsigned long starttime = (unsigned long)0;
unsigned long actualtime = (unsigned long)0;

// Tastenstatus
boolean buttonpressed = (boolean)false; // keine Taste gedrueckt
boolean selectbuttonpressed = (boolean)false; // Select Taste nicht gedrückt

// Cursorposition
byte curpos = (byte)CURSORMARGINLEFT;

// LCD Shield mit Tasten (I2C)
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// Init the DS1302
// Set pins: CE, IO,CLK
DS1302RTC RTC(27, 29, 31);

// Funktionen —————————————————————
void setup()
{
DebugPrintInit();
DebugPrint(„Messtechnik1 – Display + Tasten“);
lcd.begin(16, 2); // Anzahl Spalten und Zeilen vom Display setzen
lcd.setBacklight(ON); // Beleuchtung einschalten
lcd.clear(); // erstmal alles löschen
lcd.home(); // Cursor nach links oben
DisplayTime(tag,monat,jahr,stunde,minut); // Init Zeitzeile ausgeben
DisplayMesswert(temperatur, feuchte); // Init Messzeile ausgeben
// Activate RTC module
// GND
digitalWrite(DS1302_GND_PIN, LOW);
pinMode(DS1302_GND_PIN, OUTPUT);
// VCC
digitalWrite(DS1302_VCC_PIN, HIGH);
pinMode(DS1302_VCC_PIN, OUTPUT);

// RTC einlesen
SaveTimeToFallback(); // aktuelle Zeit merken
// Messwerte einlesen
starttime = actualtime = millis(); // Wartezeit starten
DebugPrint(„Setup abgeschlossen“);
}

void loop()
{
uint8_t buttons = (uint8_t)0;

if ((actualtime – starttime) > MINUTE) // Eine Minute ist abgelaufen
{
// RTC einlesen
// Messwerte einlesen
DebugPrint(„Minute abgelaufen: RTC und Messwerte einlesen“);
RestoreFallbackToTime(); // keine neuen Werte übernommen
CursorBlinkAus(); // Cursor und Blinken aus
DebugPrint(„Cursor aus“);
ActualizeDisplay(); // Werte ausgeben
buttonpressed = false; // kein Button gedrückt
starttime = millis(); // Start fuer naechste Minute
}
// innerhalb der minute
actualtime = millis(); // aktuelle Zeit einlesen
CheckTimeOverrun(); // Ueberlauf von millis() oder Programmfehler
buttons = GetButtons(); // Tasten einlesen
CheckButtons(buttons); // Tasten vorauswerten
if (selectbuttonpressed == true) // Select Taste wurde gedrückt
{
selectbuttonpressed = false; // Select Taste fertig ausgewertet
// RTC mit neuer Zeit setzen
DebugPrint(„neue Zeit im RTC gesetzt“);
CursorBlinkAus(); // Cursor und Blinken aus
ActualizeDisplay(); // Werte ausgeben
}
}

// Software – Ethernet und MQTT ————————————————

// Software – Temperatur- und Luftfeuchte Sensor ——————————-

// Software – RTC ————————————————————–

// Software – Display und Tasten ———————————————–
uint8_t GetButtons(void)
{
uint8_t rdbuttons = (uint8_t)0; // aktuelle Tasten
uint8_t oldbuttons = (uint8_t)0; // vorige Tasten

rdbuttons = lcd.readButtons(); // Tasten einlesen
while (rdbuttons != 0) // Warten auf Taste losgelassen
{
oldbuttons = rdbuttons; // aktuellen Wert übernehmen
rdbuttons = lcd.readButtons(); // Tasten einlesen
}
return(oldbuttons); // Tastenwerte übergeben
}

void CheckButtons(uint8_t butt)
{
byte zehner = 0;
byte einer = 0;

if (butt != (uint8_t)0) // Ein Button wurde gedrueckt
{
actualtime = starttime = millis(); // Zeitmessung starten
if (buttonpressed == false)
{
SaveTimeToFallback(); // aktuelle zeit sichern
buttonpressed = true; // Eine Taste wurde gedrückt
}
CursorBlinkEin(); // Cursor und Blinken ein
if (butt & BUTTON_UP) // BUTTON UP gedrückt
{
lcd.setCursor(curpos,0); // auf aktuelle Cursorposition setzen
switch(curpos) // nach Position auswerten
{
// Tage max = 31
case 0 : // Tag Zehner
if (tag > (byte)0)
{
zehner = GetZehner(tag);
}
if (zehner < (byte)3)
{
tag += (byte)10;
if (tag > (byte)31)
{
tag = (byte)31;
}
}
lcd.print(GetZehner(tag), DEC);
lcd.print(GetEiner(tag) , DEC);
DebugPrintValue(„Tag Zehner = „, GetZehner(tag));
break;
case 1 : // Tag Einer
if (tag > (byte)0)
{
zehner = GetZehner(tag);
einer = GetEiner(tag);
}
if (zehner < (byte)3)
{
if (einer < (byte)9)
{
tag++;
}
}
else
{
if ((byte)0 == einer)
{
tag++;
}
}
lcd.print(GetEiner(tag),DEC);
DebugPrintValue(„Tag Einer = „,GetEiner(tag));
break;
// Monat max = 12
case 3 : // Monat Zehner
if (monat > (byte)0)
{
zehner = GetZehner(monat);
}
if (zehner < (byte)1)
{
monat += (byte)10;
}
if (monat > (byte)12)
{
monat = (byte)12;
}
lcd.print(GetZehner(monat), DEC);
lcd.print(GetEiner(monat) , DEC);
DebugPrintValue(„Monat Zehner = „, GetZehner(monat));
break;
case 4 : // Monat Einer
if (monat > (byte)0)
{
zehner = GetZehner(monat);
einer = GetEiner(monat);
}
if (zehner < (byte)1)
{
if (einer < (byte)9)
{
monat++;
}
}
else
{
if (einer < (byte)2)
{
monat++;
}
}
lcd.print(GetEiner(monat),DEC);
DebugPrintValue(„Monat Einer = „,GetEiner(monat));
break;
// Jahr max = 99
case 6 : // Jahr Zehner
if (jahr > (byte)0)
{
zehner = GetZehner(jahr);
}
if (zehner < (byte)9)
{
jahr += 10;
}
lcd.print(GetZehner(jahr),DEC);
DebugPrintValue(„Jahr Zehner = „,GetZehner(jahr));
break;
case 7 : // Jahr Einer
if (jahr > (byte)0)
{
einer = GetEiner(jahr);
}
if (einer < (byte)9)
{
jahr++;
}
lcd.print(GetEiner(jahr),DEC);
DebugPrintValue(„Jahr Einer = „,GetEiner(jahr));
break;
// Stunde max = 23
case 9 : // Stunde Zehner
if (stunde > (byte)0)
{
zehner = GetZehner(stunde);
}
if (zehner < (byte)2)
{
stunde += (byte)10;
if (stunde > (byte)23)
{
stunde = (byte)23;
}
}
lcd.print(GetZehner(stunde), DEC);
lcd.print(GetEiner(stunde) , DEC);
DebugPrintValue(„Stunde Zehner = „, GetZehner(stunde));
break;
case 10 : // Stunde Einer
if (stunde > (byte)0)
{
zehner = GetZehner(stunde);
einer = GetEiner(stunde);
}
if (zehner < (byte)2)
{
if (einer < (byte)9)
{
stunde++;
}
}
else
{
if (einer < (byte)3)
{
stunde++;
}
}
lcd.print(GetEiner(stunde),DEC);
DebugPrintValue(„Stunde Einer = „,GetEiner(stunde));
break;
// Minute max = 59
case 12 : // Minute Zehner
if (minut > (byte)0)
{
zehner = GetZehner(minut);
}
if (zehner < (byte)5)
{
minut += (byte)10;
}
lcd.print(GetZehner(minut), DEC);
lcd.print(GetEiner(minut) , DEC);
DebugPrintValue(„Minute Zehner = „, GetZehner(minut));
break;
case 13 : // Minute Einer
if (minut > (byte)0)
{
zehner = GetZehner(minut);
einer = GetEiner(minut);
}
if (einer < (byte)9)
{
minut++;
}
lcd.print(GetEiner(minut),DEC);
DebugPrintValue(„Minute Einer = „,GetEiner(minut));
break;
default :
break;
}
lcd.setCursor(curpos,0); // Cursor neu setzen
}

if (butt & BUTTON_DOWN) // BUTTON DOWN gedrückt
{
lcd.setCursor(curpos,0); // auf aktuelle Cursorposition setzen
switch(curpos) // nach Position auswerten
{
// Tage min = 1
case 0 : // Tag Zehner
if (tag > (byte)0)
{
zehner = GetZehner(tag);
}
if (zehner > (byte)0)
{
tag -= (byte)10;
}
if (tag < (byte)1)
{
tag = (byte)1;
}
lcd.print(GetZehner(tag), DEC);
lcd.print(GetEiner(tag) , DEC);
DebugPrintValue(„Tag Zehner = „, GetZehner(tag));
break;
case 1 : // Tag Einer
if (tag > (byte)0)
{
einer = GetEiner(tag);
}
if (einer > (byte)0)
{
tag–;
}
if ((byte)0 == tag)
{
tag = (byte)1;
}
lcd.print(GetEiner(tag), DEC);
DebugPrintValue(„Tag Einer = „, GetEiner(tag));
break;
// Monat min = 1
case 3 : // Monat Zehner
if (monat > (byte)0)
{
zehner = GetZehner(monat);
}
if (zehner > (byte)0)
{
monat -= (byte)10;
}
if (monat < (byte)1)
{
monat = (byte)1;
}
lcd.print(GetZehner(monat), DEC);
lcd.print(GetEiner(monat) , DEC);
DebugPrintValue(„Monat Zehner = „, GetZehner(monat));
break;
case 4 : // Monat Einer
if (monat > (byte)0)
{
einer = GetEiner(monat);
}
if (einer > (byte)0)
{
monat–;
}
if ((byte)0 == monat)
{
monat = (byte)1;
}
lcd.print(GetEiner(monat), DEC);
DebugPrintValue(„Monat Einer = „, GetEiner(monat));
break;
// Jahr min = 0
case 6 : // Jahr Zehner
if (jahr > (byte)0)
{
zehner = GetZehner(jahr);
}
if (zehner > (byte)0)
{
jahr -= (byte)10;
}
lcd.print(GetZehner(jahr),DEC);
DebugPrintValue(„Jahr Zehner = „,GetZehner(jahr));
break;
case 7 : // Jahr Einer
if (jahr > (byte)0)
{
einer = GetEiner(jahr);
}
if (einer > (byte)0)
{
jahr–;
}
lcd.print(GetEiner(jahr),DEC);
DebugPrintValue(„Jahr Einer = „,GetEiner(jahr));
break;
// Stunde min = 0
case 9 : // Stunde Zehner
if (stunde > (byte)0)
{
zehner = GetZehner(stunde);
}
if (zehner > (byte)0)
{
stunde -= (byte)10;
}
lcd.print(GetZehner(stunde), DEC);
DebugPrintValue(„Stunde Zehner = „, GetZehner(stunde));
break;
case 10 : // Stunde Einer
if (stunde > (byte)0)
{
zehner = GetZehner(stunde);
einer = GetEiner(stunde);
}
if (einer > (byte)0)
{
stunde–;
}
lcd.print(GetEiner(stunde) ,DEC);
DebugPrintValue(„Stunde Einer = „,GetEiner(stunde));
break;
// Minute min = 0
case 12 : // Minute Zehner
if (minut > (byte)0)
{
zehner = GetZehner(minut);
}
if (zehner > (byte)0)
{
minut -= (byte)10;
}
lcd.print(GetZehner(minut), DEC);
DebugPrintValue(„Minute Zehner = „, GetZehner(minut));
break;
case 13 : // Minute Einer
if (minut > (byte)0)
{
einer = GetEiner(minut);
}
if (einer > (byte)0)
{
minut–;
}
lcd.print(GetEiner(minut),DEC);
DebugPrintValue(„Minute Einer = „,GetEiner(minut));
break;
default :
break;
}
lcd.setCursor(curpos,0); // Cursor neu setzen
}

if (butt & BUTTON_LEFT)
{
if (curpos > (byte)CURSORMARGINLEFT)
{
curpos–;
}
if ((curpos == 2) | (curpos == 5) | (curpos == 8) | (curpos == 11)) // ‚.‘,‘:‘,‘ ‚ ueberspringen
{
curpos–;
}
lcd.setCursor(curpos,0); // Cursor neu setzen
}

if (butt & BUTTON_RIGHT)
{
if (curpos < (byte)CURSORMARGINRIGHT)
{
curpos++;
}
if ((curpos == 2) | (curpos == 5) | (curpos == 8) | (curpos == 11)) // ‚.‘,‘:‘,‘ ‚ ueberspringen
{
curpos++;
}
lcd.setCursor(curpos,0); // Cursor neu setzen
}

DebugPrintValue(„Button gedrueckt – Cursor ein – pos = „,curpos);

if (butt & BUTTON_SELECT) // BUTTON SELECT gedrückt
{
CursorBlinkAus(); // Cursor und Blinken aus
DebugPrint(„Select gedrueckt und Cursor aus“);
buttonpressed = false; // irgendeine Taste gedrückt
selectbuttonpressed = true; // Select Taste gedrückt
}
}
}

void SaveTimeToFallback(void)
{
fb_tag = tag;
fb_monat = monat;
fb_jahr = jahr;
fb_stunde = stunde;
fb_minut = minut;
}

void RestoreFallbackToTime(void)
{
tag = fb_tag;
monat = fb_monat;
jahr = fb_jahr;
stunde = fb_stunde;
minut = fb_minut;
}

void ActualizeDisplay(void)
{
DisplayTime(tag,monat,jahr,stunde,minut); // Zeitzeile ausgeben
DisplayMesswert(temperatur, feuchte); // Messzeile ausgeben
}

void DisplayTime(byte t, byte m, byte j, byte s, byte mn)
{
lcd.setCursor(0, 0); // obere Zeile
// Tag
lcd.print(GetZehner(t),DEC);
lcd.print(GetEiner(t) ,DEC);
lcd.print(„.“);
// Monat
lcd.print(GetZehner(m),DEC);
lcd.print(GetEiner(m) ,DEC);
lcd.print(„.“);
// Jahr
lcd.print(GetZehner(j),DEC);
lcd.print(GetEiner(j) ,DEC);
// Trenn
lcd.print(“ „);
// Stunde
lcd.print(GetZehner(s),DEC);
lcd.print(GetEiner(s) ,DEC);
lcd.print(„:“);
// Minute
lcd.print(GetZehner(mn),DEC);
lcd.print(GetEiner(mn) ,DEC);
}

void DisplayMesswert(byte t, byte f)
{
char grad[2] = {(char)223,(char)0}; // Gradzeichen nach Datenblatt LCD 44780

lcd.setCursor(0, 1); // untere Zeile
// Luftfeuchte
lcd.print(GetZehner(f));
lcd.print(GetEiner(f));
lcd.print(„%“);
// Trenn
lcd.print(“ „);
// Temperatur
lcd.print(GetZehner(t));
lcd.print(GetEiner(t));
lcd.print(grad);
}

byte GetZehner(byte x)
{
return(x / 10);
}

byte GetEiner(byte y)
{
return(y – (GetZehner(y) * 10));
}

void CheckTimeOverrun(void)
{
if (actualtime < starttime) // Ueberlauf von millis() oder Programmfehler
{
starttime = actualtime = millis();
DebugPrint(„Ueberlauf millis()“);
}
}

void CursorBlinkAus(void)
{
lcd.noBlink();
lcd.noCursor();
}

void CursorBlinkEin(void)
{
lcd.cursor();
lcd.blink();
}

void DebugPrint(char *str)
{
#ifdef DEBUG
Serial.println(str);
#endif
}

void DebugPrintValue(char *str, byte val)
{
#ifdef DEBUG
Serial.print(str);
Serial.println(val,DEC);
#endif
}

void DebugPrintInit(void)
{
#ifdef DEBUG
Serial.begin(9600);
#endif
}

[/code]

Links

Die Hardware

Die Systemspezifikation

Die Anforderungen

Veröffentlicht von

Jürgen

Ich bin Software Ingenieur und habe meine Schwerpunkte in allen Aktivitäten, die zur Software Entwicklung gehören. Am längsten bin ich als Software Entwickler von Embedded Software in C tätig.