Reputation: 11
My goal is to build a Alarm clock (in form of the C4 in CSGO). I can't properly setup or use the RTC DS3231, it won't change the time/date and Outputs the same weird value every time (17:59:40.727 -> Mittwoch, 165. 2165 45:165:85) I used some random Library to test the DS3231 on Arduino Uno. What am I doing wrong?
Here's the code *.ino
(comments are german):
#include <Wire.h>
#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC DS3231
//Membervariablen
int jahr,monat,tag,stunde,minute,sekunde, wochentag;
int daysInMonth[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
String daysInWeek[7] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
String monthInYear[12] = {"Januar","Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
String outputFormat = "%s, %02d.%s %04d %02d:%02d:%02d Uhr";
//Ließt den aktuellen Zeitstempel aus dem RTC Modul.
void rtcReadTime(){
Wire.beginTransmission(RTC_I2C_ADDRESS); //Aufbau der Verbindung zur Adresse 0x68
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(RTC_I2C_ADDRESS, 7);
sekunde = bcdToDec(Wire.read() & 0x7f);
minute = bcdToDec(Wire.read());
stunde = bcdToDec(Wire.read() & 0x3f);
//Der Wochentag wird hier nicht ausgelesen da dieses mit
//dem Modul RTC DS3231 nicht über die Wire.h zuverlässig funktioniert.
/* wochentag =*/ bcdToDec(Wire.read());
tag = bcdToDec(Wire.read());
monat = bcdToDec(Wire.read());
jahr = bcdToDec(Wire.read())+2000;
}
//Funktion zum schreiben / setzen der Uhrzeit.
void rtcWriteTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde){
Wire.beginTransmission(RTC_I2C_ADDRESS);
Wire.write(0); // Der Wert 0 aktiviert das RTC Modul.
Wire.write(decToBcd(sekunde));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(stunde));
Wire.write(decToBcd(0)); // Wochentag unberücksichtigt
Wire.write(decToBcd(tag));
Wire.write(decToBcd(monat));
Wire.write(decToBcd(jahr-2000));
Wire.endTransmission();
}
//Berechnet den Tag der Woche aus dem übergebenen Datumswerten.
byte calcDayOfWeek(int jahr, byte monat, byte tag) {
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
jahr -= monat < 3;
return ((jahr + jahr/4 - jahr/100 + jahr/400 + t[monat-1] + tag) % 7);
}
//Convertiert Dezimalzeichen in binäre Zeichen.
byte decToBcd(byte val){
return ( (val/10*16) + (val%10) );
}
//Convertiert binäre Zeichen in Dezimal Zeichen.
byte bcdToDec(byte val){
return ( (val/16*10) + (val%16) );
}
//Ließt einen String und liefert einen Integer Wert von einer
//definierten Stelle (byte num) des Stringwertes.
int getIntFromString (char *stringWithInt, byte num){
char *tail;
while (num>0){
num--;
//Bei Kommanseparierten Listen werden die Kommata
//übersprungen und geben damit die Unterteilung des Strings an.
while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)){
stringWithInt++;
}
tail=stringWithInt;
//Schleife solange ausführen bis eine Zahl gefunden wurde
//welche größer 0 ist.
while ((isdigit(*tail))&&(*tail!=0)){
tail++;
}
if (num>0){
stringWithInt=tail;
}
}
return(strtol(stringWithInt, &tail, 10));
}
//Setup Methode
void setup(){
Wire.begin(); //Kommunikation über die Wire.h bibliothek beginnen.
Serial.begin(57600); //Übertragungsgeschwindigkeit 9600 Baud
Serial.println("Mit dem Befehl kann das Datum und die Uhrzeit gesetzt oder veraendert werden.");
Serial.println("Beispiel: set 28.08.2013 10:54");
}
//Gibt einen Zeitstempel auf der Seriellen Schnittstelle aus.
void printRTCDateTime(){
char linebuf[60];
int dOW = calcDayOfWeek(jahr, monat, tag);
String wochentagC = daysInWeek[dOW];
String monatC = monthInYear[monat];
String result = "";
result += wochentagC;
result += ", ";
result += tag;
result += ".";
result += monatC;
result += " ";
result += jahr;
result += " ";
if(stunde<10) { result += "0"; }
result += stunde;
result += ":";
if(minute<10) { result += "0"; }
result += minute;
result += ":";
if(sekunde<10) { result += "0"; }
result += sekunde;
Serial.println(result);
}
//Manuelles setzen der Uhrzeit über den Seriellen Monitor der IDE.
void setRTCTime(){
char linebuf[30];
byte counter;
if (Serial.available()){
delay(100); // Warte auf das Eintreffen aller Zeichen vom seriellen Monitor
memset(linebuf,0,sizeof(linebuf)); // Zeilenpuffer löschen
counter=0; // Zähler auf Null
while (Serial.available()){
linebuf[counter]=Serial.read(); // Zeichen in den Zeilenpuffer einfügen
if (counter<sizeof(linebuf)-1) counter++; // Zeichenzähler erhöhen
}
// Wenn in der gelesenen Zeile das Wort 'set' vorkommt dann...
//(Hier muss man bedenken das die Suche nach 'set' auch nach x Zeichen ein positives Ergebnis liefern wird, zbsp. 123set 09.01.2016 12:00:00)
if (strstr(linebuf,"set")==linebuf){
tag=getIntFromString (linebuf,1);
monat=getIntFromString (linebuf,2);
jahr=getIntFromString (linebuf,3);
stunde=getIntFromString (linebuf,4);
minute=getIntFromString (linebuf,5);
sekunde=getIntFromString (linebuf,6);
} else {
Serial.println("Befehl unbekannt.");
return;
}
// Ausgelesene Werte einer groben Plausibilitätsprüfung unterziehen:
if (!checkDateTime(jahr, monat, tag, stunde, minute, sekunde)){
Serial.println(linebuf);
Serial.println("Fehlerhafte Zeitangabe im 'set' Befehl");
Serial.println("Beispiel: set 28.08.2013 10:54");
return;
}
rtcWriteTime(jahr, monat, tag, stunde, minute, sekunde);
Serial.println("Zeit und Datum wurden auf neue Werte gesetzt.");
}
}
//Prüft das eingegebene Datum auf korrektheit.
boolean checkDateTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde){
boolean result = false;
if(jahr>2000){
result = true;
} else {
return false;
}
// Schaltjahr prüfen
if(jahr % 400 == 0 || (jahr % 100 != 0 && jahr % 4 == 0)){
//Wenn es ein Schaltjahr ist dann den Wert 29 in das Array an der Stelle 1 für den Monat Februar schreiben.
daysInMonth[1]=29;
}
//Monat muss kleiner 13 sein.
if (monat<13){
if( tag <= daysInMonth[monat-1] ){
result = true;
}
} else {
return false;
}
//Wert für Stunde muss zwischen 0 und 24 liegen,
//Wert für Minute und sekunde muss zwischen 0 und 59 liegen
if(stunde <24 && minute <60 && sekunde <60 && stunde >= 0 && minute >=0 && sekunde >=0){
result = true;
} else {
return false;
}
return result;
}
void loop(){
rtcReadTime();
printRTCDateTime();
setRTCTime();
delay(1000);
}
Upvotes: 0
Views: 414
Reputation: 28958
To get the second you do
sekunde = bcdToDec(Wire.read() & 0x7f);
So you simply read the 7 lowest bits of the first byte. It is a bit more complicated that this. Read the datasheet carefully!
From the datasheet:
MSB BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 LSB
0 | 10 seconds | seconds
You just read the 7 bits as your seconds value. That cannot work.
49 seconds would be 0b01001001
You read 73.
You should calculate
0b01001001 & 0x0F -> 9
your seconds value
and
0b01001001 & 0xF0 -> 4
your 10 seconds value
-> 10 * 4 + 9 = 49
You have the same or worse problems with all the other values. I hope you get my point.
You also shoudl check the code that is supposed to set the time. Why do you write integer values into register bytes? Here as well you do not follow the address table. You have to do more than just decToBcd
any value and stuff it onto the bus.
I haven't read through all of your code. I guess you should fix those issues first.
Upvotes: 0