GREETBoard RTC Modul – Ein- und Auslesen von Daten

Vor einiger Zeit habe ich das Real Time Clock Prototypen, das GREETBoard I2C RTC, vorgestellt. Es sind noch ein paar Layout-Optimierungen zu machen, aber im Grunde funktioniert es ganz hervorragend. Diesen Artikel möchte ich dafür nutzen, das C-Programm zu beschreiben, dass den DS1307 anspricht um Daten zu lesen und zu schreiben. Ich empfehle sehr den Artikel zum Prototypen vorher zu lesen, damit die Funktion des DS1307 und die Besonderheiten des Layouts bekannt sind.

Der DS1307 hat zwei Herausforderungen, die es zu meistern gilt. Zum Einen erfolgt die Kommunikation über den I2C Bus und zum Anderen werden Uhrzeit und Datum im sogennanten BCD-Code verarbeitet. Für die I2C Kommunikation verwende ich wieder die I2C-Bibliothek von Peter Fleury und binde diese im AVR Studio 6.1 ein. Die Datenpakete können somit recht einfach hin und her gesendet werden. Was die Umrechnung von BCD in Dezimal und umgekehrt angeht, so habe ich dazu bereits einen Artikel geschrieben um zu zeigen, wie das funktioniert.

Um die ausgelesenen Daten als Uhrzeit und Datum ausgeben zu können, benutze ich das GREETBoard I2CLCD Modul. Auch dieses wird über den I2C-Bus angesprochen, daher verwende ich zusätzlich noch die I2CLCD-Bibliothek von computerheld.de.

RTC Modul - Die verwendeten Module

RTC Modul – Die verwendeten Module

Das Programm in kleinen Schritten

Zunächst teile ich das Programm in kleine Schritte auf, sodass die Abschnitte die ich erklären nicht zu groß werden. Am Ende hänge ich das gesamte Programm an den Artikel an, damit es aus dem Blog herauskopiert werden kann.

Header Dateien

Wie immer startet das Programm mit der Einbindung der Header-Dateien. Zusätzlich zur IO-Header-Datei benötige ich noch die oben erwähnten Bibliotheken für den I2C-Bus und das LCD-Display.

#include <avr/io.h>
#include "i2cmaster.h"
#include "i2clcd.h"

Variablendeklaration

Im folgenden Abschnitt definiere ich einige Variablen, die später benötigt werden.

char Buffer[20];                  //Variable zur Umrechnung von INT
uint8_t rtcInitOK;                //zeigt an, ob die Initialisierung OK war
uint8_t Sec;                      //nötig zur Umrechnung von Sekunden
uint8_t i;                        //für eine For-Schleife
uint8_t init_rtc = 0;             //für die Initialisierung

uint8_t rtc_read_byte(uint8_t);   //Byte zum Auslesen des RTC

uint8_t TimeS;                    //Zeitvariablen
uint8_t TimeM;
uint8_t TimeH;

uint8_t DateD;                    //Datumsvariablen
uint8_t DateM;
uint8_t DateY;
uint8_t DateW;

#define I2C_RTC 0xD0              //Adresse des RTC

Die Umrechnungs-Funktionen

Diese beiden Funktionen sind für die Umrechnung von Dezimalzahlen in BCD und umgekehrt zuständig. Warum diese beiden Formel funktionieren, habe ich bereits in einem separaten Artikel erklärt.

uint8_t Dec2Bin(uint8_t val)
{
	return (val/10*16) + (val%10);
}

uint8_t Bin2Dec(uint8_t val)
{
	return (val/16*10) + (val%16);
}

Funktion rtc_activ

Der DS1307 besitzt einen internen Oszillator, der seine Impulse durch den externen Quarz erhält. Dass Bit 7 (CH = Clock Hold), des Sekunden-Registers (0x00), schaltet den Oszillator ein, wenn hier eine 0 gesetzt ist. Wird hingegen eine 1 gesetzt, hält dies den Oszillator an und der DS1307 stoppt.

Mit dem ersten Befehl wird der aktuelle Wert des Sekunden-Registers erfasst, mit der Bitmaske 01111111 manipuliert und in der Variablen „second“ abgelegt. Dies hat zur Folge, dass die Sekunden-Daten unverändert bleiben und das Bit 7 auf jeden Fall auf 0 gesetzt wird. Anschließend erfolgt eine Umwandlung des Manipulations-Ergebnisses  in eine Dezimalzahl

void rtc_activ(uint8_t e)
{
	uint8_t second = rtc_read_byte(0x00) & 0b01111111;
	second = Bin2Dec(second);

Ist der Funktionsaufruf mit einer 1 erfolgt hat dies zur Folge, dass das Bit 7 auf 0 gesetzt, in eine BCD-Zahl gewandelt und an den RTC-Baustein gesendet wird. Dieser wird dadurch aktiviert. Erfolgt der Aufruf mit einer 0, setzt dies das Bit 7 auf 1. Nach der Umwandlung wird diese Information an den DS1307 gesendet und dieser damit deaktiviert. In beiden Fällen ist sichergestellt, dass die Sekundendaten nicht manipuliert und verändert werden.

	if (e == 1)
	{
		second = Dec2Bin(second) & 0b01111111;
		rtc_write_byte(0x00, second);
	}
	else if (e == 0)
	{
		second = Dec2Bin(second) | 0b10000000;
		rtc_write_byte(0x00, second);
	}
}

Funktion rtc_write_byte

Die folgende Funktion ist für das Beschreiben eines einzelnen Registers des DS1307  zuständig und wird bei der Aktivierung benötigt. Eine Schreib-Funktion für alle Zeit- und Datumswerte ist in einer separate Funktion abgelegt (rtc_setup).

void rtc_write_byte(uint8_t addr, uint8_t val)
{
	if (init_rtc == 0)                  //Ist der DS1307 initialisiert?
		return;                     //wenn nicht, dann Abbruch

	i2c_start_wait(I2C_RTC+I2C_WRITE);  //Ansprechen des DS1307
	i2c_write(addr);                    //Angabe in welches Register geschrieben wird
	i2c_write(val);                     //Schreiben des Wertes
	i2c_stop();                         //Beendigung der Kommunikation
}

Funktion rtc_read_byte

Auch das Beschreiben einzelner Register ist ein Bestandteil der Aktivierung und daher als Funktion dem Programm hinzugefügt.

uint8_t rtc_read_byte(uint8_t addr)
{
	char val = 0x00;                     //Rücksetzen alter Auslesewerte

	if (init_rtc == 0)                   //Ist der DS1307 initialisiert?
		return 0;                    //wenn nicht, dann Abbruch

	i2c_start_wait(I2C_RTC+I2C_WRITE);   //Ansprechen des DS1307
	i2c_write(addr);                     //Angabe welches Register gelesen wird
	i2c_rep_start(I2C_RTC+I2C_READ);     //Aktivierung des Lesemodus
	val = i2c_readNak();                 //Auslesen des RTC-Bausteins
	i2c_stop();                          //Beendigung der Kommunikation

	return val;                          //Rückgabe des Leseergebnis
}

Funktion rtc_setup

Anders als die Funktion „rtc_write_byte“, dient „rtc_setup“ dem Beschreiben aller Zeit- und Datumsregister. Dafür werden die Daten Jahr, Monat, Tag, Stunde, Minute und Sekunde der Funktion übergeben. Diese wandelt die übergebenen Informationen in BCD-Code und schreibt diese Schritt für Schritt in die entsprechenden Register. Im Artikel GREETBoard RTC Modul – Der Prototyp (Version 0.2) ist die Übersicht der Register des DS1307 dargestellt. In der Reihenfolge dieser Register werden die BCD-Informationen in den DS1307 geschrieben.

Es ist zu beachten, dass das Bit 7 im Sekunden-Register für den internen Oszillator verantwortlich ist. Die folgende Funktion kombiniert die Sekunden-Information mit einer 1 für das Bit 7 um den internen Oszillator zu stoppen. Damit wird der DS1307 deaktiviert.

Am Ende der Funktion wird der RTC-Baustein wieder aktiviert und ausgelesen um die Daten in die Zeit- und Datumsvariablen zu laden.

void rtc_setup(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
{
	second = Dec2Bin(second) | 0b10000000;
	i2c_start_wait(I2C_RTC+I2C_WRITE);
	i2c_write(0x00);
	i2c_write(second);
	i2c_write(Dec2Bin(minute));
	i2c_write(Dec2Bin(hour));
	i2c_write(Dec2Bin(1));
	i2c_write(Dec2Bin(day));
	i2c_write(Dec2Bin(month));
	i2c_write(Dec2Bin(year));
	i2c_stop();

  rtc_activ(1);

  rtc_read();
}

Funktion rtc_init

Ganz zu Beginn sollte der RTC-Baustein initialisiert werden um mit ihm arbeiten zu können. Dazu wird in der Initialisierungs-Funktion das Flag „init_rtc“ zunächst auf 0 gesetzt, was einer Nicht-Initialisierung entspricht. Ebenso werden die Zeit- und Datumsvariablen auf 0 gesetzt.

Die Funktion wird für eine erfolgreiche Initialisierung eine 1 zurückgeben. Ansonsten wird das Ergebnis eine 0 sein.

uint8_t rtc_init(void)
{
	init_rtc = 0;   // 0 = Nicht initialisiert

	TimeH = 0;      //Zeit- und Datumsvariablen auf 0 setzen
	TimeM = 0;
	TimeS = 0;
	DateD = 0;
	DateM = 0;
	DateW = 0;
	DateY = 0;

Die anschließende Schleife spricht den RTC über den I2C-Bus an. Bei einem erfolgreichen „Kontakt“, sendet der DS1307 eine 0 zurück. Der erste Teil der if-Abfrage stoppt den I2C-Bus, wenn die Antwort des DS1307 nicht 0 war und die Schleife startet erneut. Die Schleife ist nicht endlos, da mit jedem Durchlauf die Variable um 1 erhöht wird und der Maximalwert bei 99 liegt. Erfolgt bis dahin kein Kontakt, ist die Schleife beendet und das Programm läuft weiter. Sollte der RTC mit einer 1 antworten, wird das Flag „init_rtc“ auf 1 gesetzt und die for-Schleife vorzeitig beendet (break;).

	for (int i = 0; i < 100; i++)
	{
		if (i2c_start(I2C_RTC+I2C_READ) != 0)
		{
			i2c_stop();
		}
		else
		{
			init_rtc = 1;
			break;
		}
	}

Sollte keine erfolgreiche Verbindung zum RTC aufgenommen worden sein, sorgt die folgende if-Abfrage für einen Abbruch der Funktion mit einer Rückmeldung der Funktion von 0 (return 0;).

Im Folgenden wird die Funktion rtc_activ mit dem Wert 1 aufgerufen und der RTC einmal ausgelesen. Der DS1307 ist nun einsatzbereit und die Initialisierung erfolgreich abgeschlossen. Daher wird das Flag init_rtc auf 1 gesetzt und die Funktion ebenfalls mit der Rückmeldung 1 abgeschlossen

	if (init_rtc == 0)
	{
		return 0;
	}

	rtc_activ(1);
	rtc_read();

	init_rtc = 1;
	return 1;
}

Funktion rtc_read

Um den DS1307 auszulesen wird zunächst der Initialisierungs-Status abgefragt. Ist dieser 0 (also nicht initialisiert) wird das Lesen abgebrochen.

void rtc_read(void)
{
	if (init_rtc == 0)
		return;

Die nächsten drei Zeilen sprechen den RTC-Baustein an und teilen ihm mit, dass er ausgelesen werden soll. Dabei setzt sich die Adresse aus der bereits definierten Adress-Variablen „I2C_RTC“ und den Zusätzen „I2C_WRITE“ und „I2C_READ“ zusammen, die in der i2cmaster.c Header Datei definiert sind.

Ist der Baustein bereit, werden die Zeit- und Datumdaten nacheinander ausgelesen, in Dezimalwerte umgewandelt und in der entsprechenden Variable gespeichert. Abschließend wird die I2C-Kommunikation mit dem Stopp-Befehl beendet. Die Daten sind nun gespeichert und können weiterverarbeitet werden.

	i2c_start_wait(I2C_RTC+I2C_WRITE);
	i2c_write(0x00);
	i2c_rep_start(I2C_RTC+I2C_READ);
	TimeS = i2c_readAck() & 0b01111111;
	TimeS = Bin2Dec(TimeS);
	TimeM = Bin2Dec(i2c_readAck());
	TimeH = i2c_readAck() & 0b00111111;
	TimeH = Bin2Dec(TimeH);
	DateW = Bin2Dec(i2c_readAck());
	DateD = Bin2Dec(i2c_readAck());
	DateM = Bin2Dec(i2c_readAck());
	DateY = Bin2Dec(i2c_readNak());
	i2c_stop();
}

Funktion show_time

Die Zeit-Variablen werden mit aktuellen Zeitdaten gefüllt, indem ein Auslesen des DS1307 erfolgt. Nacheinander werden die Sekunden, Minuten und Stunden auf das Display geschrieben. Werte unter 10 erfahren eine besondere Behandlung, da sie als z.B. 9 und nicht als 09 ausgegeben werden. Die Einer würden beim Übergang zu einer zweistelligen Zahl um eine Stelle nach rechts springen. Da mir das nicht gefällt, setze ich die Null manuell und platziere die einstelligen Zahlen eine Stelle nach rechts. Dieses Vorgehen wiederholt sich bei allen drei Zahlen. Am Ende setzte ich die Doppelpunkte als Trenner zwischen den Zahlen.

void show_time (void){
	rtc_read();                       //Auslesen des DS1307

	Sec = TimeS;                      //Sekunden umwandeln
	itoa(Sec, Buffer, 10);
	if (Sec < 10){                    //Sekunden anzeigen
		lcd_printlc(2,7,"0");     //wenn unter 10s, erst die 0 setzen
		lcd_printlc(2,8,Buffer);  //dann die Sekundenzahl
	}
	else{
		lcd_printlc(2,7,Buffer);  //wenn über 10s, direkt anzeigen
	}

	Sec = TimeM;
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(2,4,"0");
		lcd_printlc(2,5,Buffer);
	}
	else {
		lcd_printlc(2,4,Buffer);
	}

	Sec = TimeH;
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(2,1,"0");
		lcd_printlc(2,2,Buffer);
	}
	else{
		lcd_printlc(2,1,Buffer);
	}

	lcd_printlc(2,3,":");
	lcd_printlc(2,6,":");
	lcd_printlc(2,3,":");
}

Funktion show_date

Das Auslesen des DS1307 füllt die Datumsvariablen mit aktuellen Werten. Im Anschluss werden diese in Tages, Monats- und Jahreswerte umgewandelt, sodass sie auf dem LCD-Display anzeigbar sind. Wie bei der vorherigen Funktion werden einstellige Zahlen besonders behandelt, ansonsten ähneln sich „show_date“ und „show_time“ sehr stark. Am Ende erfolgt das Setzen der Datumspunkte.

void show_date (void){
	rtc_read();                      //Auslesen des DS1307

	Sec = DateD;                     //Tag umwandeln
	itoa(Sec, Buffer, 10);           //Tag anzeigen
	if (Sec < 10){
		lcd_printlc(1,1,"0");    //wenn unter 10, erst die 0 setzen
		lcd_printlc(1,2,Buffer); //dann die Tageszahl
	}
	else{
		lcd_printlc(1,1,Buffer); //wenn über 10, direkt anzeigen
	}

	Sec = DateM;                     //Monat umwandeln
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(1,4,"0");
		lcd_printlc(1,5,Buffer);
	}
	else{
		lcd_printlc(1,4,Buffer);
	}

	Sec = DateY;                     //Jahr umwandeln
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(1,7,"0");
		lcd_printlc(1,8,Buffer);
	}
	else{
		lcd_printlc(1,7,Buffer);
	}

	lcd_printlc(1,3,".");
	lcd_printlc(1,6,".");
	lcd_printlc(1,3,".");
}

Funktion IO_init

Wenn das Programm läuft sollen zwei Zeiten an den DS1307 gesendet werden, um ein Einstellen der Uhrzeit zu simulieren. Zu diesem Zweck ist die Einrichtung von Taster S1 und Taster S4 von Nöten. Natürlich benötigen sie auch ihre entsprechenden internen Pull-Ups

void IO_Init (void) {
	DDRC &= ~(1 << DDC2);  // PC2 = S1 = Eingang (+)
	DDRC &= ~(1 << DDC5);  // PC5 = S4 = Eingang (-)
	PORTC |= _BV(2);       // Pull Up an PC2 aktivieren
	PORTC |= _BV(5);       // Pull Up an PC5 aktivieren
}

Das Hauptprogramm

Im Hauptprogramm initialisiere ich zunächst die I2C-Kommunikation, das I2C-Display und die benötigten Eingänge. Anschließen lasse ich einen kurzen Begrüßungstext auf dem Display erscheinen.

Vor der Hauptschleife wird noch der Status der Initialisierung abgefragt um sicherzustellen, dass der DS1307 auch über den I2C-Bus angesprochen werden kann. Ist die Initialisierung nicht OK (rtc_init = 0), wird eine Fehlermeldung ausgegeben.

int main(void)
{
	i2c_init();                    //Starte I2C Kommunikation
	lcd_init();                    //Starte I2CLCD
	IO_Init();                     //Initialisierung der Eingänge

	lcd_command(LCD_CLEAR);        //Leere Display
	_delay_ms(20);		       //Warte 20ms
	lcd_printlc(1,1,"GreetBoard"); //Zeige Begrüßungstext
	lcd_printlc(2,1,"RTC Modul");
	_delay_ms(500);		       //Warte 500ms
	lcd_command(LCD_CLEAR);        //Leere Display
	_delay_ms(20);		       //Warte 20ms

	rtcInitOK = rtc_init();

	if (rtcInitOK == 0) {
		lcd_printlc(1,1,"Init NIO");
		_delay_ms(20);		       // Warte 20ms
		i2c_stop();
	}

Die Hauptschleife

Die Zeit und das Datum werden bei jedem Durchlauf der Hauptschleife ausgelesen und angezeigt. Das könnte natürlich auch Timer-gesteuert ablaufen um die Kommunikation auf dem I2C-Bus zu reduzieren. Aber für dieses Beispiel belasse ich es bei der einfachen Variante. Danach werden die beiden Taster S1 und S4 abgefragt und ggf. ein vorgegebenes Datenpakte an den DS1307 gesendet um diesen mit den Daten neu zu stellen. Taster 1 erzeugt: 17.11.2015, 09:15:05; Taster 4 erzeugt: 18.01.2019, 18:45:10

    while(1)
    {
        show_time();
	show_date();

	if (! (PINC & (1<<PINC2)) ){
		rtc_setup(15,11,17,9,15,5);
	}
	if (! (PINC & (1<<PINC5)) ){
		rtc_setup(19,1,18,18,45,10);
	}
    }
}

Fazit

Mit der Schaltung aus meinem vorherigen RTC-Artikel, und diesem Programm ist es möglich den DS1307 zu aktivieren, zu stellen und die aktuelle Uhrzeit auf dem LCD-Display anzuzeigen. Die Herausforderung bezüglich der Kommunikation über den I2C-Bus und die Umrechnung für die BCD-Codierung sind erfolgreich gemeistert, sodass die drei Module (ATMega128, I2C LCD und I2C RTC) stabil zusammenarbeiten.

Das RTC-Modul zum Leben zu erwecken hat echt viel Spaß gemacht und es war eine schöne Aufgabe, die ich mir selber gestellt habe. Umso mehr freue ich mich, dass ich es geschafft habe 🙂 In naher Zukunft werde ich das überarbeitete Layout 1.0 vorstellen, damit die z.T. groben Fehler (die sich zum Glück nicht ausgewirkt haben) behoben sind. Hier noch eine Vorschau (und der entsprechende Link) auf das zukünftige Layout.

In diesem Sinne wünsche ich alles Gute,
Euer Timo

GREETBoard I2C-RTC in 3D

Zukünftiges GREETBoard I2C-RTC in 3D

Anhang: Das vollständige Programm

#include <avr/io.h>
#include "i2cmaster.h"
#include "i2clcd.h"

char Buffer[20];                  //Variable zur Umrechnung von INT
uint8_t rtcInitOK;                //zeigt an, ob die Initialisierung OK war
uint8_t Sec;                      //nötig zur Umrechnung von Sekunden
uint8_t i;                        //für eine For-Schleife
uint8_t init_rtc = 0;             //für die Initialisierung

uint8_t rtc_read_byte(uint8_t);   //Byte zum Auslesen des RTC

uint8_t TimeS;                    //Zeitvariablen
uint8_t TimeM;
uint8_t TimeH;

uint8_t DateD;                    //Datumsvariablen
uint8_t DateM;
uint8_t DateY;
uint8_t DateW;

#define I2C_RTC 0xD0              //Adresse des RTC

uint8_t Dec2Bin(uint8_t val)
{
	return (val/10*16) + (val%10);
}

uint8_t Bin2Dec(uint8_t val)
{
	return (val/16*10) + (val%16);
}

void rtc_activ(uint8_t e)
{
	uint8_t second = rtc_read_byte(0x00) & 0b01111111;
	second = Bin2Dec(second);

	if (e == 1)
	{
		second = Dec2Bin(second) & 0b01111111;
		rtc_write_byte(0x00, second);
	}
	else if (e == 0)
	{
		second = Dec2Bin(second) | 0b10000000;
		rtc_write_byte(0x00, second);
	}
}

void rtc_write_byte(uint8_t addr, uint8_t val)
{
	if (init_rtc == 0)                  //Ist der DS1307 initialisiert?
		return;                     //wenn nicht, dann Abbruch

	i2c_start_wait(I2C_RTC+I2C_WRITE);  //Ansprechen des DS1307
	i2c_write(addr);                    //Angabe in welches Register geschrieben wird
	i2c_write(val);                     //Schreiben des Wertes
	i2c_stop();                         //Beendigung der Kommunikation
}

uint8_t rtc_read_byte(uint8_t addr)
{
	char val = 0x00;                     //Rücksetzen alter Auslesewerte

	if (init_rtc == 0)                   //Ist der DS1307 initialisiert?
		return 0;                    //wenn nicht, dann Abbruch

	i2c_start_wait(I2C_RTC+I2C_WRITE);   //Ansprechen des DS1307
	i2c_write(addr);                     //Angabe welches Register gelesen wird
	i2c_rep_start(I2C_RTC+I2C_READ);     //Aktivierung des Lesemodus
	val = i2c_readNak();                 //Auslesen des RTC-Bausteins
	i2c_stop();                          //Beendigung der Kommunikation

	return val;                          //Rückgabe des Leseergebnis
}

void rtc_setup(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
{
	second = Dec2Bin(second) | 0b10000000;
	i2c_start_wait(I2C_RTC+I2C_WRITE);
	i2c_write(0x00);
	i2c_write(second);
	i2c_write(Dec2Bin(minute));
	i2c_write(Dec2Bin(hour));
	i2c_write(Dec2Bin(1));
	i2c_write(Dec2Bin(day));
	i2c_write(Dec2Bin(month));
	i2c_write(Dec2Bin(year));
	i2c_stop();

  rtc_activ(1);

  rtc_read();
}

uint8_t rtc_init(void)
{
	init_rtc = 0;   // 0 = Nicht initialisiert

	TimeH = 0;      //Zeit- und Datumsvariablen auf 0 setzen
	TimeM = 0;
	TimeS = 0;
	DateD = 0;
	DateM = 0;
	DateW = 0;
	DateY = 0;

	for (int i = 0; i < 100; i++)
	{
		if (i2c_start(I2C_RTC+I2C_READ) != 0)
		{
			i2c_stop();
		}
		else
		{
			init_rtc = 1;
			break;
		}
	}

	if (init_rtc == 0)
	{
		return 0;
	}

	rtc_activ(1);
	rtc_read();

	init_rtc = 1;
	return 1;
}

void rtc_read(void)
{
	if (init_rtc == 0)
		return;

	i2c_start_wait(I2C_RTC+I2C_WRITE);
	i2c_write(0x00);
	i2c_rep_start(I2C_RTC+I2C_READ);
	TimeS = i2c_readAck() & 0b01111111;
	TimeS = Bin2Dec(TimeS);
	TimeM = Bin2Dec(i2c_readAck());
	TimeH = i2c_readAck() & 0b00111111;
	TimeH = Bin2Dec(TimeH);
	DateW = Bin2Dec(i2c_readAck());
	DateD = Bin2Dec(i2c_readAck());
	DateM = Bin2Dec(i2c_readAck());
	DateY = Bin2Dec(i2c_readNak());
	i2c_stop();
}

void show_time (void)
{
	rtc_read();                       //Auslesen des DS1307

	Sec = TimeS;                      //Sekunden umwandeln
	itoa(Sec, Buffer, 10);
	if (Sec < 10){                    //Sekunden anzeigen
		lcd_printlc(2,7,"0");     //wenn unter 10s, erst die 0 setzen
		lcd_printlc(2,8,Buffer);  //dann die Sekundenzahl
	}
	else{
		lcd_printlc(2,7,Buffer);  //wenn über 10s, direkt anzeigen
	}

	Sec = TimeM;
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(2,4,"0");
		lcd_printlc(2,5,Buffer);
	}
	else {
		lcd_printlc(2,4,Buffer);
	}

	Sec = TimeH;
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(2,1,"0");
		lcd_printlc(2,2,Buffer);
	}
	else{
		lcd_printlc(2,1,Buffer);
	}

	lcd_printlc(2,3,":");
	lcd_printlc(2,6,":");
	lcd_printlc(2,3,":");
}

void show_date (void)
{
	rtc_read();                      //Auslesen des DS1307

	Sec = DateD;                     //Tag umwandeln
	itoa(Sec, Buffer, 10);           //Tag anzeigen
	if (Sec < 10){
		lcd_printlc(1,1,"0");    //wenn unter 10, erst die 0 setzen
		lcd_printlc(1,2,Buffer); //dann die Tageszahl
	}
	else{
		lcd_printlc(1,1,Buffer); //wenn über 10, direkt anzeigen
	}

	Sec = DateM;                     //Monat umwandeln
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(1,4,"0");
		lcd_printlc(1,5,Buffer);
	}
	else{
		lcd_printlc(1,4,Buffer);
	}

	Sec = DateY;                     //Jahr umwandeln
	itoa(Sec, Buffer, 10);
	if (Sec < 10){
		lcd_printlc(1,7,"0");
		lcd_printlc(1,8,Buffer);
	}
	else{
		lcd_printlc(1,7,Buffer);
	}

	lcd_printlc(1,3,".");
	lcd_printlc(1,6,".");
	lcd_printlc(1,3,".");
}

void IO_Init (void) {
	DDRC &= ~(1 << DDC2);  // PC2 = S1 = Eingang (+)
	DDRC &= ~(1 << DDC5);  // PC5 = S4 = Eingang (-)
	PORTC |= _BV(2);       // Pull Up an PC2 aktivieren
	PORTC |= _BV(5);       // Pull Up an PC5 aktivieren
}

int main(void)
{
	i2c_init();                    //Starte I2C Kommunikation
	lcd_init();                    //Starte I2CLCD
	IO_Init();                     //Initialisierung der Eingänge

	lcd_command(LCD_CLEAR);        //Leere Display
	_delay_ms(20);		       //Warte 20ms
	lcd_printlc(1,1,"GreetBoard"); //Zeige Begrüßungstext
	lcd_printlc(2,1,"RTC Modul");
	_delay_ms(500);		       //Warte 500ms
	lcd_command(LCD_CLEAR);        //Leere Display
	_delay_ms(20);		       //Warte 20ms

	rtcInitOK = rtc_init();

	if (rtcInitOK == 0) {
		lcd_printlc(1,1,"Init NIO");
		_delay_ms(20);		       // Warte 20ms
		i2c_stop();
	}

    while(1)
    {
        show_time();
	show_date();

	if (! (PINC & (1<<PINC2)) ){
		rtc_setup(15,11,17,9,15,5);
	}
	if (! (PINC & (1<<PINC5)) ){
		rtc_setup(19,1,18,18,45,10);
	}
    }
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.