Еще одни часы на LCD1602 с крупными цифрами
- Войдите на сайт для отправки комментариев
[i]"Что бы вы ни делали на Ардуино, все равно получаются или часы, или метеостанция"[/i] (с) ArduinoLab
Так вышло, что у меня совпали два события - внезапно оказалось, что в комнате нет часов, и почта доставила посылку с али, в которой среди прочего был стартовый набор Ардуино. В общем, вопрос о первом изделии был очевиден.
Собственный опыт: лет 20 назад я делал некоторые вещи на рассыпной логике, потом подзабросил. Кое-какой опыт программирования тоже имеется, правда, не на C++. Честно говоря, сишный синтаксис пока еще вызывает у меня зубную боль)))
Делать пришлось на том, что было в наличии - модуль DS1302, LCD1602 с синей подсветкой и ардуино нано - UNO из набора решил оставить для дальнейших экспериментов. Ну и три тактовых кнопки с колпачками - тоже из набора.
в этом разделе принято выкладывать код в сообщении. В крайнем случае - давать ссылку на гитхаб
Архивы на ЯД категорически не приветсвуются
в этом разделе принято выкладывать код в сообщении. В крайнем случае - давать ссылку на гитхаб
Архивы на ЯД категорически не приветсвуются
Как выкладывать картинки разобрался, а как прикрепить файл?
Как выкладывать картинки разобрался, а как прикрепить файл?
а какой файл вы хотите выложить? Если скетч - то не надо файлом, вставляйте код прямо в сообщение. Только правильно вставляйте, как программный код, а не как текст
Да к скетчу заголовочный файл прилагается. Библиотеки, опять же. Проще было бы архивом выложить. Ну если нельзя, то нельзя
Скетч
файл clock_lcd_1602.h
Схема
замечания по коду нужны или ну его?
Если есть - не помешают )))
А где clock_lcd_1602.cpp?
А где clock_lcd_1602.cpp?
А кто его просит?
замечания по коду нужны или ну его?
Если есть - не помешают )))
Главное замечание - очень высокая степень дублирования кода. Реально программа могла бы быть раза в три короче. Самый яркий пример - это 10 почти одинаовых процедур custom0() - custom9() Код во всех один и тот же, разница только в шести выводимых символах. Если вынести эти символы в заголовк как параметры - можно вместо десяти процедур обойтись одной.
Ну и остальные процедуры не лучше, только там это не так видно. Две длиннющие процедуры работы с кнопками SetHourMode() SetSecondMode() отличаются буквально в мелочах, думаю их можно было бы обьединить. Процедура CheckNumData сотоит из двух одинаковых частей if (increment) и else. хотя можно обойтись одним. Подумайте, ведь, например, часы в любом случае не могут быть меньше 0 и больше 23х - так зачем нам знать, в какую сторону мы их меняем - проверяйте разом на оба условия да и все. Кстати, проверьте, в этой процедуре в строчках 730 и 737, похоже, ошибки - тоже результат дублирования кода
Вообще, по коду хорошо прослеживается. что главный принцип программирования для вас - копирование. Что я имею в виду? - Вы пишете процедуру, например, для выдачи на печать числа 1 - а потом для всех остальных чисел размножаете ее копированием. Уходите от этой практики. Во-первых, это неэффективно - получается очень раздутый код. А главное - при таком методе очень легко насажать ошибок и очень трудно их искать, потому как переменные рассыпаны по куче одинаковых процедур. Вы нашли ошибку в одном месте. исправили - а в других забыли.
по мне так процедура не увеличится. То что в каждой - свой набор - я увидел. Ну так что ж - просто передавайте эти символы как параметры.
Сейчас у вас так:
void custom2(byte x) { lcd.setCursor(x, 0); lcd.write(1); lcd.write(1); lcd.write(2); lcd.setCursor(x, 1); lcd.write(0); lcd.write(7); lcd.write(7); } void custom3(byte x) { lcd.setCursor(x, 0); lcd.write(1); lcd.write(6); lcd.write(2); lcd.setCursor(x, 1); lcd.write(4); lcd.write(4); lcd.write(5); } .................. // и так далеезаписываем так:
void custom_any(byte x, byte a, byte b, byte c, byte d, byte e, byte f) { lcd.setCursor(x, 0); lcd.write(a); lcd.write(b); lcd.print(c); lcd.setCursor(x, 1); lcd.write(d); lcd.write(e); lcd.write(f); }в итоге вместо вызова процедур custom2() и custom3() вызываем одну и ту же процедуру
С остальными дублями можно поступить точно так же.
Тут вопрос спорный. Кому-то может быть проще при вызове процедуры держать в голове, какой набор символов дать в параметры, чтобы получить нужную цифру, а кому-то проще просто вызвать нужную процедуру, чтобы получить ту же цифру. Имхо, первый вариант может быть оправдан только при условии жесткой нехватки памяти ))
Наверное, было бы лучше сделать массивы для наборов нужных символов для каждой цифры и передавать в процедуру нужный массив
правильно? Посмотрите внимательно свой код:
else { val--; if (toHour) { if (val > 23) { val = 23; } } else { if (val > 59) { val = 59; } } }у вас идет декремент (val--) - , значит значения движутся вниз - как вы сами пишете - (2-1-0-23-22...) - а значит прверять надо на нижнюю границу. А вы что проверяете?
Наверное, было бы лучше сделать массивы для наборов нужных символов для каждой цифры и передавать в процедуру нужный массив
несомненно , это лучший вариант :) Но я не хотел вас грузить этим сразу :)
Но тот вариант, что использован сейчас в коде - имхо, худший из трех
правильно?
Угу, работает же правильно)) Это byte, т.е. при val == 0 декремент присвоит не -1, а 255. Т.е. таки больше 23 или 59 ))
Наверное, было бы лучше сделать массивы для наборов нужных символов для каждой цифры и передавать в процедуру нужный массив
несомненно , это лучший вариант :) Но я не хотел вас грузить этим сразу :)
Но тот вариант, что использован сейчас в коде - имхо, худший из трех
Одна голова - хорошо, две - завсегда лучше ))) Будет время, переделаю
Угу, работает же правильно)) Это byte, т.е. при val == 0 декремент присвоит не -1, а 255. Т.е. таки больше 23 или 59 ))
ну ок, тут подловили :)
Угу, работает же правильно)) Это byte, т.е. при val == 0 декремент присвоит не -1, а 255. Т.е. таки больше 23 или 59 ))
ну ок, тут подловили :)
В повседневном кодерстве с этим не сталкивался, там экономить память на типах данных не приходится. Но тут этот момент я, как говорится, прочувствовал на своей шкуре )) Сначала тоже удивился, почему у меня на нуле все останавливалось.
А по первой вообще как-то инициализировал переменную uint8_t минус единицей - и скомпилировалось же, только МК завис на старте. Потом полез в доки и увидел, что uint8_t это byte ))
Одна голова - хорошо, две -
Мутант :)
Переписал скетч с учетом замечаний
файл clock_lcd_1602.h
Ссылка на архив в сообщении #1 тоже обновлена
ой :)
еще замечания нужны? :)
ой :)
еще замечания нужны? :)
Мне еще одни часы делать предстоит, так что принимаю все, что есть))
я кратенько, без обьяснений, а то некогда:
Вот как я бы поменял некоторые места кода.
Было:
// массивы сегментов для отрисовки цифр byte num_[6]{32, 32, 32, 32, 32, 32}; byte num0[6]{0, 1, 2, 3, 4, 5}; byte num1[6]{1, 2, 32, 4, 255, 4}; byte num2[6]{1, 1, 2, 0, 7, 7}; byte num3[6]{1, 6, 2, 4, 4, 5}; byte num4[6]{3, 4, 255, 32, 32, 255}; byte num5[6]{3, 6, 6, 4, 4, 5}; byte num6[6]{0, 6, 6, 3, 4, 5}; byte num7[6]{1, 1, 5, 32, 0, 32}; byte num8[6]{0, 6, 2, 3, 4, 5}; byte num9[6]{0, 1, 2, 7, 7, 5}; void customDraw(byte *arr, byte x) { lcd.setCursor(x, 0); lcd.write(arr[0]); lcd.write(arr[1]); lcd.write(arr[2]); lcd.setCursor(x, 1); lcd.write(arr[3]); lcd.write(arr[4]); lcd.write(arr[5]); } void printDigits(byte digits, byte x) { switch (digits) { case 0: customDraw(num0, x); break; case 1: customDraw(num1, x); break; case 2: customDraw(num2, x); break; case 3: customDraw(num3, x); break; case 4: customDraw(num4, x); break; case 5: customDraw(num5, x); break; case 6: customDraw(num6, x); break; case 7: customDraw(num7, x); break; case 8: customDraw(num8, x); break; case 9: customDraw(num9, x); break; default: customDraw(num_, x); break; } }Стало:
// 11 массивов преобразуем в один двумерный, подчеркивание помещаем в конец // смысл в том, чтобы первый индекс массива соответствовал рисуемой цифре byte nums[][6] ={ {0, 1, 2, 3, 4, 5}, // 0 {1, 2, 32, 4, 255, 4}, // 1 {0, 1, 2, 7, 7, 5}, // 9 {32, 32, 32, 32, 32, 32} // _ }; // void customDraw(byte ind, byte x) { if (ind > 9) ind =10; // при любом индексе более 9 рисуем пустой символ _ lcd.setCursor(x, 0); lcd.write(nums[ind][0]); lcd.write(nums[ind][1]); lcd.write(nums[ind][2]); lcd.setCursor(x, 1); lcd.write(nums[ind][3]); lcd.write(nums[ind][4]); lcd.write(nums[ind][5]); } // switch / case выродился в одну строчку void printDigits(byte digits, byte x) { customDraw(digits, x); }Мелькала такая мысль, поленился ))
Кстати, тогда нужда в customDraw() отпадает, код из нее переезжает в printDigits
void printDigits(byte digits, byte x) { byte ind = digits; if (ind > 9) { ind = 10; } lcd.setCursor(x, 0); lcd.write(nums[ind][0]); lcd.write(nums[ind][1]); lcd.write(nums[ind][2]); lcd.setCursor(x, 1); lcd.write(nums[ind][3]); lcd.write(nums[ind][4]); lcd.write(nums[ind][5]); }Итого минус еще 96 байт в памяти ))
Переписал скетч с использованием самописной библиотеки для работы с кнопками. Заодно избавился от delay.
Скетч
Файл clock_lcd_1602.h
// структура для хранения времени struct tTime { byte hour; byte minute; byte second; }; // получение текущего времени void getCurTime(tTime &time); // проверка на отображение символа в режиме блинка - первую половину периода // отображается,вторую - нет bool checkBlinkCount(); // проверка времени отображения настроек при отсутствии активности; // как только вернет false, настройки закрываются bool checkTimeDisplay(); // проверка задержки изменения значений при удержании кнопки bool checkAutoAddTimer(); // установка таймеров void setTimerData(unsigned long &val); // отработка нажатия на кнопки +/- void checkBtnUpDown(shButton &btn, byte &val, bool incr); // отработка нажатия на кнопку Set void checkBtnSet(byte h, byte m, byte s); // сохранение измененного времени при выходе из режима настроек void saveTimeToRTC(byte Hour, byte Minute, byte Second); // отображение режима настройки часов и минут void setHourMode(); // отображение режима настройки секунд void setSecondMode(); // мигание часов/минут/секунд void blinkNumber(byte &number); // отображение моргающего двоеточия void dpDisplay(boolean disp, boolean dp_blink); // отображение данных на экране void showClockData(byte h, byte m); // вывод числа void digitalClockDisplay(byte number, byte mode); // вывод цифры void printDigits(byte digits, byte x); // изменение значения в настройках void checkNumData(byte &val, bool increment, bool toHour); // создание сегментов цифр void createSimbols();Ссылка на архив в сообщении #1 тоже обновлена
#include "clock_lcd_1602.h" где взять эту библиотеку,?
#include "clock_lcd_1602.h" где взять эту библиотеку,?
это что? троллинг такой? пост выше вашего там что???
плиз.
#include "clock_lcd_1602.h" где взять эту библиотеку,?
Постом выше - полный код, включая файл clock_lcd_1602.h
Смотрим внимательно
просто в папке нет этой библиотеки.Там их 3 а это 4-тая.
В какой папке? Это не библиотека, а заголовочный файл, он лежит рядом с файлом скетча
прошу извинить был не в себе.
Здравствуйте! Закинул скетч (из поста #26)в IDE, при компиляции выводится ошибка в строке 546 switch (btnSet.btnState). В комментах пишет:
Дело очень давнее, библиотека shButton давно переписана и много раз обработана напильником. Скетч из архива более актуальный ))
Понял, спасибо!
У вас уже есть опыт использования данных часов, какова точность хода? Часто приходится подводить?
Точность хода модуля ds1302 мягко говоря никакая. Но долго я эти часы не пользовал, потому не подскажу ))
Говорят, может до пяти минут в сутки убегать )) У меня за месяц работы значительного убегания не было. Но в любом случае с DS3231 никакого сравнения