Software: Einbinden von Ethernet und NTP

Ethernet Shield
Das Ethernet Shield einbinden gestaltet sich relativ einfach. Die MAC Adresse habe ich auf einem Aufkleber an der Unterseite gefunden. Die Bibliothek habe ich dann heruntergeladen und als Zip Bibliothek installiert. Bei den Beispielen ist auch die DHCP Abfrage dabei. Das ist das erste, was ich für die Inbetriebnahme brauche. Plötzlich funktioniert der Sensor nicht mehr…. Ich verschiebe die Anschlusspins um einen Pin, um von der SPI Schnittstelle wegzukommen, die vom Ethernetshield benutzt wird. Hurra, jetzt funktioniert der Sensor wieder!

Abfragen der NTP Zeit
Aus der Beispielsoftware baue ich mir meine NTP Abfrage zusammen. Da ich nicht den Platz habe eine Datumsumrechnung mit Schaltjahren etc. zu machen, hole ich mir also nur die aktuelle Zeit in Stunden und Minuten. Auch dabei muss ich noch die Sommerzeit / Winterzeit berücksichtigen.

Zeitzone und Sommerzeit
Die Zeit, die ich zurückbekomme ist UTC Zeit. Meine Zeitzone ist UTC + 1. Ich muss also noch eine Stunde dazu addieren. Ach ja, die Sommerzeit kommt auch noch dazu.

Refactoring
Diese Gelegenheit nutze ich außerdem für ein Refactoring der Software. Mein besonderes Augenmerk liegt dabei auf die Ausgaben für das Debuggen. Also fasse ich (fast) sämtliche Debugausgaben unter DebugPrint……() zusammen und bekomme die #define DEBUG Direktiven aus dem Sourcecode heraus. Zusätzlich mache ich dabei die Debugausgaben etwas übersichtlicher, da sie inzwischen schon recht umfangreich geworden sind.

Die geänderte Software:

/****************************************************************************
* Projekt – Messtechnik 1
* (c) 2017 softwareentwicklung-als-prozess.de
* Dokumentation s. Blog
***************************************************************************/
// Includes —————————————————————–
// LCD
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
// RTC
#include <TimeLib.h>
#include <DS1302RTC.h>
// Temp/Feuchte Sensor
#include <Adafruit_Sensor.h>
#include <DHT_U.h>
#include <DHT.h>
// Ethernet2
#include <Ethernet2.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 // in millisekunden

// 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
// GND pin -> Arduino Digital 33
// VCC pin -> Arduino Digital 35
#define DS1302_GND_PIN 33
#define DS1302_VCC_PIN 35

// Sensor Pins
// DHT11: GND pin -> Arduino Digital 45
// VCC pin -> Arduino Digital 47
// I/O pin -> Arduino Digital 49
#define DHT11_GND_PIN 45
#define DHT11_VCC_PIN 47
#define DHTPIN 49 // DHT11 data pin
#define DHTTYPE DHT11

// Fuer NTP
#define SEKUNDEN_PRO_TAG 86400L
#define SEKUNDEN_PRO_STUNDE 3600
#define SEKUNDEN_PRO_MINUTE 60
#define SEVENTY_YEARS 2208988800UL

// Sommerzeit check
#define SONNTAG (byte)1
#define MONTAG (byte)2
#define DIENSTAG (byte)3
#define MITTWOCH (byte)4
#define DONNERSTAG (byte)5
#define FREITAG (byte)6
#define SAMSTAG (byte)7

#define MAERZ (byte)3
#define APRIL (byte)4
#define MAI (byte)5
#define JUNI (byte)6
#define JULI (byte)7
#define AUGUST (byte)8
#define SEPTEMBER (byte)9
#define OKTOBER (byte)10

typedef enum JahresZeiten
{
SommerZeit,
WinterZeit
};

// Variablen —————————————————————–
// Zeitangaben
byte tag = (byte)0;
byte monat = (byte)0;
byte jahr = (byte)0;
byte stunde = (byte)0;
byte minut = (byte)0;
byte wtag = (byte)1; // Wochentag von 1=Sonntag bis 7=Samstag
// Fallback falls keine Aenderung gewuenscht
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 ———- Messbereich
byte temperatur = (byte)0; // 0 – 50 Grad Celsius
byte feuchte = (byte)0; // 20 – 80 Prozent relative Luftfeuchte
sensor_t sensor; // Sensortyp
sensors_event_t event; // Sensor Messwerte
uint32_t delayMS; // Sensor Wartezeit

// Ethernet MAC Adresse
byte mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x4f, 0x44};
// NTP
IPAddress ip(192, 168, 178, 1); // lokaler NTP Server
unsigned int localPort = 8888; // lokales port für UDP pakete
const int NTP_PACKET_SIZE = 48; // NTP Zeit information
byte packetBuffer[NTP_PACKET_SIZE]; // NTP paketpuffer

// 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 gedrueckt

// Cursorposition
byte curpos = (byte)CURSORMARGINLEFT;

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

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

// DHT11 Sensor
DHT_Unified dht(DHTPIN, DHTTYPE);

// Ethernet Client Library
EthernetClient Ether;

// UDP
EthernetUDP Udp;

// Funktionen —————————————————————
void setup()
{
DebugPrintInit();
DebugPrint(„Projekt Messtechnik1“);

// LCD
lcd.begin(16, 2); // Anzahl Spalten und Zeilen vom Display setzen
lcd.setBacklight(ON); // Beleuchtung einschalten
lcd.clear(); // erstmal alles loeschen
lcd.home(); // Cursor nach links oben
ActualizeDisplay(); // Werte ausgeben

// RTC
RTCActivate(); // RTC aktivieren
RTCCheckStatus(); // RTC Status einlesen
RTCRead(); // RTC einlesen
ActualizeDisplay(); // eingelesene Werte ausgeben
SaveTimeToFallback(); // aktuelle Zeit merken
RTCStart(); // RTC Clock starten

// DHT11
DHT11Activate(); // Temp-/Feuchtesensor aktivieren
dht.begin(); // Schnittstelle init
DHT11GetInfoTemperature(); // Sensorinformation einlesen
DHT11GetInfoHumidity(); // Sensor Messwerte einlesen
DebugPrint(„———-„);
delayMS = sensor.min_delay / 1000; // Wartezeit berechnen
temperatur = DHT11ReadTemperature(); // Temperaturwert
feuchte = DHT11ReadHumidity(); // relative Luftfeuchte
DebugPrintLongValueUnit(„Verzoegerungszeit: „,delayMS,“ ms“);
ActualizeDisplay(); // eingelesene Werte ausgeben

// Ethernet2
if (Ethernet.begin(mac) == 0)
{
DebugPrint(„Ethernet Fehler – DHCP nicht erfolgreich“);
}
else
{
DebugPrint(„- Ethernet aktiviert -„);
#ifdef DEBUG
Serial.print(„Die IP Adresse ist: „);
for (byte thisbyte = 0; thisbyte < 4; thisbyte++)
{
Serial.print(Ethernet.localIP()[thisbyte],DEC);
if (thisbyte < 3)
{
Serial.print(„.“);
}
}
Serial.println();
#endif
// NTP Abfrage
Udp.begin(localPort);
NTPsendpacket(ip); // Sende NTP paket zum Zeit Server
delay(1000); // Warte auf Antwort
DebugPrint(„- NTP Abfrage -„);
NTPGetTime(); // Antwort einlesen
RTCWrite(); // RTC mit neuer Zeit setzen
}
starttime = actualtime = millis(); // naechste Minute Wartezeit starten
DebugPrint(„*** Setup abgeschlossen ***“);
}

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

if ((actualtime – starttime) > MINUTE) // Eine Minute ist abgelaufen
{
DebugPrint(„– Minute abgelaufen: RTC und Messwerte einlesen“);
RTCRead(); // RTC einlesen
// Messwerte einlesen
temperatur = DHT11ReadTemperature(); // Temperaturwert
feuchte = DHT11ReadHumidity(); // relative Luftfeuchte
CursorBlinkAus(); // Cursor und Blinken aus
ActualizeDisplay(); // Werte ausgeben
buttonpressed = false; // kein Button gedrueckt
starttime = millis(); // Start fuer naechste Minute
RestoreFallbackToTime(); // keine neuen Werte uebernommen
} // 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 gedrueckt
{
selectbuttonpressed = false; // Select Taste fertig ausgewertet
RTCWrite(); // RTC mit neuer Zeit setzen
CursorBlinkAus(); // Cursor und Blinken aus
ActualizeDisplay(); // Werte ausgeben
curpos = (byte)CURSORMARGINLEFT; // Cursor auf Startposition
lcd.setCursor(curpos,0); // auf Startposition setzen
}
}

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

// Software – NTP Zeit einlesen ————————————————
void NTPGetTime(void) // aus der Beispielsoftware entnommen und angepasst
{
unsigned long highWord = 0ul;
unsigned long lowWord = 0ul;
unsigned long secsSince1900 = 0ul;
unsigned long epoch = 0ul;

if ( Udp.parsePacket() )
{
Udp.read(packetBuffer, NTP_PACKET_SIZE); // Paket empfangen und einlesen
highWord = word(packetBuffer[40], packetBuffer[41]);
lowWord = word(packetBuffer[42], packetBuffer[43]);
secsSince1900 = highWord << 16 | lowWord; // NTP Zeit
epoch = secsSince1900 – SEVENTY_YEARS;// Unix Zeit beginnt am 1. Jan 1970
stunde = ((epoch % SEKUNDEN_PRO_TAG) / SEKUNDEN_PRO_STUNDE) + 1; // hiesige Zeitzone ist UTC + 1
minut = (epoch % SEKUNDEN_PRO_STUNDE) / SEKUNDEN_PRO_MINUTE;
DebugPrintLongValue(„Sekunden seit dem 1. Januar 1900 = „,secsSince1900);
DebugPrintLongValue(„Unix Zeit = „,epoch);
#ifdef DEBUG
Serial.print(„UTC + 1 Zeit ist „); // UTC ist die Zeit am Greenwich Meridian (GMT)
Serial.print(stunde); // Ausgabe Stunde
Serial.print(‚:‘);
if ( ((epoch % SEKUNDEN_PRO_STUNDE) / SEKUNDEN_PRO_MINUTE) < 10 )
{
Serial.print(‚0‘); // In den ersten 10 minuten eine führende ‚0‘ ausgeben
}
Serial.println(minut); // Ausgabe Minuten
#endif
if (CheckSommerzeit() == SommerZeit)
{
DebugPrint(„Sommerzeit“);
stunde += 1;
}
else
{
DebugPrint(„Winterzeit“);
}
}
}

unsigned long NTPsendpacket(IPAddress address) // NTP Anfrage senden
{
memset(packetBuffer, 0, NTP_PACKET_SIZE); // set all bytes in the buffer to 0
// Initwerte fuer den NTP Request
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// bytes 4 bis 11: 8 bytes mit ‚0‘ fuer Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;

Udp.beginPacket(address, 123); //NTP Abfragen auf Port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}

// Software – Temperatur- und Luftfeuchte Sensor ——————————-
void DHT11Activate(void)
{
digitalWrite(DHT11_GND_PIN, LOW); // GND = 0 Volt
pinMode(DHT11_GND_PIN, OUTPUT);
digitalWrite(DHT11_VCC_PIN, HIGH); // VCC = +5 Volt
pinMode(DHT11_VCC_PIN, OUTPUT);
DebugPrint(„- DHT aktiviert -„);
delay(1000); // Warten auf Chip…
}

void DHT11GetInfoTemperature(void)
{
dht.temperature().getSensor(&sensor);
DebugPrint(„— Temperatur —„);
DebugPrint2(„Sensor: „,sensor.name);
DebugPrintValue(„Driver Ver: „,sensor.version);
DebugPrintLongHexValue(„Unique ID: „,sensor.sensor_id);
DebugPrintValueUnit(„Max Value: „,sensor.max_value,“ *C“);
DebugPrintValueUnit(„Min Value: „,sensor.min_value,“ *C“);
DebugPrintValueUnit(„Resolution: „,sensor.resolution,“ *C“);
}

void DHT11GetInfoHumidity(void)
{
dht.humidity().getSensor(&sensor);
DebugPrint(„— relative Luftfeuchte —„);
DebugPrint2(„Sensor: „,sensor.name);
DebugPrintValue(„Driver Ver: „,sensor.version);
DebugPrintLongHexValue(„Unique ID: „,sensor.sensor_id);
DebugPrintValueUnit(„Max Value: „,sensor.max_value,“ %“);
DebugPrintValueUnit(„Min Value: „,sensor.min_value,“ %“);
DebugPrintValueUnit(„Resolution: „,sensor.resolution,“ %“);
}

byte DHT11ReadTemperature(void)
{
byte retval = (byte)0;

delay(delayMS * 2); // Wartezeit einhalten
dht.temperature().getEvent(&event); // Temperatur einlesen
if (isnan(event.temperature))
{
DebugPrint(„DHT11 Temperatur Lesefehler!“);
}
else
{
DebugPrintValueUnit(„aktuelle Temperatur: „,event.temperature,“ *C“);
retval = byte((event.temperature + (float)0.5));
}
return(retval);
}

byte DHT11ReadHumidity(void)
{
byte retval = (byte)0;

delay(delayMS * 2); // Wartezeit einhalten
dht.humidity().getEvent(&event); // Luftfeuchte einlesen
if (isnan(event.relative_humidity))
{
DebugPrint(„DHT11 Luftfeuchte Lesefehler!“);
}
else
{
DebugPrintValueUnit(„relative Luftfeuchte: „,event.relative_humidity,“ %“);
retval = byte((event.relative_humidity + (float)0.5));
}
return(retval);
}

// Software – RTC ————————————————————–
void RTCActivate(void)
{
digitalWrite(DS1302_GND_PIN, LOW); // GND = 0 Volt
pinMode(DS1302_GND_PIN, OUTPUT);
digitalWrite(DS1302_VCC_PIN, HIGH); // VCC = +5 Volt
pinMode(DS1302_VCC_PIN, OUTPUT);
DebugPrint(„- RTC aktiviert -„);
delay(500); // Warten auf Chip…
}

void RTCCheckStatus(void)
{
if (RTC.haltRTC()) // Check RTC Clock Oscillator
{
DebugPrint(„RTC Clock steht“);
}
else
DebugPrint(„RTC Clock laeuft“);
if (RTC.writeEN()) // Check RTC Schreibschutz
DebugPrint(„RTC RAM Schreiben erlaubt“);
else
DebugPrint(„RTC RAM Schreibgeschuetzt“);
delay(2000); // Warten auf Chip…
}

void RTCStart(void)
{
RTC.haltRTC((uint8_t)0);
delay(2000);
}

void RTCStop(void)
{
RTC.haltRTC((uint8_t)1);
delay(2000);
}

void RTCSetWriteEnable(void)
{
RTC.writeEN((uint8_t)0);
}

void RTCClearWriteEnable(void)
{
RTC.writeEN((uint8_t)1);
}

void RTCRead(void)
{
tmElements_t tm;
uint8_t ret = (uint8_t)0;

ret = RTC.read(tm);
delay(2000); // Zeit zum Einlesen
if ((uint8_t)0 == ret)
{
DebugPrint(„RTC eingelesen“);
}
else
{
DebugPrint(„RTC Fehler beim Einlesen“);
}
tag = (byte)tm.Day;
monat = (byte)tm.Month;
// tmYearToY2k() wird hier benutzt um die Bibliotheksfunktion zu ueberlisten
// Die Bibliotheksfunktion ist fuer die Verwendung unter Linux geschrieben
// Ein Problem existiert fuer diese Library mit Jahren ueber 69, da intern nur von 0 – 99 funktioniert
jahr = (byte)tmYearToY2k(tm.Year);
stunde = (byte)tm.Hour;
minut = (byte)tm.Minute;
wtag = (byte)tm.Wday;
DebugPrintDatumZeit(tag,monat,jahr,stunde,minut,wtag);
}

void RTCWrite(void)
{
tmElements_t tm;
time_t tmp;
uint8_t ret = (uint8_t)0;

tm.Second = (uint8_t)0;
tm.Minute = minut;
tm.Hour = stunde;
tm.Day = tag;
tm.Month = monat;
// Y2kYearToTM() wird hier benutzt um die Bibliotheksfunktion zu ueberlisten
// Die Bibliotheksfunktion ist fuer die Verwendung unter Linux geschrieben
// Ein Problem existiert fuer diese Library mit Jahren ueber 69, da intern nur von 0 – 99 funktioniert
tm.Year = y2kYearToTm(jahr);
tm.Wday = wtag;
ret = RTC.write(tm);
delay(2000);
if((uint8_t)255 == ret)
{
DebugPrint(„RTC Fehler (WP not disabled)“);
}
else
{
DebugPrint(„RTC geschrieben!“);
}
}

// 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 Uebernehmen
rdbuttons = lcd.readButtons(); // Tasten einlesen
}
return(oldbuttons); // Tastenwerte Uebergeben
}

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 gedrueckt
}
CursorBlinkEin(); // Cursor und Blinken ein
if (butt & BUTTON_UP) // BUTTON UP gedrueckt
{
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 gedrueckt
{
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 gedrueckt
{
CursorBlinkAus(); // Cursor und Blinken aus
DebugPrint(„Select gedrueckt und Cursor aus“);
buttonpressed = false; // irgendeine Taste gedrueckt
selectbuttonpressed = true; // Select Taste gedrueckt
}
}
}

/****************************************************************************
* Sommerzeit erkennen
* (c) 2017 softwareentwicklung-als-prozess.de
* Dokumentation s. Blog
***************************************************************************/
JahresZeiten CheckSommerzeit(void)
{
JahresZeiten ret = WinterZeit;
// vom 1.4. bis 24.10. ist sicher Sommerzeit
switch(monat)
{
case APRIL:
case MAI:
case JUNI:
case JULI:
case AUGUST:
case SEPTEMBER:
ret = SommerZeit;
break;
case OKTOBER:
if ((byte)25 > tag)
{
ret = WinterZeit;
}
else
{
ret = SommerZeit;
}
}

// Die letzte Woche von Maerz und Oktober muss untersucht werden
if ((MAERZ == monat) || (OKTOBER == monat))
{
switch(tag)
{
case (byte)25:
switch(wtag)
{
case SONNTAG:
ret = OberhalbDiagonale();
break;

default:
ret = UnterhalbDiagonale();
break;
}
break;

case (byte)26:
switch(wtag)
{
case SONNTAG:
case MONTAG:
ret = OberhalbDiagonale();
break;

default:
ret = UnterhalbDiagonale();
break;
}
break;

case (byte)27:
switch(wtag)
{
case SONNTAG:
case MONTAG:
case DIENSTAG:
ret = OberhalbDiagonale();
break;

default:
ret = UnterhalbDiagonale();
break;
}
break;

case (byte)28:
switch(wtag)
{
case SONNTAG:
case MONTAG:
case DIENSTAG:
case MITTWOCH:
ret = OberhalbDiagonale();
break;

default:
ret = UnterhalbDiagonale();
break;
}
break;

case (byte)29:
switch(wtag)
{
case SONNTAG:
case MONTAG:
case DIENSTAG:
case MITTWOCH:
case DONNERSTAG:
ret = OberhalbDiagonale();
break;

default:
ret = UnterhalbDiagonale();
break;
}
break;

case (byte)30:
switch(wtag)
{
case SONNTAG:
case MONTAG:
case DIENSTAG:
case MITTWOCH:
case DONNERSTAG:
case FREITAG:
ret = OberhalbDiagonale();
break;

default:
ret = UnterhalbDiagonale();
break;
}
break;

case (byte)31:
switch(wtag)
{

default:
ret = OberhalbDiagonale();
break;
}
break;
}
}
return(ret);
}

JahresZeiten OberhalbDiagonale(void)
{
JahresZeiten ret = SommerZeit;

if(MAERZ == monat)
{
ret = SommerZeit;
}
if(OKTOBER == monat)
{
ret = WinterZeit;
}
return(ret);
}

JahresZeiten UnterhalbDiagonale(void)
{
JahresZeiten ret = SommerZeit;

if(MAERZ == monat)
{
ret = WinterZeit;
}
if(OKTOBER == monat)
{
ret = SommerZeit;
}
return(ret);
}

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();
DebugPrint(„Cursor ist aus“);
}

void CursorBlinkEin(void)
{
lcd.cursor();
lcd.blink();
DebugPrint(„Cursor ist an“);
}

// — Routinen zum Debuggen
void DebugPrintDatumZeit(byte ta, byte mo, byte ja, byte st, byte mi, byte wt)
{
#ifdef DEBUG
Serial.print(„Datum: „);
switch(wt)
{
case 1:
Serial.print(„Sonntag“);
break;
case 2:
Serial.print(„Montag“);
break;
case 3:
Serial.print(„Dienstag“);
break;
case 4:
Serial.print(„Mittwoch“);
break;
case 5:
Serial.print(„Donnerstag“);
break;
case 6:
Serial.print(„Freitag“);
break;
case 7:
Serial.print(„Samstag“);
break;
}
Serial.print(„, der „);
Serial.print(ta,DEC);
Serial.print(„.“);
Serial.print(mo,DEC);
Serial.print(„.20″);
Serial.print(ja,DEC);
Serial.print(“ Zeit: „);
Serial.print(st,DEC);
Serial.print(„:“);
if (mi < 10)
{
Serial.print(„0“);
}
Serial.println(mi,DEC);
#endif
}

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

void DebugPrint2(char *str1, char * str2)
{
#ifdef DEBUG
Serial.print(str1);
Serial.println(str2);
#endif
}

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

void DebugPrintLongValueUnit(char *str, unsigned long val, char *unit)
{
#ifdef DEBUG
Serial.print(str);
Serial.print(val,DEC);
Serial.println(unit);
#endif
}

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

void DebugPrintLongHexValue(char *str, unsigned long val)
{
#ifdef DEBUG
Serial.print(str);
Serial.println(val,HEX);
#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
}

// * Ende *

Links und Literaturhinweise

Algorithmus Sommerzeit

Die Ethernet2 Bibliothek
http://www.arduinolibraries.info/libraries/ethernet2

Die Beschreibung dazu
https://www.arduino.cc/en/Reference/Ethernet

NTP RFC
https://tools.ietf.org/html/rfc5905

Martin Fowler / Kent Beck
– Refactoring: Improving the Design of Existing Code

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.