Отстает время на DS3231
- Войдите на сайт для отправки комментариев
Вс, 29/04/2018 - 20:16
Доброго времени суток друзья. Решил собрать часы на ГРИ. Нашел в инете схему и код. Использовал 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
Решил собрать часы на ГРИ.
...
В коде ничего не понимаю от слова совсем
А с какой целью?
А с какой целью решил собрать часы на гри? Они красиво светят своими газоразрядными индикаторами. Самими часами то доволен, а вот модулем ds3231 нет. т.к он отстает на 2 сек в час. И прошу у вас помощи в програмной корекции.
ну программно подводи на 2 секунды в час вперед. И да записывай в EEPROM время последнего подвода. Но если не понимашь что я сказал, то учитесь сами. Я в этом не виноват, и делать за вас не хочу.
Зачем дома точность в 2 сек/час? Раз в сутки плюсовать и хватит вполне.
Нет, надо переводить про секунде каждые полчаса.
Ну я бы, для себя, прояснил в чем проблема. Потому что у меня на DS3231 собрано двое часов(матричные и в погодной станции) и никаких проблем нет. Поэтому, в интернете полно программ, потестируйте модуль. Может действительно левая DS3231 - поменяйте.
Можно и по секунде каждые полчаса, не суть. Если секунды не отображаются, то для дома вообще не критично. А в целом Genri5 прав - надо не подводить, а понять, почему отстают. Был бы такой хреновый чип по дефолту - давно бы уже контора раззорилась.
Можно и по секунде каждые полчаса, не суть. Если секунды не отображаются, то для дома вообще не критично. А в целом Genri5 прав - надо не подводить, а понять, почему отстают. Был бы такой хреновый чип по дефолту - давно бы уже контора раззорилась.
заказал на китайском сайте. сам модуль стоит в 2 раза дешевле чем орининальный чип
заказал на китайском сайте. сам модуль стоит в 2 раза дешевле чем орининальный чип
Все мы заказываем на китайских сайтах. Кому-то везет, кому-то не везет. Я получил давеча два PT100 от одного продавца, скрутил вместе, сунул в воду, подождал и измерил сопротивление - разнится. По таблице - разбег в градус-полтора. Хотя, казалось бы - где тут можно накосячить в терморезисторе?
Можно и по секунде каждые полчаса, не суть. Если секунды не отображаются, то для дома вообще не критично. А в целом Genri5 прав - надо не подводить, а понять, почему отстают. Был бы такой хреновый чип по дефолту - давно бы уже контора раззорилась.
заказал на китайском сайте. сам модуль стоит в 2 раза дешевле чем орининальный чип
"...не гонялся бы ты поп за дешевизной"
правда с китаем так, высокая стоимость не означает качество, тут как-то тема прбегала про плохие стабизаторы на 3,3 и пять вольт из серии 1ххх, и дескать на них нельзя строить надёжную аппаратуру, разбирался, строить можно, но только на оригинальных, берем лупу максимального увеличения и смотрим маркировку, технологии маркировки видимо в поднебесную не передают )))
У меня знакомый, тоже ругался на DS3231. А покупал он на алиэкспресс. Я на радиорынке у проверенного продавца. Поделился с ним и у него о микросхеме мнение изменилось. Делайте выводы.
https://www.youtube.com/watch?v=_b4hF8FNdvU
Я хотел сказать, что хочется дешевле, будь готов получить геморой.
Genri5, Вы не понимаете главного. Все что поставляется с али это банальная отбраковка. Сделали партию, не вошла в нормы , или излишек производства , то все на Али. Обычные китайские предприятия не рассматривают вас как покупателя. Вы же не заказываете миллионами их. А так извини подвинься. А то что купили на рынке у проверенного продавана .Так и он не интересут китайских производителей. А жаловаться на китайских продовцов мусора, что их мусор плохого качества, это что издевка над форумом. Ну а что делать если китайский мусор он дешев и доступен радиолюбителям всего мира.
Да нет, я как раз это и понимаю. Я, к примеру, предпочитаю покупать у официальных дилеров.
У вас что есть человек в Китае, который покупает напрямую с предприятий??
До предъявления обвинений китайским труженикам стоило бы проверить часовую плату на максимально урезанном скетче - только чтение из часов и вывод в монитор, без всех извращений с индикацией.
Ну и http://arduino.ru/forum/obshchii/ds3231-otstayut-na-1-minutu-za-sutki , см. #18 и #19