RTC DS3231 Modul - Dauerhaftes 1 Hz Signal aus SQW

Hallo liebe Community,
zuerst einmal: Ich bin noch ein blutiger Anfänger, also habt erbarmen mit mir.

Ich verzweifel im Moment etwas am RCT Modul (DS3231), welches mit dem UNO - Kit geliefert wird. Ich dachte die Funktionsweise wäre mir klar, aber scheinbar war ich doch etwas zu guter Dinge.

Folgendes Problem:

Ich möchte einfach nur mit dem DS3231 einen Interrupt zu einer bestimmten Uhrzeit an den Arduino senden. Alarm einstellen etc. klappt wunderbar. Aber aus dem SQW pin des Moduls kommt ein dauerhaftes Sinussignal, auch wenn die vorgegebene Uhrzeit noch nicht erreicht ist (ich kann an den Anschluss direkt eine LED anschließen, diese blinkt selbst ohne Code dauerhaft im Sinussignal). So wie ich das verstanden habe, soll dieses doch erst auftreten, wenn der Alarm getriggert wird oder verstehe ich das Modul jetzt komplett falsch?

Folgender Code wird genutzt (sollte keinen Fehler haben, da dies der Standartcode aus der Bibliothek ist und nicht von mir programmiert wurde). Die Verschaltung habe ich auch hochgeldaden.

Beste Grüße,
Olliwaa

/*
 DS3231: Real-Time Clock. Alarm simple
 Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-DS3231.html
 GIT: https://github.com/jarzebski/Arduino-DS3231
 Web: http://www.jarzebski.pl
 (c) 2014 by Korneliusz Jarzebski
*/

#include <Wire.h>
#include <DS3231.h>

DS3231 clock;
RTCDateTime dt;
boolean isAlarm = false;
boolean alarmState = false;
int alarmLED = 4;

void alarmFunction()
{
 Serial.println("*** INT 0 ***");
 isAlarm = true;
}

void setup()
{
 Serial.begin(9600);
 
 // Initialize DS3231
 Serial.println("Initialize DS3231");;
 clock.begin();

 // Disarm alarms and clear alarms for this example, because alarms is battery backed.
 // Under normal conditions, the settings should be reset after power and restart microcontroller.
 clock.armAlarm1(false);
 clock.armAlarm2(false);
 clock.clearAlarm1();
 clock.clearAlarm2();

 // Manual (Year, Month, Day, Hour, Minute, Second)
 clock.setDateTime(2014, 4, 25, 0, 0, 0);

 // Set Alarm1 - Every 20s in each minute
 // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true)
 clock.setAlarm1(0, 0, 0, 10, DS3231_MATCH_S);

 // Attach Interrput 0. In Arduino UNO connect DS3231 INT to Arduino Pin 2
 attachInterrupt(0, alarmFunction, FALLING);

 // Setup LED Pin
 pinMode(alarmLED, OUTPUT);
}

void loop()
{
 dt = clock.getDateTime();
 Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt));

 if (isAlarm)
 {
   digitalWrite(alarmLED, alarmState);
   alarmState = !alarmState;
   clock.clearAlarm1();
 } 

 delay(1000);
}

DS3231_intalarm.ino (1.52 KB)

Setze deinen Sketch in Code-Tags, dann kann ihn auch jeder lesen.
Verwende die Schaltfläche </> oben links im Editorfenster.

Genaueres über die RTC findest du im Datenblatt.
Und einiges schon hier: Rechteck 1Hz (+-2ppm) ausgeben mit dem RTC DS3231 und dem Arduino | Shelvin – Elektronik ausprobiert und erläutert
Wenn du Google bemühst, fndest du noh mehr Infos.

Ich denke das INTCN -Bit ist falsch gesetzt.

s.h. https://datasheets.maximintegrated.com/en/ds/DS3231.pdf

@Rintin

Das habe ich zuerst auch gedacht...

Ich habe auch schon wie Blöd Bits hin und her geschoben und das Datenblatt studiert. Kann es sein, dass meine Uhr einfach kaputt ist?

Olliwaa:
Ich habe auch schon wie Blöd Bits hin und her geschoben und das Datenblatt studiert. Kann es sein, dass meine Uhr einfach kaputt ist?

Möglich aber doch recht selten.
Funktioniert denn sonst alles, wie Datum und Uhrzeit ?

Dann evtl. die Alarmfunktion selbst programmieren.

Hast du mal einen kompletten Beispielcode in dem INTCN manipuliert wird?

Olliwaa:
Aber aus dem SQW pin des Moduls kommt ein dauerhaftes Sinussignal, auch wenn die vorgegebene Uhrzeit noch nicht erreicht ist (ich kann an den Anschluss direkt eine LED anschließen, diese blinkt selbst ohne Code dauerhaft im Sinussignal). So wie ich das verstanden habe, soll dieses doch erst auftreten, wenn der Alarm getriggert wird oder verstehe ich das Modul jetzt komplett falsch?

Das 'Sinussignal' ist ein Rechtecksignal und sollte bei richtiger Programmierung auch erst nach einem Alarm aktiv werden.

Active-Low Interrupt or Square-Wave Output. This open-drain pin requires an external pullup resistor connected
to a supply at 5.5V or less. This multifunction pin is determined by the state of the INTCN bit in the Control
Register (0Eh). When INTCN is set to logic 0, this pin outputs a square wave and its frequency is determined by
RS2 and RS1 bits. When INTCN is set to logic 1, then a match between the timekeeping registers and either of
the alarm registers activates the INT/SQW pin (if the alarm is enabled). Because the INTCN bit is set to logic 1
when power is first applied, the pin defaults to an interrupt output with alarms disabled. The pullup voltage can
be up to 5.5V, regardless of the voltage on VCC. If not used, this pin can be left unconnected.

Rintin:
Ich denke das INTCN -Bit ist falsch gesetzt.

s.h. https://datasheets.maximintegrated.com/en/ds/DS3231.pdf

Ja, das denke ich auch.

Hallo,

in meiner Anfangszeit hatte ich das auslesen und schreiben der Register mit Hilfe vom Forum zu Fuss gemacht. Habs auf das auslesen gekürzt :slight_smile: und alles nützliche reingepackt. Damit schauste dir mit Hifle vom Datenblatt die Register an um erstmal zu sehen was schief läuft beim experimentieren. Wenn das verstanden ist und du dich mit I2C näher befasst, schreibste dir noch die write Funktion selbst und fertig ist die Laube. Oder testest alle verfügbaren Lib. Je nach Forscherdrang,

/*
 Doc Arduino - german Arduino Forrum
 15.06.2018  (Ursprung 2015)
 Arduino Mega 2560
 DS3231 RTC Modul (I2C Bus)       
 alle Register & Temperatur auslesen
 */

#include <Wire.h>

#define RTC_I2C_ADDRESS 0x68    // I2C Adresse der RTC ist 0x68 für DS1307 und DS3231

unsigned int Sekunde, Minute, Stunde, Wochentag, Tag, Monat, Jahr;
byte addr_07, addr_08, addr_09, addr_0A, addr_0B, addr_0C, addr_0D, addr_0E, addr_0F, addr_11, addr_12;

char RtcDateTimeBuf[26];    // Buffer Datum & Zeit
char RtcTempBuf[8];         // Buffer Temperaturwert

void setup()  {
  Serial.begin(9600);    
  Wire.begin();             
}  

void loop(void) {

  update (5000);
  
}   // Ende loop


/* ------------------------------------------------------------------------------------------------ */

void update (unsigned int delay)
{
  static unsigned long last_ms = 0;

  if (millis() - last_ms < delay)  return;
  last_ms = millis();

  if (read_RTC_DS3231_Temp (RTC_I2C_ADDRESS) == true)  {  
    Serial.println("DS3231 I2C Busfehler");
  } 
  else {
    // Datum und Zeit für Ausgabe formatieren und in globalen String 'RtcDateTimeBuf' speichern
    snprintf(RtcDateTimeBuf,26,"%02d.%02d.%04d ; %02d:%02d:%02d",Tag,Monat,Jahr,Stunde,Minute,Sekunde);   
    Serial.println(RtcDateTimeBuf);
    ersetzt_Zeichen_in_charArray(RtcTempBuf, '.', ','); 
    Serial.print(F("RTC Temp: ")); Serial.println(RtcTempBuf);
  }

  if (read_RTC_DS3231_Register (RTC_I2C_ADDRESS) == true)  {     // RTC Register auslesen
    Serial.println("DS3231 I2C Busfehler");
  }
}


bool read_RTC_DS3231_Register (int i2c_adresse)
{                                          // aktuelle Zeit aus RTC auslesen
  boolean error = false;                   // Fehlerstatus setzen
  Wire.beginTransmission(i2c_adresse);     // Connect
  Wire.write(0x00);                        // Anfrage ab/der Register Nummer 00h
  if (Wire.endTransmission() > 0 )         // war Connect fehlerfrei?
    { 
     error = true;                         // I2C Busfehler
     return error;                         // Abruch
    } 
  Wire.requestFrom(i2c_adresse, 19);       // 19 Bytes in Folge anfordern/lesen, Register 07h bis 12h
  if (Wire.available() > 0 )               // sind Daten vorhanden?
    {
     Serial.println(F("Register:  Byte"));   
     Sekunde   = bcdToDec(Wire.read() & 0x7F);    // Maske für die ersten 7 Bits alleine
     Minute    = bcdToDec(Wire.read() );
     Stunde    = bcdToDec(Wire.read() & 0x3F);    // Umschaltung auf 24h statt 12h (AM/PM)
                          Wire.read();            // wäre der Wochentag
     Tag       = bcdToDec(Wire.read() );             
     Monat     = bcdToDec(Wire.read() );
     Jahr      = bcdToDec(Wire.read() ) + 2000;
     addr_07 = Wire.read();                       // Alarm 1 Sekunden
     addr_08 = Wire.read();                       // Alarm 1 Minuten
     addr_09 = Wire.read();                       // Alarm 1 Stunden
     addr_0A = Wire.read();                       // Alarm 1 Day/Date
     addr_0B = Wire.read();                       // Alarm 2 Minuten
     addr_0C = Wire.read();                       // Alarm 2 Stunden
     addr_0D = Wire.read();                       // Alarm 2 Day/Date
     addr_0E = Wire.read();                       // Control
     addr_0F = Wire.read();                       // Control/Status
               Wire.read();                       // Aging Offset, Register 0x10 wird ausgelassen
     addr_11 = Wire.read();                       // MSB of Temp
     addr_12 = Wire.read();  // LSB of Temp
     
    }  
    
  Serial.print("07: "); formatiere_Byte (addr_07); 
  Serial.print("08: "); formatiere_Byte (addr_08);  
  Serial.print("09: "); formatiere_Byte (addr_09); 
  Serial.print("0A: "); formatiere_Byte (addr_0A); 
  Serial.print("0B: "); formatiere_Byte (addr_0B); 
  Serial.print("0C: "); formatiere_Byte (addr_0C); 
  Serial.print("0D: "); formatiere_Byte (addr_0D);
  Serial.print("0E: "); formatiere_Byte (addr_0E); 
  Serial.print("0F: "); formatiere_Byte (addr_0F);  
  Serial.print("11: "); formatiere_Byte (addr_11);  // MSB of Temp
  Serial.print("12: "); formatiere_Byte (addr_12);  // LSB of Temp
  return error;  
}


bool read_RTC_DS3231_Temp (int i2c_adresse)  {  // RTC Temperatur auslesen  
  int data = 0;
  byte LSB = 0;
  float temp = 0.0;
    
  bool error = false;                      // Fehlerstatus setzen
  Wire.beginTransmission(i2c_adresse);     // Connect
  Wire.write(0x11);                        // Anfrage ab/der Register Nummer 11h
  if (Wire.endTransmission() > 0 )  {      // war Connect fehlerfrei?
    error = true;                          // I2C Busfehler
    return error;                          // Abbruch
  } 
  Wire.requestFrom(i2c_adresse, 2);        // 2 Bytes in Folge anfordern/lesen
  if (Wire.available() > 0 )  {            // sind Daten vorhanden?
    data = Wire.read();                    // 0x11h ... MSB of Temp
    data = data << 8;                      // MSB Bits ins höherwertige Byte im int verschieben
    LSB = Wire.read();                     // 0x12h ... LSB of Temp
    data = data | LSB;                     // LSB Bits in niederwertige Byte einfügen
  }  
  
  data = data >> 6;       // Ganzzahl gibt ein Vielfaches von 1/4 Grad an
  temp = (float) data * 0.25; 
  
  dtostrf(temp, 7, 2, RtcTempBuf);  // Input, Gesamtstellen inkl. Komma, Nachkommastellen, Output
  
  return error;  
}


void ersetzt_Zeichen_in_charArray (char *zeichenkette, char charSearch, char charReplace)
{
  int i = 0;
  while ( zeichenkette[i] != '\0')  {
    if ( zeichenkette[i] == charSearch )  {   // suche nach Zeichen 'charSearch' und
      zeichenkette[i] = charReplace;          // ersetze es durch 'charReplace'
    }
  i++;
  }
}


byte bcdToDec(byte val)  // convert binary coded decimal to decimal number
{
  return ( (val/16*10) + (val%16) );
}


void formatiere_Byte (byte data)
{  
  for (char i=7;i>=4;i--) {
    Serial.print(bitRead(data,i)); 
  }
  Serial.print('.');
  for (char i=3;i>=0;i--) {
    Serial.print(bitRead(data,i)); 
  }
  Serial.println();
}

Olliwaa:
Kann es sein, dass meine Uhr einfach kaputt ist?

Eher nicht, bei mir verhält es sich genauso. Eher macht die Bibliothek samt Beispielen auf den ersten Blick einen etwas schrägen Eindruck.

Versuche mal dies:

  // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true)
  clock.setAlarm1(0, 0, 0, 10, DS3231_MATCH_S);
  clock.enableOutput(false);

  pinMode(2, INPUT_PULLUP);
  // Attach Interrput 0. In Arduino UNO connect DS3231 INT to Arduino Pin 2
  attachInterrupt(0, alarmFunction, FALLING);

Dann gibt es immer zur zehnten Sekunde einen Interrupt, also um 21:56:10.