![]() |
Raspberry-Pi-Projekte: Real Time ClockProf. Jürgen Plate, Jonas Goll, Tobias Müller, Xiao Wang |
Wenn der Raspberry Pi mit dem Netzwerk verbunden ist, muss man sich um das Stellen der Uhr keine Gedanken machen, denn von Haus aus läuft der Network Time Daemon (ntp), der für das Abrufen der korrekten Uhrzeit und das Stellen der internen Uhr sorgt. Nur, wenn der RasPi keine Verbindung nach außen hat, muss man sich um die korrekte Uhrzeit kümmern.
Der Raspberry Pi besitzt keine integrierte Real Time Clock (RTC) wie ein PC. Damit er über die aktuelle Uhrzeit verfügt, muss er entweder die Uhrzeit über eine Netzwerkverbindung einlesen oder er benötigt eine lokale Uhr. Dieses Projekt versorgt den Rechner mit einer autonomen Uhr. Nach jedem Systemstart wird die Uhrzeit aus der RTC ausgelesen und als Systemzeit verwendet. Die RTC befindet sich auf einer eigenen Platine und wird per I2C integriert.
Dieser Baustein ist eine Echtzeituhr, die man über die I2C-Schnittstelle ansprechen kann und die batteriegepuffert weiterläuft, wenn der RasPi abgeschaltet ist. Die Genauigkeit ist nicht so überragend, Abweichungen von 1-2 Sekunden in 24 Stunden sind möglich (abhängig von Temperatur und Quarz). Bei großen Temperaturschwankungen sind die Abweichungen noch um einiges größer. An die RTC wird vom Raspberry Pi eine möglichst exakte Zeit übertragen. Diese Uhreit wird nun von der RTC mit Hilfe des des internen Quarzoszillators aktualisiert. Bei Bedarf ( z. B. beim Hochfahren des RasPi) wird die Zeit abgefragt und als Systemzeitgespeichert - so wie das beim PC schon seit Jahrzehnten der Fall ist. Die Batterie soll nach Datenblatt bis zu 10 Jahre lang halten. In den Registern der RTC stehen die Uhrzeit, der Wochentag und das Datum. Die einzelnen BCD-Werte können über die folgende Adressen ausgelesen werden.
| Adresse | Inhalt | Beschreibung |
|---|---|---|
| 0x00 | Sekunden und CH-Bit | Bits 0 - 6: Sekunden (0..59) Bit 8: Uhr ein- und ausschalten |
| 0x01 | Minuten | Bits 0 - 6: Minuten (0..59) |
| 0x02 | Stunden | Bits 0 - 6: Stunden; 12/24h umschaltbar |
| 0x03 | Wochentag | Bits 0 - 2: Wochentag (0..7) |
| 0x04 | Tag | Bits 0 - 5: Tag (0..31) |
| 0x05 | Monat | Bits 0 - 4: Monat (0..12) |
| 0x06 | Jahr | Bits 0 - 7: Jahr (0..99) |
| 0x07 | Einstellungen | SQW-Output einstellen |
| 0x08 – 0x3F | RAM | 56 x 8 Bit |
Bem Sekundenregister ist darauf zu achten, dass das MSB (CH Bit) zum Ein- und Ausschalten der Uhr dient. Ist CH = 1, Stoppt der DS1307. Dieses Bit sollte beim Schreiben einer neuen Uhrzeit stets auf 1 gesetzt sein. Nachdem alle Werte gespeichert wurden, wird es zusammen mit der Sekundenangabe wieder auf 0 gesetzen und somit die RTC wieder eingeschaltet. Beim Auslesen der Sekunde muss das MSB natürlich ignoriert werden.
Es gibt diverse Break-Out-Boards mit dem DS1307 im Handel, wobei die meisten die I2C-Anschlüsse direkt zum Raspberry Pi führen. Die Pull-Up-Widerstände auf dem RasPI-Board sorgen für die korrekte High-Spannung von 3.3 V. Da die Projektgruppe sich nicht sicher war, ob das auch bei zukünftigen Versionen so bleiben wird, ist eine eigene Schaltung mit Board entwickelt worden, welche aktive Pegelwandler enthält:
Die entsprechenden Eagle-Dateien stehen zur Verfügung (siehe Links weiter unten). Der Anschluss der Platine erfolgt am Raspberry Pi an +5 V (Pin 2), +3,3 V (Pin 1), GND (Pin 6), SDA (Pin 3) und SCL (Pin 5). Siehe auch I2C-Konfiguration. Im folgenden wird davon ausgegangen, dass die Module i2c_bcm2708 und i2c_dev laden geladen sind. Ein erster Test kann mit den I2C-Tools mit Root-Rechten (sudo su) erfolgen:
i2cdetect -l i2cdetect -y 1Die RTC muss auf Adresse 0x68 sichtbar sein. Nun können Sie versuchen, einige Register auszulesen, z. B.:
i2cget -y 1 0x68 0 # Sekunde i2cget -y 1 0x68 1 # Minute i2cget -y 1 0x68 2 # StundeWenn das geklappt hat, ist schon mal alles in Butter. Jetzt kann man schon per Programm auf die Uhr zugreifen, wie das folgende Beispiel in C zeigt. Es genügen dabei die normalen Dateioperationen, die der I2C-Treiber bereitstellt. Compiliert wird das Programm mit dem Kommando gcc -Wall -o ds1307 ds1307.c.
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* Puffer fuer die RTC-Daten */
#define BUFSIZE 7
/* Verwende I2C 1 */
#define I2CADDR "/dev/i2c-1"
/* defined in <linux/i2c-dev.h> */
#define I2C_SLAVE 0x703
/* Adresse des RTC-Chips */
#define RTC 0x68
int main()
{
int Device; /* Device-Handle */
char Date[BUFSIZE]; /* Datenpuffer */
int i;
/* I2C aktivieren */
if ((Device = open(I2CADDR, O_RDWR)) < 0)
{
printf("I2C-Modul kann nicht geladen werden!\n");
return -1;
}
/* Port und Adresse setzen */
if (ioctl(Device, I2C_SLAVE, RTC) < 0)
{
printf("RTC-Deviceadresse wurde nicht gefunden!\n");
exit(1);
}
/* Pointer auf Adresse 0 (Startadresse) setzen */
Date[0] = 0x00;
if(write(Device, Date, 1) != 1)
{
printf("Fehler beim Schreiben der Daten!\n");
return -1;
}
/* Uhrzeit einlesen */
if (read(Device, Date, BUFSIZE) != BUFSIZE)
{
printf("Fehler beim Lesen der Daten!\n");
return -1;
}
else
{
/* Werte von BCD in Dezimal umwandeln */
for(i = 0; i < BUFSIZE; i++)
{
Date[i] = (Date[i] & 0x0f) + 10 * (Date[i] >> 4);
}
/* Ausgabe von Uhrzeit und Datum */
printf("\n");
printf("Uhrzeit: %02d:%02d:%02d\n", Date[2],Date[1],Date[0]);
printf("Datum: %02d.%02d.%04d\n", Date[4],Date[5],Date[6] + 2000);
switch(Date[3])
{
case 1: printf("Sonntag"); break;
case 2: printf("Montag"); break;
case 3: printf("Dienstag"); break;
case 4: printf("Mittwoch"); break;
case 5: printf("Donnerstag"); break;
case 6: printf("Freitag"); break;
case 7: printf("Samstag"); break;
}
printf("\n");
}
close(Device);
return 0;
}
Die Ausgabe des Programm erscheint nach einem Aufruf des Programms dann auf dem Bildschirm:
Uhrzeit: 13:03:05 Datum: 05.02.2015 DonnerstagEs geht aber noch viel einfacher.
Raspbian hat neben anderen Treibern auch einen für den DS1307 integriert. Man brauch also nichts zu installieren, sondern kann den Treiber gleich laden. Von Hand (zum Ausprobieren) macht man das mittels:
modprobe rtc-ds1307Jetzt muss noch eine virtuelle Datei für die Uhr angelegt werden. Dabei muss man den richtigen I2C-Bus Nummer 1 verwenden, also i2c-1:
echo "ds1307 0x68" > /sys/class/i2c-adapter/i2c-1/new_deviceNun können die Systemprogramme über diese Adresse auf die RTC zugreifen. Dagegen läuft das Programm von oben nicht mehr, das der RTC-Treiber sich das Device gekrallt hat. Mit dem folgenden System-Befehl können Sie nun (als Root) die Uhrzeit ausgeben:
hwclock -rBeim ersten Abruf wird eventuell noch der 1. Januar 2000 angezeigt. Sonst zeigt uns der Aufruf die aktuelle Zeit, z. B.:
Do 05 Feb 2015 13:45:57 CET -0.073826 secondsMit dem date-Kommando kann die Systemuhrzeit gestellt werden, wenn keine Möglichkeit besteht, die Uhrzeit aus dem Netz zu holen. Dann kann man die gültige Zeit in die RTC übertragen:
hwclock --systohc -D --noadjfile --utcDas Kommando ist etwas länger als nur hwclock -w. Die Parameter haben folgende Bedeutung:
sudo hwclock --debug -r hwclock from util-linux 2.20.1 Using /dev interface to clock. Last drift adjustment done at 1423140131 seconds after 1969 Last calibration done at 1423140131 seconds after 1969 Hardware clock is on UTC time Assuming hardware clock is kept in UTC time. Waiting for clock tick... /dev/rtc0 does not have interrupt functions. Waiting in loop for time from /dev/rtc0 to change ...got clock tick Time read from Hardware Clock: 2015/02/05 12:45:57 Hw clock time : 2015/02/05 12:45:57 = 1423140357 seconds since 1969 Do 05 Feb 2015 13:45:57 CET -0.073826 seconds
Wenn soweit alles klappt, muss noch dafür gesorgt werden, dass nach einem Neustart auch alles wieder aktiviert werden muss. Deshalb wird das Ganze jetzt automatisiert. Vorausgesetzt wird, dass in der Datei /etc/modules die beiden Module i2c-bcm2708 und i2c-dev eingetragen sind und auch in /etc/modprobe.d/raspi-blacklist.conf die Zeile "i2c-bcm2708" auskommentiert wurde. Alle anderen Einstellungen nehmen Sie in der Startdatei /etc/rc.local vor (immer noch als Root). Tragen Sie vor der exit-Zeile die folgenden drei Zeilen ein (die ersten beiden sind genau diejenigen, die Sie oben auf der Kommandozeile eingetippt haben):
modprobe rtc-ds1307 echo "ds1307 0x68" > /sys/class/i2c-adapter/i2c-1/new_device hwclock --hctosysDas dritte Kommando setzt die Systemuhr mit der RTC-Uhrzeit. Testen können Sie das, indem Sie den Raspberry Pi für einige Minuten ausschalten und dann ohne Netzwerkanbindung starten. Hat er nun die aktuelle Zeit, haben Sie es geschafft!
Alternativ können Sie auch die erste Zeile ("modprobe rtc-ds1307") weglassen und dafür die folgende Zeile in der Datei /etc/modules eintragen:
rtc-ds1307
Ab Kernelversion 3.18 wird für das Einsetzen der Module der sogenannte Device Tree verwendet. Ab dann wird die One-Wire-Schnittstelle in der Datei /boot/config.txt aktiviert, indem dort eine Zeile eingetragen werden:
dtoverlay=i2c-rtc,ds1307Es kann statt des Chips ds1307 auch einer der Chips ds3231, pcf2127, pcf8523 oder pcf8563 angegeben werden. Siehe auch das Device Tree Kapitel.
Wer nicht basteln will, kann ohne Änderungen ein Fertigmodul verwenden, das auch noch genauer ist. Es wurde ein Modul mit dem DS3231-RTC-Chip ausprobiert. Das getestet Modul wird von SunFounder (www.sunfounder.com produziert und ist bei Ebay oder Amazon für einige Euro zu bekommen. Es lässt sich direkt auf die erste Pinreihe des GPIO aufstecken. Die Chips des DS3231 verwenden die gleichen I2C-Befehle wie der DS1307, so dass alles funktioniert wie oben beschrieben. Der DS3231 ist nicht nur als Uhr genauer als der DS1307, sondern hat auch noch den Quarz integriert, so dass nur noch der übliche Blockkondensator nötig ist. Er ist zudem auch mit 3,3 V Versorgungsspannung zufrieden.
Das Bild zeigt das aufgesteckte Modul. Auf der Platinenoberseite sitzt der DS3231, auf der Unterseite ist die Puffer-Knopfzelle angebracht. der einzige Nachteil besteht darin, dass das Modul den I2C-Anschluß blockiert.