Nokia 5110 и часы DS1307
- Войдите на сайт для отправки комментариев
Ср, 16/05/2018 - 18:26
Здравия.
Ситуация в следующем.
Долго мучался с экранчиком 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); } }
Для начала, мы не знаем какой год у Вас установлен в часах. Думаю, что 48 и устанволен. Ставили с NTP? Так там нетрудно ошибиться между unix и 2k временем. Ну, если уж нет, то надо библиотеку смотреть - может она от юникса считает, а у Вас 2к. Тогда просто вычитайте вычитайте 30.
Устанавливал и "автоматом" системное время и в ручную, один хрен.
Весь прикол, что если просто выводить в COM порт, то выводится правильно, 2018.
А вот если "вручную" установить, к примеру 2008, то отображается 2038 год.
Разница в 30 лет.
Про 2К, это про это? Wire.write(dec2bcd(tmYearToY2k(tm.Year))); Из библиотеки строка
Если из года вычитать 30, то и сегодняшний год отображается правильно, и если перевести в 2000 -2009, тоже отображается правильно. Разница в 30 лет.
Вот только не пойму, а почему такая ерунда?
Буду благодарен тому кто объяснит.
В юниксе время считается от 01.01.1970 года, а в системе 2k - от 01.01.2000 года. Нормальные библиотеки поддержтают и то, и другое. У Вас установка происходит в юниксе, а чтение в 2к. Вот и получается, то что в юниксе 2018, в 2к - 2048.
Правильный выход - разберитесь с библиотекой, с установкой, с чтением, с чем угодно и сделайте так. чтобы у Вас установка и чтение были в одной эпохе - в любой. Ну, или если это трудно, тупо вычитайте 30 лет - это должно работать, но есть опасность, что в какой-то момент Вы поменяете установку и\или чтение и опять случайно эпохи смените.
Стоп! Только сейчас заметил.
Это точно?
Если перед строкой №77 поставить вывод в сериал, то в сериал пойдёт 2018, а на экран - 2048? Точно? проверьте! Если так, то заодно проверьте другие единицы (в минутах, в часах) - они правильные или тоже на 4-ки заменяются.
Примерно понял, но вот как я и говорил, если просто выводить в COM порт, на экранчик 1802 или 2004, то выводится правильно.
А если на экран Nokia 5110, то то, что есть...
Так получается виноват Nokia 5110 ?
А вот если так то год выводится 48, дни месяцы, часы минуты секунды нормально.
Нет, уж, Вы сделайте то, что я написал - поставьте печать прямо рядом со строкой 77 и точно убедитесь. И если выводится по разному, проверьте другие единицы (в часах и минутах) - они тоже врут или нет.
Ещё раз. Поставьте печать в сериал прямо рядом со строкой 77. Если и впрямь по разному, проверьте другие единицы. И выложите свежий код, я посмотрю как поставили.
Врет только год.
Остольное кажит нормально.
Вот этот скетч из примера. Он выводит в COM порт все правильно.
Вся загвоздка в строке № 28 из примера.
Serial
.print(tmYearToCalendar(tm.Year));
Но если так то выводится год правильно, но полностью не 18, а 2018.
Нет, погодите.
Вы так говорите, что я понять не могу. Вот Ваш код (не пример). Строки 82 и 83 что выводят. Чётко, без лишних слов и без слов типа "нормально", "глючит" - что выводится в строке 82 и что в строке 83?
82 строка - 48
83 строка - 18
Ну, значит, все правильно. у Вас там сидит 48.
А что Вам надо?
Если Вам надо получить 2018, используйте макрос как tmYearToCalendar как в примере - он тупо прибавит 1970 и будет всё окей.
Если Вам надо получить только 18, то вместо tmYearToCalendar, вызовите tmYearToY2k, она тупо вычтет 30.
Вот и все дела.
Или проблема в чём-то другом?
Если Вам надо получить только 18, то вместо tmYearToCalendar, вызовите tmYearToY2k, она тупо вычтет 30.
Тупо вычтет?
А ничего, что 30 на 4 не делится, и високосные года будут давать в остатке от деления 2?
А ничего, что 30 на 4 не делится, и високосные года будут давать в остатке от деления 2?
Но это уже лучше, чем ошибка на 30 лет - не правда ли?
Отнюдь.
Очевидная ошибка - гораздо лучше, чем когда внезапно будут сбиваться (притом, всего на 1) числа, дни недели и т.п.
Помнить, что сейчас 2018 год гораздо легче, чем каждый раз мысленно проверять, а не сбились ли часы на один день.
Тупо вычтет?
Именно, тупо вычтет. Вот библиотека, которую использует ТС, а вот этот самый макрос из неё
Как видите, тупо вычитает.
А ничего, что 30 на 4 не делится, и високосные года будут давать в остатке от деления 2?
С какого перепугу? Вы знакомы с реализацией стандартной службы времени? Боюсь, нет. После вычитания получится правильный календарный год.
В юникс эпохе время начинается с 1970 года (невисокосного), а потому у неё как раз високосность сдвинута - 10-ый год високосный (соответсвует 1980-ому), а 12-ый нет. И это не мешает ей правильно считать дни недели и високосности. А прибавив 1970 (или вычтя 30 для "года без века" в 21-ом веке) получим правильный календарный год.
Это вещи настолько общие, что Вы просто не можете их не знать. Переклинило под вечер? Бывает.
Благодарю за разъяснение.
Теперь почти понятно. Непонятно зачем нужно было городить "В юниксе время считается от 01.01.1970 года, а в системе 2k - от 01.01.2000 года. " ?
И все же:
если Serial.print(tmYearToCalendar(tm.Year)); то выводится сообщение "2018",
если Serial.print(tm.Year); то выводится сообщение "48".
Получается вот этот кусок "tmYearToCalendar" "оттяпывает" первые две цифры "20" и заменяет "1" на "4".
Зачем эти трудности?
Получается как китайцы, в начале создавать себе трудности, а потом с удовольствием их преодолевать.
Ладно, работает и то хорошо.
Еще раз благодарю и всем хорошим людям, здравия.
И все же:
если 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).
Вот и всё.
Да понял я про это.
Я не понял, для чего "До материальной эпохи, после материальной эпохи". :)
А Вы как хотели? Там же реально внутри хранятся просто секунды от начала эпохи одним числом. Вы хотели хранить секунды от 01.01.0001? И какой же тип данных Вам бы понадобился? Тут и так уже при 32 битовом числе эпоха unix скоро переполнится (погуглите по фразе "Проблема 2038 года" - узнаете много интересного).
Очевидная ошибка
В чём? В том, что за ноль в UNIX и в стандартной С/С++ библиотеке взято начало невисокосного 1970 года? И в том, что из-за этого во всех системах, сделанных основе этой библиотеки, "неправильно" считаются дни недели и високосности? А мужики-то, блин, и не знали! А может это просто очевидная некомпетентность некоторых обнаружителей очевидных ошибок? Нет?
А мужики-то, блин, и не знали! А может это просто очевидная некомпетентность некоторых обнаружителей очевидных ошибок? Нет?
Вы сомневаетесь, что при неправильном использовании библиотеки можно получить неверные данные?
Нет. И также не сомневаюсь, что в данном случае, ты правильное использование обозвал "очевидной ошибкой".
Здравия.
Заодно хотел спросить, по поводу моего скетча.
Он конечно работает, но с "эстетической" стороны, правильно я сделал, по поводу подставки нулей, когда выводимое значение мньше 10 и отображается только один символ. И с организацией сдвига. С крайне правым, проще, там сдвига нет(точнее он происходит автоматом). А в случае с левым и центральным, выводом информации, без сдвига не обойтись. Это когда однозначное число выводится по одним координатам, а когда оно становится двузначным, то требуется его сдвинуть на одно положение влево, где до этого подставлялся ноль.
Я бы по другому делал, но сделали и сделали, как умеете.
Так и вопрос, как лучше.
С Ардуино я всего второй месяц общаюсь, до этого старая добрая схемотехника, без МК.
(На драйве2 выложил как то схему управления автономным отопителем(чистая схемотехника), а один человек, поинтересовался, почему не на ардуино. Вот тогда то изапала мысля, посмотреть что это такое Ардуино и с чем ее того. И вот как говорится "дошли руки" до Ардуино)
В принципе ничего сложного, таже логика, разница лишь, с организацией логики более совместимой с данным МК.
Если не трудно, как можно было сделать по другому?
Более "по феншую" если можно так выразится.
Нет. И также не сомневаюсь, что в данном случае, ты правильное использование обозвал "очевидной ошибкой".
Уверенность - дело хорошее...
А теперь смотрим посты сначала №16, а потом №15. Вы действительно считаете ошибку в 30 лет правильным использованием?
Так и вопрос, как лучше.
Можно, например, фрагменты вида
заменить на
а можно еще неоднократно используемые фрагменты кода заменить на вызов функции.