Nokia 5110 и часы DS1307

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018
Здравия. 
Ситуация в следующем.
Долго мучался с экранчиком Nokia 5110 и часами DS1307
С отрисовкой нуля вроде бы разобрался, а вот год вместо 18, выводится 48.
Кто может подскажет, в чем подвох?
#include <LCD5110_Basic.h>
#include <Wire.h>
#include <DS1307RTC.h>

//      SCK  - CLK - Pin 2
//      MOSI - DIN - Pin 3
//      DC   - Pin 4
//      RST  - Pin 6
//      CE   - Pin 5
//

LCD5110 myGLCD(2, 3, 4, 6, 5);

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];

void setup()
{
  Serial.begin(9600);
  myGLCD.InitLCD(70);
  myGLCD.setFont(SmallFont);
  myGLCD.clrScr();
}

void loop()
{
  tmElements_t tm;
  if (RTC.read(tm))
  {
    myGLCD.clrScr();
    myGLCD.setFont(MediumNumbers);
    if (tm.Hour >= 0 && tm.Hour < 10)
    {
      myGLCD.printNumI(0, 0, 0);
      myGLCD.printNumI(tm.Hour, 13, 0);
    }
    if (tm.Hour >= 10)
    {
      myGLCD.printNumI(tm.Hour, LEFT, 0);
    }
    if (tm.Minute >= 0 && tm.Minute < 10)
    {
      myGLCD.printNumI(0, 32, 0);
      myGLCD.printNumI(tm.Minute, 44, 0);
    }
    if (tm.Minute >= 10)
    {
      myGLCD.printNumI(tm.Minute, CENTER, 0);
    }
    myGLCD.printNumI(tm.Second, RIGHT, 0);
    if (tm.Second >= 0 && tm.Second < 10)
    {
      myGLCD.printNumI(0, 60, 0);
    }
    myGLCD.setFont(SmallFont);
    myGLCD.print(":", 25, 10);
    myGLCD.print(":", 55, 10);
    myGLCD.setFont(MediumNumbers);
    if (tm.Day >= 0 && tm.Day < 10)
    {
      myGLCD.printNumI(0, 0, 35);
      myGLCD.printNumI(tm.Day, 13, 35);
    }
    if (tm.Day >= 10)
    {
      myGLCD.printNumI(tm.Day, LEFT, 35);
    }
    if (tm.Month >= 0 && tm.Month < 10)
    {
      myGLCD.printNumI(0, 32, 35);
      myGLCD.printNumI(tm.Month, 44, 35);
    }
    if (tm.Month >= 10)
    {
      myGLCD.printNumI(tm.Month, CENTER, 35);
    }
    myGLCD.printNumI(tm.Year, RIGHT, 35);

    if (tm.Year >= 0 && tm.Year < 10)
    {
      myGLCD.printNumI(0, 60, 35);
    }
    myGLCD.setFont(SmallFont);
    myGLCD.print("*", 25, 35);
    myGLCD.print("*", 25, 40);
    myGLCD.print("*", 55, 35);
    myGLCD.print("*", 55, 40);

    delay(1000);
  }
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Для начала, мы не знаем какой год у Вас установлен в часах. Думаю, что 48 и устанволен. Ставили с NTP? Так там нетрудно ошибиться между unix и 2k временем. Ну, если уж нет, то надо библиотеку смотреть - может она от юникса считает, а у Вас 2к. Тогда просто вычитайте вычитайте 30.

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Устанавливал и "автоматом" системное время и в ручную, один хрен.

Весь прикол, что если просто выводить в COM порт, то выводится правильно, 2018. 

А вот если "вручную" установить, к примеру 2008, то отображается 2038 год.

Разница в 30 лет.

Про 2К, это про это?  Wire.write(dec2bcd(tmYearToY2k(tm.Year))); Из библиотеки строка

Если из года вычитать 30, то и сегодняшний год отображается правильно, и если перевести в 2000 -2009, тоже отображается правильно. Разница в 30 лет.

    myGLCD.printNumI(tm.Year - 30, RIGHT, 35);

    if (tm.Year - 30 >= 0 && tm.Year - 30 < 10)
    {
      myGLCD.printNumI(0, 60, 35);
    }

Вот только не пойму, а почему такая ерунда?

Буду благодарен тому кто объяснит.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

В юниксе время считается от 01.01.1970 года, а в системе 2k - от 01.01.2000 года. Нормальные библиотеки поддержтают и то, и другое. У Вас установка происходит в юниксе, а чтение в 2к. Вот и получается, то что в юниксе 2018, в 2к - 2048.

Правильный выход - разберитесь с библиотекой, с установкой, с чтением, с чем угодно и сделайте так. чтобы у Вас установка и чтение были в одной эпохе - в любой. Ну, или если это трудно, тупо вычитайте 30 лет - это должно работать, но есть опасность, что в какой-то момент Вы поменяете установку и\или чтение и опять случайно эпохи смените.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Стоп! Только сейчас заметил.

Katapuf пишет:
если просто выводить в COM порт, то выводится правильно, 2018.

Это точно?

Если перед строкой №77 поставить вывод в сериал, то в сериал пойдёт 2018, а на экран - 2048? Точно? проверьте! Если так, то заодно проверьте другие единицы (в минутах, в часах) - они правильные или тоже на 4-ки заменяются.

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Примерно понял, но вот как я и говорил, если просто выводить в COM порт, на экранчик 1802 или 2004, то выводится правильно.

А если на экран Nokia 5110, то то, что есть...

Так получается виноват Nokia 5110 ?

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

А вот если так то год выводится 48, дни месяцы, часы минуты секунды нормально.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нет, уж, Вы сделайте то, что я написал - поставьте печать прямо рядом со строкой 77 и точно убедитесь. И если выводится по разному, проверьте другие единицы (в часах и минутах) - они тоже врут или нет.

Ещё раз. Поставьте печать в сериал прямо рядом со строкой 77. Если и впрямь по разному, проверьте другие единицы. И выложите свежий код, я посмотрю как поставили.

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Врет только год.

Остольное кажит нормально.

#include <LCD5110_Basic.h>
#include <Wire.h>
#include <DS1307RTC.h>

//      SCK  - CLK - Pin 2
//      MOSI - DIN - Pin 3
//      DC   - Pin 4
//      RST  - Pin 6
//      CE   - Pin 5
//

LCD5110 myGLCD(2, 3, 4, 6, 5);

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];

void setup()
{
  Serial.begin(9600);
  myGLCD.InitLCD(70);
  myGLCD.setFont(SmallFont);
  myGLCD.clrScr();
}

void loop()
{
  tmElements_t tm;
  if (RTC.read(tm))
  {
    myGLCD.clrScr();
    myGLCD.setFont(MediumNumbers);
    if (tm.Hour >= 0 && tm.Hour < 10)
    {
      myGLCD.printNumI(0, 0, 0);
      myGLCD.printNumI(tm.Hour, 13, 0);
    }
    if (tm.Hour >= 10)
    {
      myGLCD.printNumI(tm.Hour, LEFT, 0);
    }
    if (tm.Minute >= 0 && tm.Minute < 10)
    {
      myGLCD.printNumI(0, 32, 0);
      myGLCD.printNumI(tm.Minute, 44, 0);
    }
    if (tm.Minute >= 10)
    {
      myGLCD.printNumI(tm.Minute, CENTER, 0);
    }
    myGLCD.printNumI(tm.Second, RIGHT, 0);
    if (tm.Second >= 0 && tm.Second < 10)
    {
      myGLCD.printNumI(0, 60, 0);
    }
    myGLCD.setFont(SmallFont);
    myGLCD.print(":", 25, 10);
    myGLCD.print(":", 55, 10);
    myGLCD.setFont(MediumNumbers);
    if (tm.Day >= 0 && tm.Day < 10)
    {
      myGLCD.printNumI(0, 0, 35);
      myGLCD.printNumI(tm.Day, 13, 35);
    }
    if (tm.Day >= 10)
    {
      myGLCD.printNumI(tm.Day, LEFT, 35);
    }
    if (tm.Month >= 0 && tm.Month < 10)
    {
      myGLCD.printNumI(0, 32, 35);
      myGLCD.printNumI(tm.Month, 44, 35);
    }
    if (tm.Month >= 10)
    {
      myGLCD.printNumI(tm.Month, CENTER, 35);
    }
    Serial.println(tm.Hour);
    Serial.println(tm.Minute);
    Serial.println(tm.Second);
    Serial.println(tm.Day);
    Serial.println(tm.Month);
    Serial.println(tm.Year);
    myGLCD.printNumI(tm.Year - 30, RIGHT, 35);

    if (tm.Year - 30 >= 0 && tm.Year - 30 < 10)
    {
      myGLCD.printNumI(0, 60, 35);
    }
    myGLCD.setFont(SmallFont);
    myGLCD.print("*", 25, 35);
    myGLCD.print("*", 25, 40);
    myGLCD.print("*", 55, 35);
    myGLCD.print("*", 55, 40);

    delay(1000);
  }
}

 

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Вот этот скетч из примера. Он выводит в COM порт все правильно.

#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

void setup() {
  Serial.begin(9600);
  while (!Serial) ; // wait for serial
  delay(200);
  Serial.println("DS1307RTC Read Test");
  Serial.println("-------------------");
}

void loop() {
  tmElements_t tm;

  if (RTC.read(tm)) {
    Serial.print("Ok, Time = ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print(", Date (D/M/Y) = ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

 

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Вся загвоздка в строке № 28 из примера.

Serial.print(tmYearToCalendar(tm.Year));

Но если так то выводится год правильно, но полностью не 18, а 2018.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нет, погодите.

Вы так говорите, что я понять не могу. Вот Ваш код (не пример). Строки 82 и 83 что выводят. Чётко, без лишних слов и без слов типа "нормально", "глючит" - что выводится в строке 82 и что в строке 83?

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

82  строка - 48

83   строка - 18

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, значит, все правильно. у Вас там сидит 48.

А что Вам надо?

Если Вам надо получить 2018, используйте макрос как tmYearToCalendar как в примере - он тупо прибавит 1970 и будет всё окей.

Если Вам надо получить только 18, то вместо tmYearToCalendar, вызовите tmYearToY2k, она тупо вычтет 30.

Вот и все дела.

Или проблема в чём-то другом?

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

ЕвгенийП пишет:

Если Вам надо получить только 18, то вместо tmYearToCalendar, вызовите tmYearToY2k, она тупо вычтет 30.

Тупо вычтет?

А ничего, что 30 на 4 не делится, и високосные года будут давать в остатке от деления 2?

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

andriano пишет:

А ничего, что 30 на 4 не делится, и високосные года будут давать в остатке от деления 2?

Но это уже лучше, чем ошибка на 30 лет - не правда ли?

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Отнюдь.

Очевидная ошибка - гораздо лучше, чем когда внезапно будут сбиваться (притом, всего на 1) числа, дни недели и т.п.

Помнить, что сейчас 2018 год гораздо легче, чем каждый раз мысленно проверять, а не сбились ли часы на один день.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:

Тупо вычтет?

Именно, тупо вычтет. Вот библиотека, которую использует ТС, а вот этот самый макрос из неё

#define  tmYearToY2k(Y)      ((Y) - 30)    // offset is from 2000

Как видите, тупо вычитает.

andriano пишет:

А ничего, что 30 на 4 не делится, и високосные года будут давать в остатке от деления 2?

С какого перепугу? Вы знакомы с реализацией стандартной службы времени? Боюсь, нет. После вычитания получится правильный календарный год.

В юникс эпохе время начинается с 1970 года (невисокосного), а потому у неё как раз високосность сдвинута - 10-ый год високосный (соответсвует 1980-ому), а 12-ый нет. И это не мешает ей правильно считать дни недели и високосности. А прибавив 1970 (или вычтя 30 для "года без века" в 21-ом веке) получим правильный календарный год.

Это вещи настолько общие, что Вы просто не можете их не знать. Переклинило под вечер? Бывает.

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Благодарю за разъяснение.

Теперь почти понятно. Непонятно зачем нужно было городить "В юниксе время считается от 01.01.1970 года, а в системе 2k - от 01.01.2000 года. " ?

И все же:

если Serial.print(tmYearToCalendar(tm.Year)); то выводится сообщение "2018",

если Serial.print(tm.Year); то выводится сообщение "48".

Получается вот этот кусок "tmYearToCalendar" "оттяпывает" первые две цифры "20" и заменяет "1" на "4".

Зачем эти трудности?

Получается как китайцы, в начале создавать себе трудности, а потом с удовольствием их преодолевать.

Ладно, работает и то хорошо.

Еще раз благодарю и всем хорошим людям, здравия.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Katapuf пишет:

И все же:

если Serial.print(tmYearToCalendar(tm.Year)); то выводится сообщение "2018",

если Serial.print(tm.Year); то выводится сообщение "48".

Получается вот этот кусок "tmYearToCalendar" "оттяпывает" первые две цифры "20" и заменяет "1" на "4".

Зачем эти трудности?

Не, Вы таки не поняли. В tm.Year хранится номер года, начиная с 1970. Для 2018 это, понятное дело, - 48.

Макрос tmYearToCalendar тупо прибавляет 1970 к своему аргументу (и потому получается 2018)

Макрос tmYearToY2k тупо вычитает 30 из своего аргумента (и потому получается 18).

Вот и всё.

 

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Да понял я про это.

Я не понял, для чего "До материальной эпохи, после материальной эпохи". :)

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А Вы как хотели? Там же реально внутри хранятся просто секунды от начала эпохи одним числом. Вы хотели хранить секунды от 01.01.0001? И какой же тип данных Вам бы понадобился? Тут и так уже при 32 битовом числе эпоха unix скоро переполнится (погуглите по фразе "Проблема 2038 года" - узнаете много интересного).

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

andriano пишет:

Очевидная ошибка

В чём? В том, что за ноль в UNIX и в стандартной С/С++ библиотеке взято начало невисокосного 1970 года? И в том, что из-за этого во всех системах, сделанных основе этой библиотеки, "неправильно" считаются дни недели и високосности? А мужики-то, блин, и не знали! А может это просто очевидная некомпетентность некоторых обнаружителей очевидных ошибок? Нет?

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Ворота пишет:

А мужики-то, блин, и не знали! А может это просто очевидная некомпетентность некоторых обнаружителей очевидных ошибок? Нет?

Вы сомневаетесь, что при неправильном использовании библиотеки можно получить неверные данные?

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

Нет. И также не сомневаюсь, что в данном случае, ты правильное использование обозвал "очевидной ошибкой".

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Здравия.

Заодно хотел спросить, по поводу моего скетча.

Он конечно работает, но с "эстетической" стороны, правильно я сделал, по поводу подставки нулей, когда выводимое значение мньше 10 и отображается только один символ. И с организацией сдвига. С крайне правым, проще, там сдвига нет(точнее он происходит автоматом).  А в случае с левым и центральным, выводом информации, без сдвига не обойтись. Это когда однозначное число выводится по одним координатам, а когда оно становится двузначным, то требуется его сдвинуть на одно положение влево, где до этого подставлялся ноль.

/*
      SCK  - CLK - Pin 2
      MOSI - DIN - Pin 3
      DC         - Pin 4
      RST        - Pin 6
      CE         - Pin 5
*/

#include <LCD5110_Basic.h>
#include <Wire.h>
#include <DS1307RTC.h>

LCD5110 myGLCD(2, 3, 4, 6, 5);

extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];

void setup()
{
  Serial.begin(9600);
  myGLCD.InitLCD(70);
  myGLCD.clrScr();
}

void loop()
{
  tmElements_t tm;
  if (RTC.read(tm))
  {
    myGLCD.clrScr();
    myGLCD.setFont(MediumNumbers);
    if (tm.Hour >= 0 && tm.Hour < 10)
    {
      myGLCD.printNumI(0, 0, 0);
      myGLCD.printNumI(tm.Hour, 13, 0);
    }
    if (tm.Hour >= 10)
    {
      myGLCD.printNumI(tm.Hour, LEFT, 0);
    }
    if (tm.Minute >= 0 && tm.Minute < 10)
    {
      myGLCD.printNumI(0, 32, 0);
      myGLCD.printNumI(tm.Minute, 44, 0);
    }
    if (tm.Minute >= 10)
    {
      myGLCD.printNumI(tm.Minute, CENTER, 0);
    }
    myGLCD.printNumI(tm.Second, RIGHT, 0);
    if (tm.Second >= 0 && tm.Second < 10)
    {
      myGLCD.printNumI(0, 60, 0);
    }
    myGLCD.setFont(SmallFont);
    myGLCD.print(":", 25, 10);
    myGLCD.print(":", 55, 10);
	
    myGLCD.setFont(MediumNumbers);

    if (tm.Day >= 0 && tm.Day < 10)
    {
      myGLCD.printNumI(0, 0, 35);
      myGLCD.printNumI(tm.Day, 13, 35);
    }
    if (tm.Day >= 10)
    {
      myGLCD.printNumI(tm.Day, LEFT, 35);
    }
    if (tm.Month >= 0 && tm.Month < 10)
    {
      myGLCD.printNumI(0, 60, 35);
      myGLCD.printNumI(tm.Month, RIGHT, 35);
    }
    if (tm.Month >= 10)
    {
      myGLCD.printNumI(tm.Month, CENTER, 35);
    }
    myGLCD.setFont(SmallFont);
    myGLCD.printNumI(tmYearToCalendar(tm.Year), CENTER, 40);

    delay(1000);
  }
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Я бы по другому делал, но сделали и сделали, как умеете. 

Katapuf
Katapuf аватар
Offline
Зарегистрирован: 16.05.2018

Так и вопрос, как лучше.

С Ардуино я всего второй месяц общаюсь, до этого старая добрая схемотехника, без МК.

(На драйве2 выложил как то схему управления автономным отопителем(чистая схемотехника), а один человек, поинтересовался, почему не на ардуино. Вот тогда то изапала мысля, посмотреть что это такое Ардуино и с чем ее того. И вот как говорится "дошли руки" до Ардуино)

В принципе ничего сложного, таже логика, разница лишь, с организацией логики более совместимой с данным МК.

Если не трудно, как можно было сделать по другому?

Более "по феншую" если можно так выразится.

 

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Ворота пишет:

Нет. И также не сомневаюсь, что в данном случае, ты правильное использование обозвал "очевидной ошибкой".

Уверенность - дело хорошее...

А теперь смотрим посты сначала №16, а потом №15. Вы действительно считаете ошибку в 30 лет правильным использованием?

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Katapuf пишет:

Так и вопрос, как лучше.

Можно, например, фрагменты вида

    if (tm.Minute >= 0 && tm.Minute < 10)
    {
      myGLCD.printNumI(0, 32, 0);
      myGLCD.printNumI(tm.Minute, 44, 0);
    }
    if (tm.Minute >= 10)
    {
      myGLCD.printNumI(tm.Minute, CENTER, 0);
    }

заменить на 

    if (tm.Minute >= 0 && tm.Minute < 10)
    {
      myGLCD.printNumI(0, 32, 0);
    }
    myGLCD.printNumI(tm.Minute, 44, 0);

а можно еще неоднократно используемые фрагменты кода заменить на вызов функции.