Aus Raspberry Pi Geek 02/2014

RasPi zeitgesteuert starten per RTC (Seite 3)

Das Listing 8 speichern Sie in der Datei rtc-power.c und übersetzen diese mit gcc rtc-power.c -o rtc-power gleich am RasPi selbst. Bevor Sie rtc-power ins Verzeichnis /sbin/ verschieben, setzen Sie noch den Eigentümer und die Gruppe mit sudo chown root:root rtc-power auf die passenden Werte.

Listing 8

 

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <time.h>
#define MCP7941X        0x6f
#define CTRLREG         0x07
#define ALARM0REG       0x0a
#define ALARMREGSETLEN  6
#define ALARMMC         0x70
#define RTCOUT1         0x80
#define ALARM0EN        0x10
#define MINTIMEGAP      120
char int2bcd(char val) {
  return (val%10+16*(val/10));
}
int main(int argc, char *argv[])
{
  int file;
  int i2cbus; // I2C bus number
  char i2cdevicename[11];
  char cbuffer[2]; // I2C Control Buffer
  char buffer[ALARMREGSETLEN+1]; // I2C Alarm0 Buffer
  char *end;
  time_t atime; // Alarm time in seconds since epoch
  time_t now = time(NULL);
  struct tm *alarm; // Alarm in broken down time
  /* get command line parameters */
  if (argc != 3) {
    printf("Error: 2 Parameters expected.\n");
    exit(1);
  }
  i2cbus = strtol(argv[1], &end, 0);
  if (*end || i2cbus < 0 || i2cbus > 1) {
    printf("Error: I2C Bus Number 0 or 1 expected.\n");
    exit(2);
  }
  atime = strtol(argv[2], &end, 0);
  if (*end || atime < 0) {
    printf("Error: Alarm time zero or greater expected.\n");
    exit(3);
  }
  /* set RTC control and ALARM0 accordingly */
  if (atime == 0) { // in case alarm time is zero then ...
    int i;
    cbuffer[1] = RTCOUT1; // ... simply switch off ...
    for (i=1; i<=ALARMREGSETLEN; i++) buffer[i]=0; // ... and clear alarm time
  }
  else { // in case of a non-zero alarm time ....
    cbuffer[1] = ALARM0EN; // ... enable the alarm ...
    if (atime - now < MINTIMEGAP) atime = now + MINTIMEGAP; // ... make alarm causal ...
    alarm = gmtime(&atime);
    if (alarm->tm_sec > 59) alarm->tm_sec = 59; // ... skip any leap seconds if any ...
    buffer[1] = int2bcd(alarm->tm_sec); // and write seconds
    buffer[2] = int2bcd(alarm->tm_min); // minutes
    buffer[3] = int2bcd(alarm->tm_hour); // hour
    buffer[4] = int2bcd(alarm->tm_wday+1); // day of week
    buffer[4] |= ALARMMC; // add alarm match condition and write
    buffer[5] = int2bcd(alarm->tm_mday); // day of month
    buffer[6] = int2bcd(alarm->tm_mon+1); // month
  }
  /* open i2c device */
  snprintf(i2cdevicename, 11, "/dev/i2c-%d", i2cbus);
  file = open(i2cdevicename, O_WRONLY);
  if (file < 0) {
    printf("Error: Can't open /dev/i2c-%d.\n", i2cbus);
    exit(4);
  }
  if (ioctl(file, I2C_SLAVE_FORCE, MCP7941X) < 0) {
    printf("Error: Can't attach I2C Client 0x%x.\n", MCP7941X);
    exit(5);
  }
  /* write alarm0 to RTC */
  buffer[0] = ALARM0REG; // set ALARM0 register address
  if (write(file, buffer, ALARMREGSETLEN+1) != ALARMREGSETLEN+1) {
    printf("Error: Can't write alarm to I2C Client 0x%x.\n", MCP7941X);
    exit(6);
  }
  /* activate alarm and deactivate power rail */
  cbuffer[0] = CTRLREG; // set RTC control register address
  if (write(file, cbuffer, 2) != 2) {
    printf("Error: Can't write configuration to I2C Client 0x%x.\n", MCP7941X);
    exit(7);
  }
  exit(0);
}

Weckruf

Beim Systemstopp – am einfachsten initiiert mit sudo halt – erwartet das Skript aus Listing 6 die Weckzeit in der Datei /etc/wakealarm als Anzahl der Sekunden seit dem 1. Januar 1970 um 00:00:00 UTC [6]. Listing 9 zeigt, wie Sie eine absolute Weckzeit am Weihnachtsabend oder eine relative von der Kommandozeile aus anlegen.

Listing 9

 

$ sudo sh -c 'date -d "2014-12-24 17:59:30" +%s > /etc/wakealarm'
$ sudo sh -c 'echo $((`date +%s` + (7 * 60 + 11) * 60 + 13)) > /etc/wakealarm'

Das Wecken deaktivieren Sie durch das Löschen dieser Datei oder indem Sie die Weckzeit auf 0 setzen.

Fazit

Die hier vorgestellte Hardware mit der zugehörigen Software eignet sich als Basis für eigene Weiterentwicklungen. Vorab ein wenig Übung mit dem Lötkolben sowie eine Elektronikbastlerausstattung in der Werkstatt sind sicher anzuraten, denn den MCP79410 gibt es nur als SMD. Ein Steckbrett wäre eine Alternative, wenn Sie das SMD auf eine eigene steckbare Platine ziehen.

Das Design der Software fällt deutlich eleganter aus, wenn Sie direkt an die Wurzel gehen, also an den Kernel und seine Module. Dort liegen die notwendigen Funktionen zum Ansteuern einer Stromversorgung vor, und auch das Erstellen eines vollwertigen Treibers für den MCP79410 wäre keine Hexerei. Wegen der deutlich effektiveren Kommunikation zwischen Kernel und Hardware ließe sich die Verzögerungszeit des Zeitgebers auf diesem Weg deutlich reduzieren. 

Glossar

RTC

Real Time Clock. Chip mit integriertem Quartzoszillator, inkrementiert so in einem bestimmten Intervall einen Zähler. Durch Umrechnen erzeugt der Computer daraus eine für Menschen lesbare Uhrzeit mit Datumsangabe.

SMD

Surface-mounted Device. Oberflächenmontiertes Gerät, dass heutzutage in der Regel mit Maschinen auf die vorbereiteten Leiterbahnen angebracht wird.

Der Autor

Werner Hein beschäftigt sich seit 1994 mit Linux als Hobby und seit 1997 professionell mit der Entwicklung des Modems in Mobiltelefonen. Auch dort gibt es eine Weckuhr, allerdings mit deutlich höherer Zeitauflösung und viel kürzeren Zyklen; schließlich gilt es, keinen Anruf und keine Nachricht zu verlieren.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 8 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben