A DS3231 connected over I2c can be programmed to output a 1Hz square wave (rtc.writeSqwPinMode (DS3231_SquareWave1Hz);
) or nothing at all ( rtc.writeSqwPinMode (DS3231_OFF);
).
However, when setting the code for, for example 4kHz, (rtc.writeSqwPinMode (DS3231_SquareWave4kHz);
), the output remains at 1Hz.
What has to be changed so that the output changes to 1.024KHz, 4.096KHz or 8.192kHz when programmed as such with the code for this library RTClib.h?
//https://arduino.stackexchange.com/questions/29873/how-to-set-up-one-second-interrupt-isr-for-ds3231-rtc
#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 rtc;
const byte rtcTimerIntPin = 2;
volatile byte flag = false;
void rtc_interrupt ()
{
flag = true;
} // end of rtc_interrupt
void setup () {
Serial.begin(115200);
while (!Serial); // for Leonardo/Micro/Zero
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// enable the 1 Hz output
rtc.writeSqwPinMode (DS3231_SquareWave4kHz);
// set up to handle interrupt from 1 Hz pin
pinMode (LED_BUILTIN, OUTPUT);
pinMode (rtcTimerIntPin, INPUT_PULLUP);
attachInterrupt (digitalPinToInterrupt (rtcTimerIntPin), rtc_interrupt, CHANGE);
}
void loop () {
if (flag) {
digitalWrite(LED_BUILTIN, HIGH); // flash the led
delay(100); // wait a little bit
digitalWrite(LED_BUILTIN, LOW); // turn off led
flag = false; // clear the flag until timer sets it again
}
}
What has to be changed so that the output changes to 1.024KHz, 4.096KHz or 8.192kHz when programmed as such with the code for this library RTClib.h?
There is a library example fore RTClib.h which shows how to set the square wave for the DS1307. You should be able to easily modify it for the Ds3231. The key point is setting up the modes which link back to an enum in RTClib.h.
cattledog:
There is a library example fore RTClib.h which shows how to set the square wave for the DS1307. You should be able to easily modify it for the Ds3231. The key point is setting up the modes which link back to an enum in RTClib.h.
I had tried this example without modifications and of course it would not work: your comments gave me an idea: I changed all references from DS1307 to DS3231 (respecting the syntax of the RTClib library), but I get a compiler error on line 26:
exit status 1
cannot convert 'Ds1307SqwPinMode' to Ds3231SqwPinMode' in initialisation.
..even though in the RTClib library the enum for DS3231 is present:
// RTC based on the DS3231 chip connected via I2C and the Wire library
enum Ds3231SqwPinMode { DS3231_OFF = 0x01, DS3231_SquareWave1Hz = 0x00, DS3231_SquareWave1kHz = 0x08, DS3231_SquareWave4kHz = 0x10, DS3231_SquareWave8kHz = 0x18 };
class RTC_DS3231 {
public:
boolean begin(void);
static void adjust(const DateTime& dt);
bool lostPower(void);
static DateTime now();
static Ds3231SqwPinMode readSqwPinMode();
static void writeSqwPinMode(Ds3231SqwPinMode mode);
};
The code of the example, that I adapted for DS3231 (replace DS1307 by DS3231):
// SQW/OUT pin mode using a DS1307 RTC connected via I2C.
//
// According to the data sheet (http://datasheets.maxim-ic.com/en/ds/DS1307.pdf), the
// DS1307's SQW/OUT pin can be set to low, high, 1Hz, 4.096kHz, 8.192kHz, or 32.768kHz.
//
// This sketch reads the state of the pin, then iterates through the possible values at
// 5 second intervals.
//
// NOTE:
// You must connect a pull up resistor (~10kohm) from the SQW pin up to VCC. Without
// this pull up the wave output will not work!
#include <Wire.h>
#include "RTClib.h"
#if defined(ARDUINO_ARCH_SAMD)
// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero!
#define Serial SerialUSB
#endif
RTC_DS3231 rtc;
int mode_index = 0;
Ds3231SqwPinMode modes[] = {OFF, ON, SquareWave1HZ, SquareWave4kHz, SquareWave8kHz, SquareWave32kHz};
void print_mode() {
Ds3231SqwPinMode mode = rtc.readSqwPinMode();
Serial.print("Sqw Pin Mode: ");
switch(mode) {
case OFF: Serial.println("OFF"); break;
case ON: Serial.println("ON"); break;
case SquareWave1HZ: Serial.println("1Hz"); break;
case SquareWave4kHz: Serial.println("4.096kHz"); break;
case SquareWave8kHz: Serial.println("8.192kHz"); break;
case SquareWave32kHz: Serial.println("32.768kHz"); break;
default: Serial.println("UNKNOWN"); break;
}
}
void setup () {
#ifndef ESP8266
while (!Serial); // for Leonardo/Micro/Zero
#endif
Serial.begin(57600);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
print_mode();
}
void loop () {
rtc.writeSqwPinMode(modes[mode_index++]);
print_mode();
if (mode_index > 5) {
mode_index = 0;
}
delay(5000);
}
With this change there is no compile error.
//Ds3231SqwPinMode modes[] = {OFF, ON, SquareWave1HZ, SquareWave4kHz, SquareWave8kHz, SquareWave32kHz};
Ds3231SqwPinMode modes[] = { DS3231_OFF, DS3231_SquareWave1Hz, DS3231_SquareWave1kHz, DS3231_SquareWave4kHz, DS3231_SquareWave8kHz};
cattledog:
With this change there is no compile error.
//Ds3231SqwPinMode modes[] = {OFF, ON, SquareWave1HZ, SquareWave4kHz, SquareWave8kHz, SquareWave32kHz};
Ds3231SqwPinMode modes[] = { DS3231_OFF, DS3231_SquareWave1Hz, DS3231_SquareWave1kHz, DS3231_SquareWave4kHz, DS3231_SquareWave8kHz};
Nice!
But why do I have to include "DS3231_" for each mode? In the RTClib library the "ON", "OFF", "SquareWave1Hz", etc.. are included in the class RTC_DS3231.
And why is "ON" not present (I get a compiler error when I include "DS3231_ON")?
cattledog:
With this change there is no compile error.
//Ds3231SqwPinMode modes[] = {OFF, ON, SquareWave1HZ, SquareWave4kHz, SquareWave8kHz, SquareWave32kHz};
Ds3231SqwPinMode modes[] = { DS3231_OFF, DS3231_SquareWave1Hz, DS3231_SquareWave1kHz, DS3231_SquareWave4kHz, DS3231_SquareWave8kHz};
When I execute this code, the serial output screen gives lines with "Sqw Pin Mode: OFF" and 2 lines with "Sqw Pin Mode: 1Hz", continually.
The SQW output on a scope is permanent 1Hz
When I change the switch(mode) code @ line 35 to:
switch(mode) {
case DS3231_OFF: Serial.println("OFF"); break;
//case DS3231_ON: Serial.println("ON"); break;
case DS3231_SquareWave1Hz: Serial.println("1Hz"); break;
case DS3231_SquareWave4kHz: Serial.println("4.096kHz"); break;
case DS3231_SquareWave8kHz: Serial.println("8.192kHz"); break;
//case DS3231_SquareWave32kHz: Serial.println("32.768kHz"); break;
default: Serial.println("UNKNOWN"); break;
}
the serial output changes nicely, but not the SQW physical output: that stays at 1Hz
EDIT: "changes nicely", correction: serial print gives 4 lines with 1Hz and 2 lines with 4.096kHz
EDIT2: Just to make sure: I measure with a scope on the SQW pin of the DS3231, using 2k2 pullup to Vcc.
Now using a program (source: Arduino Crystal vs. DS3231 TXCO | µC eXperiment to write directly into the chip registers. Even then no other frequency gets output except 1Hz or static 5V on SQW.
EDIT: I edit line 98 Wire.write(8);
with values 8=1024Hz, 0=1Hz, etc..
What is the reason?
//https://ucexperiment.wordpress.com/2012/02/10/arduino-crystal-vs-ds3231-txco/
/*
1 Hz Test
Copyright 2012, all rights reserved.
James M. Eli
1/9/2012
project parts:
(1) arduino 16MHz
(1) ChronoDot RTC (DS3231SN)
(1) breadboard
(1) 10 ohm resister (pullup)
(7) wires
DS3231SN TXCO RTC (ChronoDot) pin outs:
CD - Arduino - Port
SQW - D2 - Port D2 (tied thru 10K resister to VCC)
GND - GND - Ground
VCC - VCC - 5V
*/
#include <Wire.h>
//millisecond counter
volatile unsigned long my_timer0_millis;
//ms counters for arduino & TXC0
volatile unsigned long us_t, us_a;
//boolean flag
volatile bool flag;
//this interrupt is called on a TCXO RTC 1Hz SQW
ISR(INT0_vect) { //PD2 or D2 pin
unsigned long m;
uint8_t t;
//assumptions here: arduino 168/328 running @ 16MHz
m = my_timer0_millis;
t = TCNT0;
if ((TIFR0 & _BV(TOV0)) && (t < 249))
m++;
//save current microsecond [us] count
us_a = ((m*250) + t)*(64/clockCyclesPerMicrosecond());
//set flag
flag = true;
}
//timer0 interrupt handler
ISR(TIMER0_COMPA_vect) {
//incremented every 1ms by arduino timer0
my_timer0_millis++;
}
//returns current millis count
unsigned long myMillis(void) {
unsigned long m;
uint8_t oldSREG;
oldSREG = SREG;
cli();
m = my_timer0_millis;
SREG = oldSREG;
return m;
}
void setup(void) {
//init various
us_t = 0;
flag = false;
//turn off interrupts
cli();
//replace arduino timer0 code with our timer
my_timer0_millis = 0;
//16Mhz/64 prescale/250 counts = 16000000/64/250 = 1000us (1ms)
TCCR0A = 0;
TCCR0A |= (1<<WGM01); //CTC mode, top=OCR0A, TOV0 set@max, update immediate
TCCR0B = 0;
TCCR0B |= (1<<CS01) | (1<<CS00); //Fcpu/64
TIMSK0 |= (1<<OCIE0A); //enable CTC A interrupt
OCR0A = 249; //249 results in a 250 count rollover
TCNT0 = 0;
//setup digital #2 external interrupt
EICRA |= (1<<ISC00) | (1<<ISC01);
EIMSK |= (1<<INT0);
//enable interrupts
sei();
//init wire & serial
Wire.begin();
Serial.begin(9600);
//setup square wavew at choice of 0=1Hz/8=1024Hz/16=4096Hz/24=8192Hz
Wire.beginTransmission(104);
//select control register
Wire.write(0x0e);
//set square wave @ 1 Hz
Wire.write(8);
Wire.endTransmission();
}
void loop(void) {
Serial.println("# Starting Test");
while(1) { //endless loop
if (flag) {
if (us_t == 0)
us_t = us_a;
else
us_t += 1000000;
Serial.print(us_t/1000000);
Serial.print(", ");
Serial.println(us_a - us_t);
flag = false;
} //if
} //while
} //loop
What is the reason?
I don't understand, as I can see varying output with the sketch you provided. Your rtc may be defective.
Using 2K2 pullup on the output pin and a scope should show varying square waves when writing to register 0x0E as you have done.
Here is a simple sketch which reads the square wave output. Jumper the square wave output pin to D2. The internal pullup on D2 appears sufficient in my setup.
#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
volatile unsigned long count = 0;
unsigned long copyCount = 0;
unsigned long sumCount = 0;
unsigned long lastSumCount;
unsigned long lastRead = 0;
void setup()
{
Wire.begin();
Serial.begin(115200);
Serial.println("start...");
pinMode(2, INPUT_PULLUP);
attachInterrupt(0, isrCount, RISING);
//writeNVRAM(0X0E, B00000000);//1Hz sqw
writeNVRAM(0X0E, B00001000);//1.024 KHz sqw
//writeNVRAM(0X0E, B00010000);//4.096KHz sqw
//writeNVRAM(0X0E, B00011000);//8.192KHz sqw
}
void loop()
{
if (millis() - lastRead >= 1000) //readinterrupt count every second
{
lastRead = millis();
// make copy of count, disable interrupts while copying, then reenable
noInterrupts();
copyCount = count;
count = 0; // reset counter in isr
interrupts();
}
//process interrupt count data
sumCount = sumCount + copyCount;
if (sumCount != lastSumCount)
{
Serial.print(copyCount);
Serial.print('\t');
Serial.println(sumCount);
copyCount = 0;
lastSumCount = sumCount;
}
}
void isrCount()
{
count++;
}
void writeNVRAM(byte location, byte data)
// writes data to DS3231 NVRAM location
{
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(location);
Wire.write(data);
Wire.endTransmission();
}
cattledog:
I don't understand, as I can see varying output with the sketch you provided. Your rtc may be defective.
Using 2K2 pullup on the output pin and a scope should show varying square waves when writing to register 0x0E as you have done.
Here is a simple sketch which reads the square wave output. Jumper the square wave output pin to D2. The internal pullup on D2 appears sufficient in my setup.
I tried your program with my current rtc, as well as with a brand new out-of-the-box unit: same results, only 1Hz.
RTC's both are SOIC DS3231M, with M being indicative of a version with non-programmable frequencies.
I just found out. After looking with magnifying glass to the chip.

DS3231M I2C RTC real-time clock.pdf (891 KB)
RTC's both are SOIC DS3231M, with M being indicative of a version with non-programmable frequencies.
Good catch. I was not aware of his chip. Is it being used in a module? If so, which one?
I'm sure this issue will come up again in the forum if this chip becomes widely used in something like the ZS-042.
As you've discovered, the M version can only output 1Hz on the SQW pin.
I have the DS3231 and the code below makes it output a 1024Hz square wave on the SQW pin.
Wire.beginTransmission(CLOCK_ADDRESS);
Wire.write(0x0e); //select control register
Wire.write(0x08);
Wire.endTransmission();
0x10 generates 4096Hz and 0x18 generates 8192HZ (and 0x00 is 1Hz).
Pete
cattledog:
Good catch. I was not aware of his chip. Is it being used in a module? If so, which one?
I'm sure this issue will come up again in the forum if this chip becomes widely used in something like the ZS-042.
https://www.aliexpress.com/item/DS3231-AT24C32-IIC-Module-Precision-Clock-Module-without-battery-DS3231SN-for-Arduino-Memory-module/32822420722.html?spm=a2g0s.9042311.0.0.AfATFw
Edit: it shows the DS3231SN module on the picture of the chip -which would be ok-, but in fact the DS3231M was delivered.
brice3010:
RTC's both are SOIC DS3231M, with M being indicative of a version with non-programmable frequencies.
Thanks so much for posting the link to that datasheet. The datasheet I have is for the DS3231S/SN and doesn't mention the DS3231M at all. Don't know why they would put out two separate datasheets for nearly identical chips.
Now that I know the difference, I've looked at my three DS3231 boards. One, a "ZS-042" I bought off amazon is the M, but another ZS-042 and my Adafruit Chronodot are the SN.
And I can confirm that the chips marked DS3231SN support the higher SQW rates.