DS1307 RTC RAM beschreiben

Hallo,

Ich möchte den RAM Speicher der DS1307 zum Speichern von Einstellungen benutzen.
Im Forum habe ich dazu folgendes gefunden. (Beitrag #2)

#define DS1307_ADDR 0x68
#define RAM_OFFSET 8         //map logical ram addresses (0-55) to physical addresses (8-63)

//write to DS1307 RAM where addr>=0 and addr<56
void dsSramWrite(byte addr, byte *values, byte nBytes)
{
    Wire.beginTransmission(DS1307_ADDR);
    Wire.write(addr + RAM_OFFSET);
    for (byte i=0; i<nBytes; i++) Wire.write(values[i]);
    Wire.endTransmission();   
}

//read from DS1307 RAM where addr>=0 and addr<56
void dsSramRead(byte addr, byte *values, byte nBytes)
{
    Wire.beginTransmission(DS1307_ADDR);
    Wire.write(addr + RAM_OFFSET);
    Wire.endTransmission(); 
    Wire.requestFrom( (uint8_t)DS1307_ADDR, nBytes );
    for (byte i=0; i<nBytes; i++) values[i] = Wire.read();
}

//is the DS1307 oscillator running?
boolean dsIsRunning(void)
{
    byte secRegister;        //seconds register, bit 7 is clock halt (CH) bit
   
    Wire.beginTransmission(DS1307_ADDR);
    Wire.write(0x00);        //seconds register is address zero
    Wire.endTransmission(); 
    Wire.requestFrom( DS1307_ADDR, 1 );
    secRegister = Wire.read();
   
    return !(secRegister & 0x80);
}

Ich verstehe allerdings nicht wie man die Funktionen benutzt.
Die DS1307 benutzt ja die ersten 8 Adresse des RAM Speichers für Zeit und Datum und die anderen 56 sind frei verfügbar. Nun wollte ich testweise einfach mal einen Wert der ersten 8 Adressen auslesen (dazu habe ich RAM_OFFSET auf 0 gesetzt).

Wie mache ich das?
Die Funktion "dsSramRead" ist ja mit void definiert und gibt mir keine Werte zurück oder verstehe ich das falsch. Und für was wird die Variable byte *values, verwendet?

Vielen Dank schonmal für Eure Hilfe

ArduinoArti:
Die Funktion "dsSramRead" ist ja mit void definiert und gibt mir keine Werte zurück oder verstehe ich das falsch. Und für was wird die Variable byte *values, verwendet?

Informiere Dich über Arrays und Zeiger/Pointer und die Grundlagen von Werteübergaben an Funktionen.

Gruß Tommy

Die Funktion "dsSramRead" ist ja mit void definiert und gibt mir keine Werte zurück oder verstehe ich das falsch

Funktionen können keine Arrays zurückgegeben. Das sind in C/C++ keine Objekte wie in manchen anderen Sprachen. Deshalb übergibt das Ziel-Array als Parameter und die Funktion füllt es

Außerdem entsprechen Array-Variablen praktisch Zeigern auf das erste Element. Deshalb byte*. Und zusätzlich übergibt man noch die Größe des Arrays damit die Funktion weiß wie viel Platz ist

//read from DS1307 RAM where addr>=0 and addr<56
void dsSramRead(byte addr, byte *values, byte nBytes)
{
    Wire.beginTransmission(DS1307_ADDR);
    Wire.write(addr + RAM_OFFSET);
    Wire.endTransmission(false);
    Wire.requestFrom( (uint8_t)DS1307_ADDR, nBytes );
    for (byte i=0; i<nBytes; i++) values[i] = Wire.read();
}

Das fehlte ein false, ich habe es mal eingetragen

Macht für diese Anwendung wohl keinen Unterschied, könnte aber dem einen oder anderen unverhofft ein Beinchen stellen.
Zudem könnte man die Rückgabewerte der Methoden überprüfen, und so herausfinden ob die Aktion überhaupt Erfolg hatte.

Also ich habe mich mal eingelesen. Die Rückgabe erfolgt also "per pointer". Ganz verstanden habe ich es aber trotzdem noch nicht. Der Zeiger hat den gleichen Datentyp wir die Variable auf die gezeigt wird. Wie ich den Zeiger in diesem Fall jetzt aber definieren muss ist mir noch nicht klar. Ich wollte probeweise mal den Wochentag, den Tag und den Monat auslesen.
Hier sind die Speicherorte der RTC nachzulesen.

Versucht habe ich es folgendermaßen

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

#define DS1307_ADDR 0x68
#define RAM_OFFSET 0
byte Ram[3];

void setup () {
  while (!Serial); // for Leonardo/Micro/Zero
  Serial.begin(9600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");

  }
}
void loop () {
  DateTime now = rtc.now();
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" (");
  Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
  Serial.print(") ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.println(now.second(), DEC);


  dsSramRead(3, Ram, 3);
  Serial.print("Wert1:");
  Serial.println(Ram[0]);
  Serial.print("Wert2:");
  Serial.println(Ram[1]);
  Serial.print("Wert3:");
  Serial.println(Ram[2]);

  delay(3000);
}

void dsSramRead(byte addr, byte *values, byte nBytes)
{
  Wire.beginTransmission(DS1307_ADDR);
  Wire.write(addr + RAM_OFFSET);
  Wire.endTransmission(false);
  Wire.requestFrom( (uint8_t)DS1307_ADDR, nBytes );
  for (byte i = 0; i < nBytes; i++) values[i] = Wire.read();
}

Als Rückgabe habe ich aber folgendes bekommen.

2020/9/27 (Sunday) 17:19:10
Wert1:3
Wert2:39
Wert3:9

Was ist hier falsch?

Wie ich den Zeiger in diesem Fall jetzt aber definieren muss ist mir noch nicht klar.

Gar nicht. Der Zeiger wird doch von der Funktion schon definiert. Du darfst nicht Arrays mit Zeigern verwechseln. Die sind miteinander verwandt, aber zwei verschiedene Dinge

byte data[3];
dsSramRead(..., data, sizeof(data));

Danach stehen in data 3 Bytes aus dem RAM. Die Adresse musst du noch eintragen

Die Array-Variable zerfällt bei der Übergabe einfach in einen Zeiger auf das erste Element. Oder in anderen Worten man übergibt die Anfangs-Adresse eines Bereichs im Speicher

Ich wollte probeweise mal den Wochentag, den Tag und den Monat auslesen.

Du solltest beachten dass Zeit und Datum im BCD Format abgespeichert sind:

39 = 0010 0111

Das ist 27 in BCD. Passt also

Hmmm.
Das Lesen startet an Adresse 3 - dem Link nach wäre das der Wochentag.
Und dann ist 3 Dienstag und nicht Sonntag.

Vielleich habe ich auch was übersehen...

wno158:
Hmmm.
Das Lesen startet an Adresse 3 - dem Link nach wäre das der Wochentag.
Und dann ist 3 Dienstag und nicht Sonntag.

Vielleich habe ich auch was übersehen...

Ja das ist mir auch aufgefallen.
Ich nutze aktuell die Bibliothek RTClib von Adafruit Version 1.11.2. Laut Beschreibung enthält diese bereits Funktionen zum Schreiben und auslesen.
Diese funktionieren auch, sodass mein eigentliches Problem, das Speichern im Ram Speicher, gelöst ist. :smiley:

Was mich wundert ist jedoch, dass wenn ich über diese Funktionen die ersten 8 Stellen auslese bekomme ich wieder komplett andere Werte.

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

#define DS1307_ADDR 0x68
#define RAM_OFFSET 0
byte Ram[13];
uint8_t Ram2;
byte testin;


void setup () {
  while (!Serial); // for Leonardo/Micro/Zero
  Serial.begin(9600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");

  }
}
void loop () {
  DateTime now = rtc.now();
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" (");
  Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
  Serial.print(") ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.println(now.second(), DEC);


  dsSramRead(0, Ram, 12);
  Serial.println(Ram[0]);
  Serial.println(Ram[1]);
  Serial.println(Ram[2]);
  Serial.println(Ram[3]);
  Serial.println(Ram[4]);
  Serial.println(Ram[5]);
  Serial.println(Ram[6]);
  Serial.println(Ram[7]);
  Serial.println(Ram[8]);
  Serial.println(Ram[9]);
  Serial.println(Ram[10]);
  Serial.println(Ram[11]);
    Serial.println(" ");
  
  //Versuch mit rtc lib von adafruit

  //testin = 45;
  //rtc.writenvram(10,testin);
  Serial.println(rtc.readnvram (0));
  Serial.println(rtc.readnvram (1));
  Serial.println(rtc.readnvram (2));
  Serial.println(rtc.readnvram (3));
  Serial.println(rtc.readnvram (4));
  Serial.println(rtc.readnvram (5));
  Serial.println(rtc.readnvram (6));
  Serial.println(rtc.readnvram (7));
  Serial.println(rtc.readnvram (8));
  Serial.println(rtc.readnvram (9));
  Serial.println(rtc.readnvram (10));
  Serial.println(rtc.readnvram (11));


  delay(30000);
}

void dsSramRead(byte addr, byte *values, byte nBytes)
{
  Wire.beginTransmission(DS1307_ADDR);
  Wire.write(addr + RAM_OFFSET);
  Wire.endTransmission(false);
  Wire.requestFrom( (uint8_t)DS1307_ADDR, nBytes );
  for (byte i = 0; i < nBytes; i++) values[i] = Wire.read();
}
2020/9/27 (Sunday) 20:10:16
22
16
32
3
39
9
32
147
182
170
215
230
 
182
170
215
230
240
156
239
59
175
183
45
125

Nochmal: Das ist BCD kodiert. Lese nach was BCD ist und rechne das um. Das geht auch bequem mit dem Windows Taschenrechner wenn man sich die Binärdarstellung ansieht

22 -> 16
16 -> 10
32 -> 20
3 -> 3 (das sollte aber eher 1 sein für Sonntag)
39 -> 27
9 -> 9
32 -> 20 (Jahre haben nur zwei Stellen)

Die Registerwerte sind nicht nur BCD codiert sondern einzelne Bits haben auch noch bestimmte Bedeutungen wie zB 12/24 h Anzeige.

Verwende eine DS1307 Bibliothek die das Schreiben/Lesen aus dem RAM unterstützt. Das ist das einfachste.
Grüße Uwe

3 -> 3 (das sollte aber eher 1 sein für Sonntag)

Das ist ein Zähler, der unabhängig vom gestellten Datum ist.
Müsste ich jetzt nachsehen,ob 0..6 oder 1..7.
Wenn du ihn brauchst, musst du ihn eben richtig setzen, zusammen mit dem Datum.

michael_x:
Wenn du ihn brauchst, musst du ihn eben richtig setzen, zusammen mit dem Datum.

Das weiß ich. Aber ich hatte vielleicht etwas naiv angenommen dass das gemacht wurde :s