Naja, ich find das schon ziemlich komisch, dass ein Halbbit nicht bis F geht. Aber, Du hast Recht, dafür ist es tatsächlich leicht verständlich.
Hier wie versprochen der Sketch für die Einstellung einer RTC nach der GPS-Zeit:
/* Info: This scetch works on Arduino Nano V3.0
* Pin connections:
* Arduino Pin "5V" -> RTC MCP79410 Pin "Vcc" and -> GPS-Breakout Pin "VIN"
* Arduino PIN "GND" -> RTC MCP79410 Pin "GND" and -> GPS-Breakout Pin "GND"
* Arduino PIN "D2" -> GPS-Breakout Pin "RX"
* Arduino PIN "D3" -> GPS-Breakout Pin "TX"
* Arduino PIN "A4" -> RTC MCP79410 Pin "SDA"
* Arduino PIN "A5" -> RTC MCP79410 Pin "SCL"
* Auf dem Adruino Nano V3.0 gibt es zwei "GND"-Pins - man kann jeden nehmen.
*** Special thanks to Doc_Arduino, agmue & Serenifly @ forum.arduino.cc ***/
// *** GPS section ***
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3,2);
#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
#define PMTK_SET_NMEA_OUTPUT_RMC "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"
char zeichen;
String nmeaString;
String gpsTimeStamp = "1";
unsigned int nmeaStringLaenge;
int ssInt;
int mmInt;
int hhInt;
int ddInt;
int mMInt;
int yyInt;
int ssWait;
// *** RTC section ***
#include <Wire.h>
String rtcTimeStamp = "2";
void setup() {
// *** GPS section ***
while (!Serial); // Prüfen, ob diese Zeile gelöscht werden kann.
Serial.begin(9600);
mySerial.begin(9600);
delay(2000);
mySerial.println(PMTK_SET_NMEA_OUTPUT_RMC);
mySerial.println(PMTK_SET_NMEA_UPDATE_1HZ);
// *** RTC section ***
Wire.begin();
delay(2000);
}
void loop() {
// *** GPS section ***
nmeaString = getNMEAString();
nmeaStringLaenge = nmeaString.length();
// *** Zeit & Datum aus String extrahieren ***
if (nmeaString.substring(1,6) == "GPRMC") {
ssInt = nmeaString.substring(11,13).toInt();
mmInt = nmeaString.substring(9,11).toInt();
hhInt = nmeaString.substring(7,9).toInt();
ddInt = nmeaString.substring(nmeaStringLaenge - 15,nmeaStringLaenge - 13).toInt();
mMInt = nmeaString.substring(nmeaStringLaenge - 13,nmeaStringLaenge - 11).toInt();
yyInt = nmeaString.substring(nmeaStringLaenge - 11,nmeaStringLaenge - 9).toInt();
// Plausibilitätsschranke
if (
yyInt > 15 && // after 2015
yyInt < 20 && // before 2020
mMInt > 0 && // higher 0
mMInt < 13 && // beyond 13 months/year
ddInt > 0 && // higher 0
ddInt < 32 && // beyond 32 days/month
hhInt < 24 && // beyond 24 hours/day
mmInt < 60 && // beyond 60 minutes/hour
ssInt < 60 // beyond 60 seconds/minute
) {
ssWait = 60-ssInt;
Serial.print("Plausibilitaetsschranke ueberwunden. \n Wartezeit: ");
Serial.print(ssWait);
Serial.println(" Sekunden.");
delay(ssWait * 1000);
mmInt = mmInt +1;
// *** RTC section ***
WriteRTCByte(0,0); //stop RTC
WriteRTCByte(1,decToBCD(mmInt)); //minute
WriteRTCByte(2,decToBCD(hhInt)); //hour
// WriteRTCByte(3,0x06); //day of the week = 1(Monday) & VBAT = 1 (Wochentag ermitteln?!)
WriteRTCByte(4,decToBCD(ddInt)); //day of the month
WriteRTCByte(5,decToBCD(mMInt)); //month
WriteRTCByte(6,decToBCD(yyInt)); //year
WriteRTCByte(0,0x80); //start RTC, second = 00
} else {
Serial.print("Plausibilitaetstest nicht bestanden: ");
Serial.println(nmeaString);
}
}
nmeaString = getNMEAString();
nmeaStringLaenge = nmeaString.length();
// *** Zeit & Datum aus String extrahieren ***
if (nmeaString.substring(1,6) == "GPRMC") {
gpsTimeStamp = "20";
gpsTimeStamp = gpsTimeStamp
+ nmeaString.substring(nmeaStringLaenge - 11,nmeaStringLaenge - 9) + "."
+ nmeaString.substring(nmeaStringLaenge - 13,nmeaStringLaenge - 11) + "."
+ nmeaString.substring(nmeaStringLaenge - 15,nmeaStringLaenge - 13) + " "
+ nmeaString.substring(7,9) + ":"
+ nmeaString.substring(9,11) + ":"
+ nmeaString.substring(11,13);
rtcTimeStamp = "20";
rtcTimeStamp = rtcTimeStamp
+ ReadRTCData(6,8) + "."
+ ReadRTCData(5,5) + "."
+ ReadRTCData(4,6) + " "
+ ReadRTCData(2,6) + ":"
+ ReadRTCData(1,7) + ":"
+ ReadRTCData(0,7);
// Serial.println(nmeaString);
Serial.println("RTC time: " + rtcTimeStamp + "\nGPS time: " + gpsTimeStamp);
if (rtcTimeStamp == gpsTimeStamp) {
Serial.println("RTC adjustment sucessfully finished.\nSystem halted for 60 sec.\nPlease switch off!");
Serial.println(nmeaString);
delay(60000);
}
}
}
// *** function section ***
// function to write a byte to RTC register
void WriteRTCByte(const unsigned char adress, const unsigned char data) {
Wire.beginTransmission(0x6f);
Wire.write(adress);
Wire.write(data);
Wire.endTransmission();
}
// function to read a byte from RTC register
unsigned char ReadRTCByte(const unsigned char adr) {
unsigned char data;
Wire.beginTransmission(0x6f);
Wire.write(adr);
Wire.endTransmission();
Wire.requestFrom(0x6f,1);
while (Wire.available()) data=Wire.read();
return data;
}
// function to read data from RTC register
String ReadRTCData(const unsigned char adr, const unsigned char validbits) {
unsigned char hexaDezimalZahlAlsString = ReadRTCByte(adr) & 0xff >> (8 - validbits);
String dezimalZahlAlsString = String(hexaDezimalZahlAlsString,HEX);
if (hexaDezimalZahlAlsString < 10)
dezimalZahlAlsString = "0" + dezimalZahlAlsString;
return dezimalZahlAlsString;
}
// function to convert binary coded decimal to an integer
byte bcdToDec(byte bcdValue) {
return ((bcdValue/16*10) + (bcdValue%16));
}
// function to convert an integer to binary coded decimal
byte decToBCD(byte decValue) {
return ((decValue/10*16) + (decValue%10));
}
// function to read a NMEA-String from GPS device
// return is the NMEA string or a String contains "error"
String getNMEAString() {
String _NMEAString = "$";
char _Zeichen;
byte _CheckSumCalculated = 0;
boolean _TransferSwitch = true;
boolean _CheckSumCalculatorSwitch = false;
boolean _StartRecord = false;
unsigned int _NMEAStringLaenge;
while (_TransferSwitch) {
if (mySerial.available()) {
_Zeichen = mySerial.read();
if (_Zeichen == '
Ein kleiner bug ist immernoch drin: Das Programm rechnet aus, bis die nächste Minute voll ist und fährt dann erst mit der Einstellung der Zeit fort. Das musste ich so machen, weil die Sekunden nicht einstellbar sind. Wenn die Wartezeit länger als etwa 30 s beträgt, dann bleibt das Programm hängen. Hab nicht rausgekriegt, warum. Mit einem Reset zur rechten Zeit geht's aber.) {
_StartRecord = ! _StartRecord;
_CheckSumCalculatorSwitch = true;
if (! _StartRecord) {
_TransferSwitch = false;
}
} else {
if (_StartRecord) {
_NMEAString = _NMEAString + _Zeichen;
}
if (_Zeichen == '*') {
_CheckSumCalculatorSwitch = false;
}
if (_CheckSumCalculatorSwitch) {
_CheckSumCalculated = _CheckSumCalculated ^ _Zeichen; // calculate XOR checksum
}
}
}
}
// NMEA-String qualifizieren und bei positiver Bewertung übergeben
_NMEAStringLaenge = _NMEAString.length();
if (_NMEAString.substring(_NMEAStringLaenge - 4,_NMEAStringLaenge - 2).toInt() == String(_CheckSumCalculated,HEX).toInt()) {
return _NMEAString;
} else {
return "error";
}
}
Ein kleiner bug ist immernoch drin: Das Programm rechnet aus, bis die nächste Minute voll ist und fährt dann erst mit der Einstellung der Zeit fort. Das musste ich so machen, weil die Sekunden nicht einstellbar sind. Wenn die Wartezeit länger als etwa 30 s beträgt, dann bleibt das Programm hängen. Hab nicht rausgekriegt, warum. Mit einem Reset zur rechten Zeit geht's aber.