Fehlermeldung nach dem validieren der empfangenen Daten
Wir haben nun die empfangenen Daten erfolgreich validiert somit können wir nun im nächsten Gang die Zeichenkette parsen und das Datum und die Uhrzeit extrahieren.
Um den Sketch jedoch übersichtlich zu halten wird das ganze zunächst in eine eigene Funktion ausgelagert welche als Rückgabewert ein Boolean hat. Ein Boolean kann zwei Status annehmen True & False. Die neue Funktion liefert also Boolean.True zurück wenn das lesen der Werte okay ist und Boolean.False wenn ein Fehler aufgetreten ist. (Die Fehlermeldungen werden weiterhin ausgegeben.)
char linebuf = {};
boolean readData;
void setup() {
//beginn der seriellen Kommunikation mit
//9600 baud
Serial.begin(9600);
}
void loop() {
readDataFromSerial();
if(readData){
boolean isParameterSet = parameterIsSet();
if(isParameterSet == true){
//Hier wird nun das Datum und die Uhrzeit geparst.
Serial.println("parsen des Datums und der Uhrzeit");
}
}
}
void readDataFromSerial(){
//Char Array für das Speichern der empfangenen Daten.
linebuf = {};
//Zähler für die Zeichen
byte counter = 0;
readData = false;
//Wenn Daten verfügbar sind dann...
if (Serial.available() > 0) {
delay(250);
readData = true;
//solange Daten von der seriellen Schnittstelle
//empfangen werden...
while(Serial.available()){
//speichern der Zeichen in dem Char Array
linebuf = Serial.read();
if(counter counter++;
}
}
} else {
readData = false;
}
return linebuf;
}
boolean parameterIsSet(){
boolean result = true;
boolean foundKeyWord = false;
boolean keyWordIsOnPosZero = false;
//Variable mit Pointer zu einem Speicherbereich
char *s;
//zuweisen eines Wertes (es wird kein neuer Speicher belegt)
s = strstr(linebuf,"set");
//Wenn ein Wert hinterlegt wurde dann...
if(s){
foundKeyWord = true;
//Ermitteln der Position durch Pointer Substraction
int pos = s-linebuf;
//Wenn die Zeichenkette "set" am Anfang steht dann...
if(pos == 0){
keyWordIsOnPosZero = true;
}
}
if(!foundKeyWord || !keyWordIsOnPosZero){
result = false;
Serial.println("!! Fehler !!");
//Wenn das Schlüsselwort "set" nicht gefunden wurde...
if(!foundKeyWord){
Serial.println("Das Schlüsselwort \"set\" wurde nicht gefunden!");
}
//Wenn das Schlüsselwort "set" nicht an Position 0 steht, dann...
if(!keyWordIsOnPosZero){
Serial.print("Das Schlüsselwort \"set\" steht nicht an Position 0");
Serial.print(" der Zeichenkette ");
}
}
return result;
}
parsen von Datum & Uhrzeit
definieren des Datumsformats
Bevor wir mit dem parsen des Datums und der Uhrzeit beginnen, müssen wir zunächst definieren in welchem Format dieses geliefert werden muss. Da ich aus Deutschland komme und die meisten Besucher / Betrachter meines Blogs aus eben Deutschland sind, möchte ich erläutern wie man das Format TT.MM.JJJJ HH:mm:SS parst.
Wobei
TT - für den Tag mit ggf. führender 0 steht, (min. 00, max. 31)
MM - für den Monat mit ggf. führender 0 steht, (min. 01, max. 12)
JJJJ - für das Jahr in 4 stellig steht, (min. 1900, max. 9999)
HH - für die Stunde mit ggf. führender 0 steht, (min. 00, max. 23)
mm - für die Minute mit ggf. führender 0 steht, (min. 00, max. 59)
SS - für die Sekunde mit ggf. führende 0 steht, (min. 00, max. 59)
Das Trennzeichen für Tag,Monat und Jahr ist ein Punkt und für die Uhrzeit der Doppelpunkt.
char linebuf = {};
boolean readData;
int t,mo, j, st, mi, s;
void setup() {
//beginn der seriellen Kommunikation mit
//9600 baud
Serial.begin(9600);
}
void loop() {
readDataFromSerial();
//Wenn Daten gelesen wurden dann...
if(readData){
//prüfen ob in den gelesenen Daten das Schlüsselwort "set" vorkommt,
//und das Schlüsselwort an erster stelle steht, dann...
boolean isParameterSet = parameterIsSet();
if(isParameterSet == true){
//Hier wird nun das Datum und die Uhrzeit geparst.
String line = linebuf;
//den Zeitstempel aus dem String extrahieren,
//dieser beginnt bei der Position 4
String timestamp = line.substring(4);
//prüfen ob der Zeitstempel im richtigen Format ist
boolean isTimestampCorrect = timestampIsCorrect(timestamp);
//wenn der Zeitstempel korrekt ist dann soll dieser auf die RTC geschrieben werden.
if(isTimestampCorrect){
}
}
}
}
boolean timestampIsCorrect(String timestamp){
boolean result = true;
//Der Zeitstempel muss 19 Zeichen lang sein.
if(timestamp.length() == 19){
//Das Datum muss inkl. den Punkten 10 Zeichen lang sein
String datum = timestamp.substring(0,10);
String tag = datum.substring(0,2);
String monat = datum.substring(3,5);
String jahr = datum.substring(6,10);
//Die Uhrzeit beginnt ab dem 11 Zeichen aus dem Zeitstempel
String uhrzeit = timestamp.substring(11);
String stunde = uhrzeit.substring(0,2);
String minute = uhrzeit.substring(3,5);
String sekunde = uhrzeit.substring(6);
//prüfen ob in den Variablen tag, monat, jahr, stunde, minute, sekunde nur Zahlen sind
if(!isNummeric(tag) || !isNummeric(monat) || !isNummeric(jahr)
|| !isNummeric(stunde) || !isNummeric(minute) || !isNummeric(sekunde)){
result = false;
}
//Wenn das Format korrekt ist, d.h. zbsp.
//der Tag darf nicht weniger als 0 Stunden und nicht mehr als 23 Stunden haben,
//die Minute darf nicht weniger als 0 Minuten haben und nicht mehr als 59, usw.
if(!isFormatCorrect(tag.toInt(), monat.toInt(), jahr.toInt(), stunde.toInt(), minute.toInt(), sekunde.toInt() )){
//Wenn das Format nicht korrekt ist dann wird "false" zurück geliefert.
result = false;
} else {
//Wenn das Format korrekt ist dann sollen die Werte aus den Strings in die Felder geschrieben werden.
t = tag.toInt();
mo = monat.toInt();
j = jahr.toInt();
st = stunde.toInt();
mi = minute.toInt();
s = sekunde.toInt();
}
} else {
Serial.println("Der Zeitstempel muss 19 Zeichenlang sein.");
result = false;
}
if(result == false){
Serial.print("Der übergebene Zeitstempelt ist nicht korrekt. ");
Serial.println("Beispiel 24.05.2019 19:35:34");
}
return result;
}
boolean isFormatCorrect(int tag, int monat, int jahr, int stunde, int minute, int sekunde ){
boolean result = true;
if(tag 31){
result = false;
}
if(monat 12){
result = false;
}
if(jahr 9999){
result = false;
}
if(stunde 23){
result = false;
}
if(minute 59){
result = false;
}
if(sekunde 59){
result = false;
}
return result;
}
//prüfen ob in dem Parameter chars nur Zahlen enthalten sind
boolean isNummeric(String chars){
boolean result = true;
for(int i=0;i 0) {
delay(250);
readData = true;
//solange Daten von der seriellen Schnittstelle
//empfangen werden...
while(Serial.available()){
//speichern der Zeichen in dem Char Array
linebuf = Serial.read();
if(counter counter++;
}
}
} else {
readData = false;
}
return linebuf;
}
boolean parameterIsSet(){
boolean result = true;
boolean foundKeyWord = false;
boolean keyWordIsOnPosZero = false;
//Variable mit Pointer zu einem Speicherbereich
char *s;
//zuweisen eines Wertes (es wird kein neuer Speicher belegt)
s = strstr(linebuf,"set");
//Wenn ein Wert hinterlegt wurde dann...
if(s){
foundKeyWord = true;
//Ermitteln der Position durch Pointer Substraction
int pos = s-linebuf;
//Wenn die Zeichenkette "set" am Anfang steht dann...
if(pos == 0){
keyWordIsOnPosZero = true;
}
}
if(!foundKeyWord || !keyWordIsOnPosZero){
result = false;
Serial.println("!! Fehler !!");
//Wenn das Schlüsselwort "set" nicht gefunden wurde...
if(!foundKeyWord){
Serial.println("Das Schlüsselwort \"set\" wurde nicht gefunden!");
}
//Wenn das Schlüsselwort "set" nicht an Position 0 steht, dann...
if(!keyWordIsOnPosZero){
Serial.print("Das Schlüsselwort \"set\" steht nicht an Position 0");
Serial.print(" der Zeichenkette ");
}
}
return result;
}
Wir haben nun die Werte für Tag, Monat, Jahr, Stunde, Minute und Sekunde in den Felder t, mo, j, st, mi, s.
Im nächsten Schritt müssen wir diese Werte auf die RealTimeClock schreiben. Da diese Funktion auch für die 2. Lösung benötigt wird möchte ich zunächst erläutern wie man einen Zeitstempel aus einem deployten Sketch auslesen kann. Hier gehts zur Funktion zum schreiben eines Zeitstempels auf die RTC.
lesen eines Zeitstempels von einem deployten Sketch
Wenn ein Sketch auf den Arduino hochgeladen wird (umgangssprachlich als deployment bezeichnet), dann wird zusätzlich ein Timestamp abgelegt, dieser entspricht bis auf wenige Sekunden dem aktuellen Zeitstempel. Das Problem ist nur dass, der Sketch einmal ausgeführt und die Zeit sofort auf die RTC geschrieben werden muss, danach darf dieses nicht erneut gestartet werden.
Daher wird das ganze nicht in der loop ausgeführt sondern im Setup somit wird sichergestellt dass, diese Funktion nur einmal beim starten ausgeführt wird.
Für den nachfolgenden Sketch bedienen wir uns zweier Konstanten "__DATE__" & "__TIME__" diese werden mit dem Zeitstempel des Uploads setzt.
Das Datum ist im Format "Jun 30 2019" somit müssen wir die engl. Abkürzungen für die Monate gegen den Monatsnamen prüfen. Diese Prüfung mache ich mit einer einfachen Schleife über die Monate und wenn diese Werte gleich sind breche ich die Schleife ab und merke mir den Index. Zu diesem Index muss jedoch noch eine Zahl drauf addiert werden, denn Arrays beginnen immer bei 0 jedoch die Monate bei 1.
#include //Bibliothek für die kommunikation mit der RTC
#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC DS3231
//Variablen für die Werte aus Datum und Uhrzeit
int tag, monat, jahr;
int stunde, minute, sekunde;
//Array mit den abkürzungen für die Monate
const String months = {"Jan", "Feb", "Mar", "Apr","May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
void setup() {
//Kommunikation über die Wire.h bibliothek beginnen.
Wire.begin();
//beginn der seriellen Kommunikation mit 9600baud
Serial.begin(9600);
//parsen des Datums
parseDate(__DATE__);
//parsen der Uhrzeit
parseTime(__TIME__);
//Ausgeben des Zeitstempels auf dem seriellen Monitor.
char timestamp;
sprintf(timestamp,"%02d.%02d.%4d %02d:%02d:%02d",tag,monat,jahr,stunde,minute,sekunde);
Serial.println(timestamp);
rtcWriteTime();
}
void parseDate(String date){
String mo = date.substring(0,3);
String t = date.substring(4,6);
String j = date.substring(7);
tag = t.toInt();
for(int i=0;i
Read the full article