Отстает время на DS3231

Volen
Offline
Зарегистрирован: 29.04.2018

Доброго времени суток друзья. Решил собрать часы на ГРИ. Нашел в инете схему и код. Использовал arduino nano и ds3231 которые заказал на китайском сайте.

Часы работают, но отстают на 2 секунды за час. ds3231 отмыл от флюса и выпаял диод который идёт на зарядку акума ( акума нет. стоит батарйка.) после выше описанных манипуляций часы так и отстают. воткнул  другой модуль и часы начали отставать примерно на 4 сек в час.
Вот код


#include <iarduino_RTC.h>
iarduino_RTC time(RTC_DS3231);
const int def_pin[] = {A3, A1, A0, A2};//выводы для дешифратора defPin[out1,out2,out4,out8];
const char dictionary_of_number[10][4] = { //словарь цифр
  {1, 0, 0, 1},//0
  {0, 0, 0, 1},//1
  {0, 0, 0, 0},//2
  {1, 0, 1, 0},//3
  {0, 1, 1, 0},//4
  {0, 1, 0, 0},//5
  {1, 1, 0, 0},//6
  {1, 1, 1, 0},//7
  {0, 0, 1, 0},//8
  {1, 0, 0, 0},//9
};
const int button_pin = 12; //пин для считывания кнопок
const int keys_pin[] = {8, 7, 6, 5, 4, 2};// выводы для транзисторных ключей
int mass_but[] = {0, 0, 0, 0, 0, 0};//массив для состояние кнопок
int time_date[] = {0, 0, 0, 0, 0, 0}; // массив где хранится временя или дата
bool swap_time_date = true, setting_flag = false, open_scroll = false; //переменные для меню
unsigned long last_time_scroll, last_scroll = 0,interval_scroll = 300000;
long counter1 = 0;
int p = 7, k = 0, lock = 0; //переменные для счетчиков

void setup() {
  TCCR1B = TCCR1B & 0b11111000 | 0x01;  // задаем частоту ШИМ на 3 выводе 30кГц
  analogWrite(9, 150); //если запитывать от блока питания 9в
  //задаем режим работы выходов микроконтроллера
  for (int i = 0; i < 4; i++) {
    pinMode(def_pin[i], OUTPUT);
  }
  for (int i = 0; i < 6; i++) {
    pinMode(keys_pin[i], OUTPUT);
  }
  time.begin();
}

void loop() {
  k++;//счетчик для мигания цифрами
  check_time_date();
  button();
  //делам прогон всех цифр во избежание "Отравление" катодов ламп
if (((millis() - last_scroll >= interval_scroll) || open_scroll) && !setting_flag) {
scroll(25);
if (swap_time_date && !open_scroll) {
interval_scroll = 10000;//время которое будет показывать дату
} else {
interval_scroll = 300000;//интервал следующего свапа
}
swap_time_date = !swap_time_date;
last_scroll = millis();
open_scroll = false;
}
  show_numbers(time_date);
}

//вывод времени
void show_numbers(int a[])
{
  for (int i = 0; i < 6; i++)
  {
    set_number(a[i]);//передаем сигналы для a[i] цифры
    digitalWrite(keys_pin[i], HIGH);//подаем сигнал на keysPin[i] индикатор
    if (!((i == p || i == p - 1) && (k > 50))) {//задержка между лампами
      delay(1);
    }
    mass_but[i] = digitalRead(button_pin);//опрос кнопок i-й кнопки
    digitalWrite(keys_pin[i], LOW);//потушим keysPin[i] индикатор
    if ((i == p) && (k > 50)) {//задержка для мигания отдельных разрядов
      delay(1);
    }
    if (k > 100) {
      k = 0;
    }
  }
}

//пебора всех цифр
void scroll(int pause) {
  for (int i = 0; i < 9; i++) {
    int a[] = {i, i, i, i, i, i};
    show_numbers(a);
    delay(pause);
    show_numbers(a);
  }
}

//меню
void button() {
  if (mass_but[1] || mass_but[2]) {//организация долгово зажатия 2й и 3й кнопки
    bool do_It = false;
    counter1++;//счетчик будет увеличиваться пока кнопка зажата
    if (counter1 > 200) {
      if ((counter1 % 10) == 0) {
        do_It = true;
      }
    }
    else if (counter1 >= 60) {
      if ((counter1 % 50) == 0) {
        do_It = true;
      }
    }
    else if (counter1 == 4) {
      do_It = true;
    }
    if (do_It && setting_flag && mass_but[1] && !mass_but[2]) { //кнопка "+"
      time_date[p]++;
      config_plus();//проверка допустимых значение
    }
    if (do_It && setting_flag && mass_but[2] && !mass_but[1]) {//кнопка "-"
      time_date[p]--;
      config_minus();//проверка допустимых значение
    }
  }
  if (!lock) {
    if (mass_but[0]) {
      if (!setting_flag) {//кнопка переключение  между датой и временем
        open_scroll = true;
      }
      else {//если часы находятся в режиме настройке, то кнопка переключает разряды
        p -= 2;
        if (p < 0) p = 5;
      }
    }
    //кнопка входа в режим настройки
    else if (mass_but[3]) {
      p = 5; k = 0;
      setting_flag = !setting_flag;
      if (!setting_flag) {//после того как кнопка была нажата повторна
        update_time_date();
        p = 7;
      }
    }
  }
  lock = mass_but[0] || mass_but[3];//чтобы ардуина считала одно нажатие даже при зажатой кнопки
}

//ограничения времени при добовления
void config_plus() {
  int sec_year = time_date[4] * 10 + time_date[5];//сек и года
  int min_mon = time_date[2] * 10 + time_date[3];//мин и месеца
  int hour_days = time_date[0] * 10 + time_date[1];//часы и дни
  //если младший разряд больше 9 то увеличить на 1 старший разряд и младший обнулить
  if (time_date[p] > 9) {
    time_date[p - 1]++;
    time_date[p] = 0;
  }
  if (swap_time_date) { //ограничения для времени
    if (hour_days > 23) {
      time_date[0] = 0; time_date[1] = 0;
    }
    if (min_mon > 59) {
      time_date[2] = 0; time_date[3] = 0;
    }
    if (sec_year > 59) {
      time_date[4] = 0; time_date[5] = 0;
    }
  }
  else { //ограничение для даты
    if (sec_year > 99) { //ограничение по годом не больше 99
      time_date[4] = 0; time_date[5] = 0;
    }
    if (min_mon > 12) { //ограничение по месецам не больше 12
      time_date[2] = 0; time_date[3] = 0;
    }
    //ограничение для дней не больше 31 или 30 или 29 дней в определенные месяца
    if ((min_mon == 1 || min_mon == 3 || min_mon == 5 || min_mon == 6 || min_mon == 7 || min_mon == 8 || min_mon == 10 || min_mon == 12) && hour_days > 31) {
      time_date[0] = 0; time_date[1] = 0;
    }
    else if (( min_mon == 4 || min_mon == 6 || min_mon == 9 || min_mon == 11) && hour_days > 30) {
      time_date[0] = 0; time_date[1] = 0;
    }
    else if (min_mon == 2 && hour_days > 29) {
      time_date[0] = 0; time_date[1] = 0;
    }
  }
}

//ограничения времени при вычитании
void config_minus() {
  int sec_year = time_date[4] * 10 + time_date[5];//сек и года
  int min_mon = time_date[2] * 10 + time_date[3];//мин и месеца
  int hour_days = time_date[0] * 10 + time_date[1];//часы и дни
  //если младший разряд мешьше 0 то уменьшить на 1 старший разряд и младший передать 9
  if (time_date[p] < 0) {
    time_date[p - 1]--;
    time_date[p] = 9;
  }
  if (swap_time_date) { //ограничения для времени
    if (hour_days < 0) {
      time_date[0] = 2; time_date[1] = 3;
    }
    if (min_mon < 0) {
      time_date[2] = 5; time_date[3] = 9;
    }
    if (sec_year < 0) {
      time_date[4] = 5; time_date[5] = 9;
    }
  }
  else { //ограничения для даты
    if (sec_year < 0) {    //ограничение по годом
      time_date[4] = 9; time_date[5] = 9;
    }
    if (min_mon < 0) { //ограничение по месецам если меньше нуля по выводить 12й месяц
      time_date[2] = 1; time_date[3] = 2;
    }
    //ограничение для дней не больше 31 или 30 или 29 дней в определенные месяца
    if ((min_mon == 1 || min_mon == 3 || min_mon == 5 || min_mon == 6 || min_mon == 7 || min_mon == 8 || min_mon == 10 || min_mon == 12) && hour_days < 0) {
      time_date[0] = 3; time_date[1] = 1;
    }
    else if (( min_mon == 4 || min_mon == 6 || min_mon == 9 || min_mon == 11) && hour_days < 0) {
      time_date[0] = 3; time_date[1] = 0;
    }
    else if (min_mon == 2 && hour_days < 0) {
      time_date[0] = 2; time_date[1] = 9;
    }
  }
}

//обращение к модулю и сохрание времени в массив
void check_time_date() {
  time.gettime(); //считываем время и дату с DS3231
  if (!setting_flag) {//если вышли из режима настройки
    if (swap_time_date) {//если мы отображали время то и будем настраивать время иначе будем настраивать дату
      time_date[0] = time.Hours / 10;
      time_date[1] = time.Hours % 10;
      time_date[2] = time.minutes  / 10;
      time_date[3] = time.minutes  % 10;
      time_date[4] = time.seconds  / 10;
      time_date[5] = time.seconds  % 10;
    }
    else {
      time_date[0] = time.day  / 10;
      time_date[1] = time.day  % 10;
      time_date[2] = time.month  / 10;
      time_date[3] = time.month % 10;
      time_date[4] = time.year / 10;
      time_date[5] = time.year % 10;
    }
  }
}

//обновления врмени и даты
void update_time_date() {
  if (swap_time_date) {
    time.settime(time_date[4] * 10 + time_date[5],//секунды 
                 time_date[2] * 10 + time_date[3],//минуты
                 time_date[0] * 10 + time_date[1],//часы
                 -1, -1, -1);
  }
  else {
    time.settime(-1, -1, -1,
                  time_date[0] * 10 + time_date[1],//день
                  time_date[2] * 10 + time_date[3],//месяц
                  time_date[4] * 10 + time_date[5]);//год
  }
}

//вывод опеределенной цифры
void set_number(int num) {
  for (int i = 0; i < 4; i++) {//цикл по словарю и взависимости от цифры в словаре подаем сигнал на к155ид1
    digitalWrite(def_pin[i], dictionary_of_number[num][i]);
  }
}

В коде ничего не понимаю от слова совсем и надюсь на вашу помощь.
Можно ли сделать коррекцию времени на уровне кода т.е +2 эти несчастные секунды.

Также прилагаю библиотеку часов.

#ifndef iarduino_RTC_DS3231_h
#define iarduino_RTC_DS3231_h
#define	RTC_DS3231 3																//	Модуль часов реального времени с протоколом передачи данных I2C, памятью 019x8, температурной компенсацией, двумя будильниками и встроенным кварцевым резонатором

class iarduino_RTC_DS3231: public iarduino_RTC_BASE{

	public:

//		Инициализация модуля:
		void	begin(void){																														//		(без параметров)
//					Инициализация работы с шиной I2C:
					funcBegin(100);																													//		(скорость шины в кГц)
//					Установка флагов управления и состояния модуля:
					varI=funcReadReg(0x02); if( varI & 0b01000000                         ){funcWriteReg(0x02, (varI&~0b01000000)            );}	//		(если установлен 6 бит в 2 регистре, то сбрасываем его - переводим модуль в 24 часовой режим)
					varI=funcReadReg(0x0E); if( varI & 0b11011111                         ){funcWriteReg(0x0E, (varI&~0b11011111)            );}	//		(если установлены 7,6,4,3,2,1 и 0 биты в 14 регистре, то сбрасываем их - разрешаем генератору работать от батарейки, запрещаем выводу SQW работать от батарейки, выводим меандр с частотой 1Гц на вывод SQW, переводим вывод INT/SQW в режим SQW, запрещаем прерывания будильников)
					varI=funcReadReg(0x0F); if((varI & 0b10000011) || !(varI & 0b00001000)){funcWriteReg(0x0F, (varI&~0b10000011)|0b00001000 );}	//		(если установлены 7,1 и 0 биты или сброшен 3 бит в 15 регистре, то сбрасываем 7,1 и 0 биты, а 3 устанавливаем - сбрасываем флаг остановки генератора, разрешаем меандр с частотой 32768Гц на выводе 32kHz, сбрасываем флаги будильников)
		}

//		Чтение одного значения из регистров даты и времени модуля:
		uint8_t	funcReadTimeIndex(uint8_t i){delay(1); return funcReadReg(arrTimeRegAddr[i]) & arrTimeRegMack[i];}									//		(i = 0-секунды / 1-минуты / 2-часы / 3-день / 4-месяц / 5-год / 6-день недели)

//		Запись одного значения в регистры даты и времени модуля:
		void	funcWriteTimeIndex(uint8_t i, uint8_t j){																							//		(i = 0-секунды / 1-минуты / 2-часы / 3-день / 4-месяц / 5-год / 6-день недели, j = значение)
					varI=funcReadTimeIndex(i);																										//		Читаем данные из регистра i
					j |= ~arrTimeRegMack[i] & varI;																									//		Устанавливаем биты значения j по маске arrTimeRegMack[i] в прочитанные из регистра i
					j &=  arrTimeRegMack[i] | varI;																									//		Сбрасываем    биты значения j по маске arrTimeRegMack[i] в прочитанные из регистра i
					funcWriteReg(arrTimeRegAddr[i], j);																								//		Сохраняем значение j в регистр arrTimeRegAddr[i]
		}

	private:

	/**	Внутренние переменные **/

		uint8_t	valAddress				=	 0x68;									//	Адрес модуля на шине I2C
		uint8_t	arrTimeRegAddr[7]		=	{0x00,0x01,0x02,0x04,0x05,0x06,0x03};	//	Определяем массив с адресами регистров даты и времени				(сек, мин, час, день, месяц, год, день недели)
		uint8_t	arrTimeRegMack[7]		=	{0x7F,0x7F,0x3F,0x3F,0x1F,0xFF,0x07};	//	Определяем маскировочный массив для регистров даты и времени		(при чтении/записи, нужно совершить побитовое «и»)
		uint8_t	varI;

	/**	Внутренние функции **/

//		Функция чтения данных из регистра модуля:
		uint8_t	funcReadReg(uint8_t i){												//	Определяем функцию читения данных из регистра модуля				(аргумент: адрес_регистра)
					varI=1;															//	Предустанавливаем переменную varI в значение 1, чтоб не вывести: 45 апреля 255 часов 127 минут и 200 секунд
					if (	funcStart		()				){						//	Если на шине I2C установилось состояние START, то ...
					if (	funcSendID		(valAddress,0)	){						//	Если модуль ответил ACK на получение адреса устройства valAddress с битом RW=0 (запись), то ...
					if (	funcWriteByte	(i)				){						//	Если модуль ответил ACK на получение адреса регистра i, то ...
					if (	funcReStart		()				){						//	Если на шине I2C установилось состояние RESTART, то ...
					if (	funcSendID		(valAddress,1)	){						//	Если модуль ответил ACK на получение адреса устройства valAddress с битом RW=1 (чтение), то ...
					varI =	funcReadByte	(false);								//	Читаем байт в переменную varI с отправкой бита NACK по шине I2C
					}}}}}	funcStop();												//	Устанавливаем состояние STOP на шине I2C
					return	varI;													//	Возвращаем значение переменной varI
		}

//		Функция записи данных в регистр модуля:
		bool	funcWriteReg(uint8_t i, uint8_t j){									//	Определяем функцию записи данных в регистр модуля					(аргументы: адрес_регистра, байт_данных)
							varI=1;													//	Сбрасываем переменную varI в 0
					if (	funcStart		()				){	varI=1;				//	Если на шине I2C установилось состояние START, то ...
					if (	funcSendID		(valAddress,0)	){	varI=2;				//	Если модуль ответил ACK на получение адреса устройства valAddress с битом RW=0 (запись), то ...
					if (	funcWriteByte	(i)				){	varI=3;				//	Если модуль ответил ACK на получение адреса регистра i, то ...
					if (	funcWriteByte	(j)				){	varI=4;				//	Если модуль ответил ACK на получение байта данных j, то ...
					}}}}	funcStop		();		return		varI==4;			//	Отправляем команду STOP и возвращаем результат записи
		}

	/**	функции для работы с шиной I2C **/
		void	funcBegin		(uint32_t j)		/*	Установка регистров шины и подтяжка выводов	(скорость шины в кГц)			*/	{pinMode(SDA, INPUT); pinMode(SCL, INPUT); digitalWrite(SDA, 1); digitalWrite(SCL, 1); TWBR=((F_CPU/(j*1000))-16)/2; if(TWBR<10){TWBR=10;} TWSR&=(~(_BV(TWPS1)|_BV(TWPS0)));                                                                 }
		bool	funcStart		(void)				/*	Установка состояния START					(без параметров)				*/	{uint16_t i=0;                  TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA); while(!(TWCR & _BV(TWINT))){i++; if(i>60000){return false;}} if((TWSR & 0xF8)==0x08)     {return true;}                                             return false;}
		bool	funcReStart		(void)				/*	Установка состояния RESTART					(без параметров)				*/	{uint16_t i=0;                  TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA); while(!(TWCR & _BV(TWINT))){i++; if(i>60000){return false;}} if((TWSR & 0xF8)==0x10)     {return true;}                                             return false;}
		void	funcStop		(void)				/*	Установка состояния STOP					(без параметров)				*/	{uint16_t i=0;                  TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO); while(!(TWCR & _BV(TWSTO))){i++; if(i>60000){break;       }} delayMicroseconds(20);                                                                              }
		bool	funcSendID		(uint8_t j, bool k)	/*	Передача  первого байта						(ID-адрес модуля, бит RW)		*/	{uint16_t i=0; TWDR = (j<<1)+k; TWCR = _BV(TWINT) | _BV(TWEN);              while(!(TWCR & _BV(TWINT))){i++; if(i>60000){return false;}} if((TWSR & 0xF8)==0x40 && k){return true;} if((TWSR & 0xF8)==0x18 && !k){return true;} return false;}
		bool	funcWriteByte	(uint8_t j)			/*	Передача  одного  байта						(байт для передачи)				*/	{uint16_t i=0; TWDR =  j;       TWCR = _BV(TWINT) | _BV(TWEN);              while(!(TWCR & _BV(TWINT))){i++; if(i>60000){return false;}} if((TWSR & 0xF8)==0x28)     {return true;}                                             return false;}
		uint8_t	funcReadByte	(bool j)			/*	Получение одного  байта						(бит подтверждения ACK/NACK)	*/	{uint16_t i=0;                  TWCR = _BV(TWINT) | _BV(TWEN) |  j<<TWEA;   while(!(TWCR & _BV(TWINT))){i++; if(i>60000){return 0;    }} if((TWSR & 0xF8)==0x50 && j){return TWDR;} if((TWSR & 0xF8)==0x58 && !j){return TWDR;} return 0;    }
};

#endif

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Volen пишет:
В коде ничего не понимаю от слова совсем и надюсь на вашу помощь.
Боюсь, напрасно надеешься.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Volen пишет:

Решил собрать часы на ГРИ.

...

В коде ничего не понимаю от слова совсем

А с какой целью?

Volen
Offline
Зарегистрирован: 29.04.2018

А с какой целью решил собрать часы на гри? Они красиво светят своими газоразрядными индикаторами. Самими часами то доволен, а вот модулем ds3231 нет. т.к он отстает на 2 сек в час. И прошу у вас помощи в програмной корекции.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ну программно подводи на 2 секунды в час вперед. И да записывай в EEPROM время последнего подвода. Но если не понимашь что я сказал, то учитесь сами. Я в этом не виноват, и делать за вас не хочу.

sadman41
Offline
Зарегистрирован: 19.10.2016

Зачем дома точность в 2 сек/час? Раз в сутки плюсовать и хватит вполне.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Нет, надо переводить про секунде каждые полчаса.

Genri5
Offline
Зарегистрирован: 31.05.2016

Ну я бы, для себя, прояснил в чем проблема. Потому что у меня на DS3231 собрано двое часов(матричные и в погодной станции) и никаких проблем нет. Поэтому, в интернете полно программ, потестируйте модуль. Может действительно левая DS3231 - поменяйте. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Можно и по секунде каждые полчаса, не суть. Если секунды не отображаются, то для дома вообще не критично. А в целом Genri5 прав - надо не подводить, а понять, почему отстают. Был бы такой хреновый чип по дефолту - давно бы уже контора раззорилась.

Volen
Offline
Зарегистрирован: 29.04.2018

sadman41 пишет:

Можно и по секунде каждые полчаса, не суть. Если секунды не отображаются, то для дома вообще не критично. А в целом Genri5 прав - надо не подводить, а понять, почему отстают. Был бы такой хреновый чип по дефолту - давно бы уже контора раззорилась.

заказал на китайском сайте. сам модуль стоит в 2 раза дешевле чем орининальный чип

sadman41
Offline
Зарегистрирован: 19.10.2016

Volen пишет:

заказал на китайском сайте. сам модуль стоит в 2 раза дешевле чем орининальный чип

Все мы заказываем на китайских сайтах. Кому-то везет, кому-то не везет. Я получил давеча два PT100 от одного продавца, скрутил вместе, сунул в воду, подождал и измерил сопротивление - разнится. По таблице - разбег в градус-полтора. Хотя, казалось бы - где тут можно накосячить в терморезисторе?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Volen пишет:

sadman41 пишет:

Можно и по секунде каждые полчаса, не суть. Если секунды не отображаются, то для дома вообще не критично. А в целом Genri5 прав - надо не подводить, а понять, почему отстают. Был бы такой хреновый чип по дефолту - давно бы уже контора раззорилась.

заказал на китайском сайте. сам модуль стоит в 2 раза дешевле чем орининальный чип


"...не гонялся бы ты поп за дешевизной"
правда с китаем так, высокая стоимость не означает качество, тут как-то тема прбегала про плохие стабизаторы на 3,3 и пять вольт из серии 1ххх, и дескать на них нельзя строить надёжную аппаратуру, разбирался, строить можно, но только на оригинальных, берем лупу максимального увеличения и смотрим маркировку, технологии маркировки видимо в поднебесную не передают )))

Genri5
Offline
Зарегистрирован: 31.05.2016

У меня знакомый, тоже ругался на DS3231. А покупал он на алиэкспресс. Я на радиорынке у проверенного продавца. Поделился с ним и у него о микросхеме мнение изменилось. Делайте выводы. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Genri5 пишет:
Я на радиорынке у проверенного продавца.
Продавец китаец и у него в гараже своя фабрика по производству микросхем. И у него этих микросхем как гуталину. Который он шлет куда попало.

https://www.youtube.com/watch?v=_b4hF8FNdvU

Genri5
Offline
Зарегистрирован: 31.05.2016

Я хотел сказать, что хочется  дешевле, будь готов получить геморой.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Genri5, Вы не понимаете главного. Все что поставляется с али это банальная отбраковка. Сделали партию, не вошла в нормы , или излишек производства , то все на Али.  Обычные китайские предприятия не рассматривают вас как покупателя. Вы же не заказываете миллионами их. А так извини подвинься. А то что купили на рынке у проверенного продавана .Так и он не интересут китайских производителей. А жаловаться на китайских продовцов мусора, что их мусор плохого качества, это что издевка над форумом. Ну а что делать если китайский мусор он дешев и доступен радиолюбителям всего мира. 

Genri5
Offline
Зарегистрирован: 31.05.2016

Да нет, я как раз это и понимаю. Я, к примеру, предпочитаю покупать у официальных дилеров. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

У вас что есть человек в Китае, который покупает напрямую с предприятий?? 

SLKH
Offline
Зарегистрирован: 17.08.2015

До предъявления обвинений китайским труженикам стоило бы проверить часовую плату на максимально урезанном скетче - только чтение из часов и вывод в монитор, без всех извращений с индикацией.

Ну и http://arduino.ru/forum/obshchii/ds3231-otstayut-na-1-minutu-za-sutki , см. #18 и #19