In der letzten Folge hatten wir uns ja die Innereien des Uhrenmoduls angesehen. Heute wollen wir einen kurzen Blick darauf werfen, wie die Uhrzeit vom Raspberry auf das Uhrenmodul kommt und wie die Auswertung der Zeit erfolgt, die ja über die serielle Schnittstelle übertragen wird.

Zunächst müssen wir dem ATMega beibringen, Daten von der seriellen Schnittstelle zu lesen. Ich verwende hierzu die UART-Bibliothek von Peter Fleury.  Um diese zu verwenden, müssen wir die Bibliothek mittels des Befehls:

uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

initialisieren. Die UART_BAUD_RATE beträgt in meinem Falle 9600 Baud, es geht natürlich auch schneller. Die Geschwindigkeit ist aber für die Übertragung der Zeit völlig ausreichend. Nun müssen wir in der Hauptschleife des Programm zyklisch prüfen, ob Daten an der seriellen Schnittstelle anliegen, dafür basteln wir uns eine Funktion:

void getUart() {
    /*
     * Get received character from ringbuffer
     * uart_getc() returns in the lower byte the received character and
     * in the higher byte (bitmask) the last receive error
     * UART_NO_DATA is returned when no data is available.
     *
     */
    char c = uart_getc();

    if ( c & UART_NO_DATA )
    {
        /*
         * no data available from UART
         */
    }
    else
    {
        /*
         * new data available from UART
         * check for Frame or Overrun error
         */
        if ( c & UART_FRAME_ERROR )
        {
            /* Framing Error detected, i.e no stop bit detected */
            uart_puts_P("UART Frame Error: ");
        }
        if ( c & UART_OVERRUN_ERROR )
        {
            /*
             * Overrun, a character already present in the UART UDR register was
             * not read by the interrupt handler before the next character arrived,
             * one or more received characters have been dropped
             */
            uart_puts_P("UART Overrun Error: ");
        }
        if ( c & UART_BUFFER_OVERFLOW )
        {
            /*
             * We are not reading the receive buffer fast enough,
             * one or more received character have been dropped
             */
            uart_puts_P("Buffer overflow error: ");
        }

        if (charNum < 16) {

            if ((unsigned char)c == 'r') {

            	parseCommand(buffer,charNum);

            	uart_puts("rn");
            	uart_puts("Ok.rn");

            	charNum = 0;
            }
            else {
            	if (isalnum(c) || isblank(c)) {
					uart_putc(c);
					buffer[charNum] = (unsigned char)c;
					charNum++;
            	}
            }

        }

    }

}

Da wir jeweils immer nur ein Zeichen einlesen können, müssen wir eine maximale Länge (hier 16) definieren und uns merken, an welcher Position wir uns befinden. Am Ende des Kommandos erfolgt ein CR LF, damit der Controller weiss, daß wir einen kompletten Befehl empfangen haben. Jetzt fehlt nur noch das Auswerten des empfangenen Kommandos und das geht so:

void parseCommand(char* cmd, uint8_t len) {

	if (strncmp(cmd,"time",4) == 0) {

		char* t = &buffer[5];

		uint16_t time   = atoi(t);

		int hour = time / 100;
		int minute = time - ((time / 100) * 100);

		tmp_date.hour = hour;
		tmp_date.minute = minute;
		tmp_date.month = 1;
		tmp_date.year = 0;
		tmp_date.day = 1;

		if (isValidTime(tmp_date)) {
			current_date.hour = hour;
			current_date.minute = minute;
		}

	}
	else if(strncmp(cmd,"gettime",7) == 0) {
		sprintf(buffer,"rn%02d:%02d",current_date.hour,current_date.minute);
		uart_puts(buffer);
	}

}

Nun können wir über die serielle Schnittstelle die Zeit empfangen und die aktuelle Zeit ausgeben. Wie aber senden wir nun die Daten vom Raspberry?

Hierzu benötigen wir zunächst ein einfaches Python Script, was die Zeit als Kommandozeilenargument übergeben bekommt und diese dann an die serielle Schnittstelle sendet:

import serial
import sys
ser = serial.Serial("/dev/ttyAMA0",9600);
ser.write("time "+sys.argv[1]+"rn")
ser.close()

Und das Shellscript, welches wir später periodisch über einen Cronjob anstossen, um die Zeit zu synchronisieren:

#!/bin/bash ntpdate -s 0.de.pool.ntp.org date +"%H%M" | xargs python /home/pi/webradio/time.py

Damit haben wir nun alles zusammen und können einen Cronjob anlegen, der einmal in der Stunde die Zeit aktualisiert, hierzu verwenden wir den Befehl crontab -e und fügen folgende Zeile hinzu:

0 */1 * * * /home/pi/webradio/time.sh

Das Script muss sich natürlich am entsprechenden Ort befinden.

Das war's dann für heute. In der nächsten Folge schauen wir uns an, wie das eigentliche Webradio auf dem Raspberry funktioniert und wie wir selbiges mit externen Tastern steuern können.