Отстает время на 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