Präzise Zeitmessung: DS3231 RTC mit GPS auf Arduino Nano synchronisieren
Komponenten und Materialien
| Bauteil | Menge | Hinweise |
|---|---|---|
| Arduino Nano R3 | 1 | |
| DS3231 RTC-Modul | 1 | High Precision |
| NEO-6M GPS-Modul | 1 | |
| Bidirektionaler Level-Shifter | 1 | Für 3,3V GPS an 5V Arduino |
| LCD 16×2 Display | 1 | |
| I2C LCD Backpack | 1 | Adresse 0x3F (nicht Standard 0x27!) |
| Steckverbinder (verschiedene) | 1 Set | 15/6/5/4-polig, Stiftleisten |
| Stripboard (24×37) | 1 | |
| Widerstand 4,7 kΩ | 2 | I2C Pull-Ups |
| Taster (momentan) | 1 | Zum Synchronisieren |
Projektbeschreibung
Mein DS3231 lief ungenau. Das Aktualisieren per Compile-Zeit (Systemzeit) war unpräzise, da Kompilieren und Hochladen durch andere Prozesse verzögert wurden.
Da GPS extrem präzise UTC-Zeit und -Datum liefert, entschloss ich mich, den DS3231 damit zu synchronisieren.
Schaltung
LCD Backpack (I2C) an Arduino:
- GND → GND
- VCC → 5V
- SDA → A4 (SDA)
- SCL → A5 (SCL)
DS3231 an Arduino (I2C, parallel zum LCD):
- GND → GND
- VCC → 5V
- SDA → A4
- SCL → A5
Level-Shifter (Arduino-Seite):
- 5V → 5V
- GND → GND
- D3 → Bus
- D4 → Bus
NEO-6M GPS (Level-Shifter-Seite):
- 3V → VCC
- GND → GND
- Bus → TXD (endet an D3)
- Bus → RXD (endet an D4)
Taster:
- Einer Pin → D9
- Anderer Pin → GND
Stromversorgung
Über USB-Kabel.
Software
99 % der Software ist das parsing.ino-Beispiel der Adafruit GPS Library. Ich fügte Code hinzu, um das extrahierte GPS-Datum und -Uhrzeit an den DS3231 zu übergeben, sowie Code zur Anzeige der DS3231-Zeit auf dem LCD.
Verwendete Bibliotheken
- Adafruit GPS Library v1.0.3
- RTCLib (Adafruit) v1.2.0
- NewLiquidCrystal (für I2C LCD Backpack)
Bedienung
- Gerät einschalten. LCD zeigt aktuelle DS3231-Zeit.
- Warten, bis GPS ein Signal hat (Lock).
- Taster drücken → Zeit per GPS setzen.
- LCD zeigt neue Zeit.
Einschränkungen & Besonderheiten
- GPS-Lock dauert: Keine Anzeige, ob Lock erreicht. Ohne Lock wird DS3231 auf 2000-0-0 / 0:0:0 gesetzt. Rote LED am GPS blinkt → Lock wahrscheinlich (kann indoors 10+ Min. dauern).
- DS3231 Pufferbatterie: War zunächst leer. Nach Laden akzeptierte er GPS-Daten und lief korrekt weiter.
- GPS-Modul Spannung: Board war nur als „NEO 6M“ beschriftet. Datasheet sagt ~3V. Level-Shifter verwendet. Ein 4A2D-Chip (Spannungsregler) war auf dem Board – aber nicht garantiert, dass Signalleitungen gepegelt sind.
- Empfang indoors: Variiert stark. LCD ermöglicht mobiles Testen draußen.
- LCD I2C-Adresse: Meines ist 0x3F (Standard oft 0x27). Bei leerem Display Adresse ändern.
- RTCLib Eigenheit: Setzt Zeit/Datum, aber nicht den Wochentags-Register. Wochentag wird per Formel aus Datum berechnet (schaltjahrsicher).
- UTC vs. Ortszeit: Für meine Zeitzone keine Umrechnung nötig. Andernfalls Code selbst ergänzen.
Referenzen
[1] u-blox NEO-6 DataSheet: PDF
Code
// DS3231 per GPS setzen - basiert auf Adafruit GPS parsing.ino Beispiel
#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 RTC;
char daysOfTheWeek[7][12] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
// LCD
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Adresse 0x3F!
// Taster
#define button 9
// GPS
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2); // RX, TX (nach Level-Shifter)
Adafruit_GPS GPS(&mySerial);
#define GPSECHO false
boolean usingInterrupt = false;
void useInterrupt(boolean);
void setup() {
Serial.begin(115200);
Serial.println("Adafruit GPS library basic test!");
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); // RMC + GGA
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz Update
GPS.sendCommand(PGCMD_ANTENNA); // Antennenstatus
useInterrupt(true); // Timer0 Interrupt für GPS-Parsing
delay(1000);
mySerial.println(PMTK_Q_RELEASE); // Firmware-Version
lcd.begin(16,2);
lcd.backlight();
lcd.clear();
pinMode(button, INPUT_PULLUP);
}
// Timer0 Interrupt (1 ms) für GPS-Daten lesen
SIGNAL(TIMER0_COMPA_vect) {
char c = GPS.read();
#ifdef UDR0
if (GPSECHO && c) UDR0 = c;
#endif
}
void useInterrupt(boolean v) {
if (v) {
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
usingInterrupt = true;
} else {
TIMSK0 &= ~_BV(OCIE0A);
usingInterrupt = false;
}
}
uint32_t timer = millis();
static bool second_time_round = false;
void loop() {
if (!usingInterrupt) {
char c = GPS.read();
if (GPSECHO && c) Serial.print(c);
}
if (GPS.newNMEAreceived()) {
if (!GPS.parse(GPS.lastNMEA())) return;
}
if (timer > millis()) timer = millis();
// Taster gedrückt? (LOW-aktiv durch Pull-Up)
if (!digitalRead(button)) {
// DS3231 setzen (RTCLib setzt keinen Wochentag-Register!)
RTC.adjust(DateTime(GPS.year, GPS.month, GPS.day, GPS.hour, GPS.minute, GPS.seconds));
lcd.clear();
lcd.setCursor(2,0);
lcd.print("Pressed set");
delay(5000);
lcd.clear();
}
// Aktuelle Zeit von DS3231 anzeigen
DateTime now = RTC.now();
lcd.setCursor(4,0);
lcd.print(now.year(), DEC); lcd.print('/');
lcd.print(now.month(), DEC); lcd.print('/');
lcd.print(now.day(), DEC); lcd.print(' ');
lcd.setCursor(4,1);
lcd.print(now.hour(), DEC); lcd.print(':');
lcd.print(now.minute(), DEC); lcd.print(':');
lcd.print(now.second(), DEC); lcd.print(" ");
}
Schaltpläne
Herstellungsprozess
- Gewindestifte (Set Screws) erklärt: Design, Unterschiede und Anwendungen
- Ein bleibendes Vermächtnis hinterlassen: Authentische Führung für eine bessere Zukunft
- SMRP veröffentlicht standardisierten KPI-Satz für Wartungs- & Zuverlässigkeitsprofis
- Java 10 Entwicklungsumgebung einrichten: Installation, PATH & IDEs
- Geodreiecke (Set Squares): Zweck, Typen & Anwendung im technischen Zeichnen
- Flachschleifen: Traditionelle Techniken für Präzision
- Warum ein Box-Way CNC-Drehmaschine die optimale Wahl für Präzision & Performance ist
- Stanzensets entmystifiziert: Ein umfassender Leitfaden
- Linearführungs-CNC-Drehmaschinen: Präzision, Geschwindigkeit und Leichtbau-Produktion
- Der ultimative Leitfaden zur Wahl des richtigen Mechaniker-Werkzeugsatzes