Спустя 3 дня график почти заполнен. Получается это барограф)
Ну, почти. Из-за ограничения разрешения экрана по вертикали всего в 8 точек, график приходится масштабировать по высоте, поскольку разброс между максимальным и минимальным значением за период, что умещается на экране, часто больше 8 мм рт.ст. Поэтому в одной точке может быть от 1 мм и больше. Соответственно и сам график с каждым новым значением может сжиматься или снова растягиваться (по вертикали). Т.е., например, визуально точно рассчитать по точкам давление, которое было некоторое время назад не получится. Но оценить его изменение или даже немного его спрогнозировать - довольно просто.
Спасибо за пояснение. А то я прикидывал - сколько едениц в одной точке...
Да, главное знать в какую сторону меняется давление и с какой скоростью. Сейчас, напрмер начало расти, солнышко выглянуло) Пару предыдущих дней - дожди шли.
А можно заменить SHT21 на DHT22. И переписать скетч с заменой.
Выбор SHT21 обусловлен исключительно тем, что он у меня уже был. Для себя можете переписывать как угодно и что угодно, под любые датчики, какими располагаете - ограничений нет. Опрос датчиков происходит через библиотеки, поэтому подключаете нужную и в скетче в соответствующих местах подправляете вызов функций для опроса вашего датчика (в сетапе - проверка наличия и инициализация датчика, и в лупе - запрос температуры и влажности).
Как можно изменить частоту измерения освещенности по фото датчику. А то видно как пульсируем яркость дисплея.
Я уже упоминал о решении подобной проблемы. Скорее всего идет засветка датчика от матрицы. Вобщем, читайте сообщение #44., там я расписал, что надо подправить.
Что же касается температуры и влажности, то SHT21 довольно точный датчик. Попробуйте его расположить в корпусе устройства согласно даташиту.
yucan, спасибо за разъяснение. дело в том что я к батарейке провод еще не тянул. если батарейка в норме то если он не будет показывать это очень даже хорошо.
с отключениями мин макс темперетурой попробую покопаться. я в програмирование не силен. знаю только Basic и Pascal они совсем не похожи
А по моему важно знать не само значение давления (на меня оно никак не влияет), а то, как оно меняется, чтобы прикидывать изменение погоды. Поэтому график нужен. Тем более время его показа незначительно.
Чтобы каждый час когда например 12-00. на любой свободный порт логическая 1 появилась на 30 секунд(время буду точно подбирать потом по секундно) . буду мп3 плеер подключать
Дык, кто ж вам запретит - делайте! Спрашивать разрешение не обязательно. Можете даже не одну сделать, а вообще перекроить скетч под свои желания. С тем функционалом, что там уже есть, пара килобайт кода туда еще влезет, а если скетч еще и прооптимизировать...
Добрые люди! Помогите пожалуйста с кодом. Чтобы в каждый час (пример в 12-00, 13-00 и.т.д.) на свободном порте появилась логическая "1" на 30 секунд (чтобы это время можно было настраивать) для Кукушки
За почти 4 года, что Вы на форуме можно было бы уже хоть немного научиться программировать. Ну правда.
Могу дать направление, в каком стоит попробовать двигаться. В DS3231 есть аж 2 будильника, и оба они свободные (в часах я писал свои будильники). Любой из них может быть настроен на срабатывание в том числе ежечасно. Вот и воспользуйтесь этим. При срабатывании будильника на ноге SQW модуль выставит низкий уровень (при соответствующей настройке). Этот сигнал можно использовать как прерывание для ардуинки. Ну а дальше чистый полет фантазии...
Правда, библиотека, которую использует скетч, не умеет работать с будильниками. Поэтому придется или использовать другую библиотеку для работы с часовым модулем (которая умеет работать с будильниками) и подправить весь скетч под нее, или посмотреть, как работают с будильниками в этой другой библиотеке, и дописать код для будильника самому.
ну да. верно. логика тут не верна. я просто накинул. что можно простым способом переделать. и часы не нужно сканировать. надо сканировать минуты и секунды.
типа
h=часы, m=минуты, sek=секунды, kuku=включение и отключение кукушки
так вроде должа работать 30 секунд каждый час.
if m=0 and sek<=30 then kuku=1 else kuku=0
а если нужно только в определенные часы то
if h=1 and m=0 and sek<=30 then kuku=1 else kuku=0
if h=12 and m=0 and sek<=30 then kuku=1 else kuku=0
Но есть одно но. Такой алгоритм не пригоден для существующего скетча, вернее, не совсем пригоден. Кукушка не всегда будет срабатывать. Вот если бы часы показывали только время, а так там навешано отображение кучи другой информации. Если смена часа произойдет в момент показа времени, то кукушка сработает, иначе врядли вы ее дождетесь.
Представьте, сейчас 11:59:55 и тут наступает время отображения дополнительной информации: дата, обе температуры, влажность, давление. И даже если вы у себя отключили вывод макс/мин температуры и график давления, то все-равно за 5 сек эта инфа не успеет пробежать по экрану. А если еще учесть, что вы уменьшили скорость скроллинга? А если это последние дни декабря и добавится "до нового года осталось..."? А если разряжена батарейка? А если день рождения любимой тещи и вы так ее любите, что накатали текст поздравлялки, который еле влез во все 16 сообщений? Тут не то что 5 сек, тут и нескольких минут не хватит.
Даже если использовать флаг (было ку-ку в этом часу или нет) и куковать уже после вывода доп.инфы - ну вернутся часы на отображение времени, скажем, в 12:03 и выдадут "ку-ку". Как будет выглядеть это "ку-ку" в 12:03 этой слегка подгулявшей кукушки?
Т.е., или в корне переделывать скетч на короткий луп, что немного хлопотно (проще написать все с нуля), или воспользоваться средствами DS3231, как я описывал немного раньше, что проще - досточно добавить нужную настройку будильника DS3231 и завести функцию обработки прерывания от будильника. Будильник DS3231 не зависит от нашего лупа и сработает в нужное время, не зависимо, что будет на экране наших часов.
Но есть еще один вариант. Велосипедный, но вариант - сделать так, как в скетче сделаны будильники.
Будильник в часах, работающих от сети 220В, то еще удовольствие. Если не было электричества, когда должен был сработать будильник - значит проспал. Поэтому будильники делались одними из последних по принципу "пускай уже будет" и все переделывать на короткий луп уже не хотелось. Еще я не хотел привязываться к какому-то конкретному модулю RTC - DS1307 или DS3231. Т.к. в DS1307, насколько мне известно (могу и ошибаться), нет выхода прерывания. А хотелось, чтобы была возможность сделать часы на обоих модулях. Потому и такой велосипед.
Так вот, в скетче перед каждым выводом какой-либо информации идет проверка, а не пора ли включить сигнал будильника. И если пора, то игнорируем то, что еще не успели показать, возвращаемся к отображению времени и включаем будильник. Таким образом, задержка хоть и может быть, но она небольшая - считаные секунды.
Можете пойти и таким путем, вместе с будильником проверять еще и нули минут и включать кукушку.
Только меня интересует один вопрос - зачем устанавливать на пине нужный уровень, длительностью определенное (да еще и изменяемое) время? MP3-модули ведь работают по команде, дали команду - проигрался файл.
Кто может помочь? Выкинул sht, пытаюсь втиснуть bme280, в результате везде нули... ЧЯДНТ? куда копать?
Вы офигели? Думаете кто-то станет разбираться, что вы там изменили в 1400 строчках?
Кто ж сразу новое оборудование в огромную программу пихает? Надо было для начала написать проверочный скетч для датчика, короткий, строк на 15-20. Убедится, что все работает. Или, если не работает - искать ошибку.. Или спросить на форуме -со скетчем в 15 строк и форум бы выстрее помог.
Блин.Я не фигел.
Одним подавай кусок кода, другим подавай весь код.Всем не угодишь. Кому то лень написать что то не унизительное?
И да, еси чо, я проверял датчик, загружал скетч. Татчик опрашивается и показывает значения в мониторе последовательного порта. Или вы думаете, что настолько руки обьектно ориентированы?
Всем спасибо за помощь. Скетч рабочий. Единственное, что изменил: указал адрес инициализации bme - bme.begin (0x76). Заменил ардуино и скомпилировал на другой машине.
Можно использовать в качестве замены при использовани bme280 вместо dht и sht.
Спустя 3 дня график почти заполнен. Получается это барограф)
Ну, почти. Из-за ограничения разрешения экрана по вертикали всего в 8 точек, график приходится масштабировать по высоте, поскольку разброс между максимальным и минимальным значением за период, что умещается на экране, часто больше 8 мм рт.ст. Поэтому в одной точке может быть от 1 мм и больше. Соответственно и сам график с каждым новым значением может сжиматься или снова растягиваться (по вертикали). Т.е., например, визуально точно рассчитать по точкам давление, которое было некоторое время назад не получится. Но оценить его изменение или даже немного его спрогнозировать - довольно просто.
Спасибо за пояснение. А то я прикидывал - сколько едениц в одной точке...
Да, главное знать в какую сторону меняется давление и с какой скоростью. Сейчас, напрмер начало расти, солнышко выглянуло) Пару предыдущих дней - дожди шли.
Добрый день.
А можно заменить SHT21 на DHT22. И переписать скетч с заменой.
А можно заменить SHT21 на DHT22. И переписать скетч с заменой.
Выбор SHT21 обусловлен исключительно тем, что он у меня уже был. Для себя можете переписывать как угодно и что угодно, под любые датчики, какими располагаете - ограничений нет. Опрос датчиков происходит через библиотеки, поэтому подключаете нужную и в скетче в соответствующих местах подправляете вызов функций для опроса вашего датчика (в сетапе - проверка наличия и инициализация датчика, и в лупе - запрос температуры и влажности).
Подскажите кто сталкивался не определяется ds18b20 все остальное работает ,пробовал разные ,пробовал садить на другой пин.
Не определяется в этом проекте или вообще?
В этом проекте в других работает
В этом проекте в других работает
Внимательно проверь монтаж. У меня всё работает
В этом проекте в других работает
Внимательно проверь монтаж. У меня всё работает
Заработало пришлось поменять ардуинку оказалась китайская подделка вместо атмеги328 стоит awga328 я и не обратил внимание свиду одинаковые.
Что такое awga328? Яндех не в курсе.
В яндексе и я искал посмотри здесь: https://elchupanibrei.livejournal.com/36239.html
Добрый вечер.
Вопрос. Как можно изменить частоту измерения освещенности по фото датчику. А то видно как пульсируем яркость дисплея.
И еще вопрос.
Как скорректировать показания температуры и влажности в помещении. Влажность занижается, а температура завышается.
Я уже упоминал о решении подобной проблемы. Скорее всего идет засветка датчика от матрицы. Вобщем, читайте сообщение #44., там я расписал, что надо подправить.
Что же касается температуры и влажности, то SHT21 довольно точный датчик. Попробуйте его расположить в корпусе устройства согласно даташиту.
Доюрый день!
Как отключить отображение напряжения батарейки? оно тут лишнее как мне кажется
еще минимальнои и максимальную температуру с временем. тоже лишнее имхо.
еще минимальнои и максимальную температуру с временем. тоже лишнее имхо.
Доюрый день!
Как отключить отображение напряжения батарейки? оно тут лишнее как мне кажется
Проверьте состояние батарейки. Если напряжение батарейки в норме - отображение отключено.
Минимальную и максимальную температуру тоже легко отлючить. В скетче есть комментарии.
yucan, спасибо за разъяснение. дело в том что я к батарейке провод еще не тянул. если батарейка в норме то если он не будет показывать это очень даже хорошо.
с отключениями мин макс темперетурой попробую покопаться. я в програмирование не силен. знаю только Basic и Pascal они совсем не похожи
нашел как отключить мин. макс. температуру. сам написал комментарий :)
мне тоже кажется что бегущая строка слишком быстро пробегает. куда там нужна delay() напписать чтобы задержку включить? :)
я в програмирование не силен. знаю только Basic и Pascal они совсем не похожи
Та ну напуй.
мне тоже кажется что бегущая строка слишком быстро пробегает. куда там нужна delay() напписать чтобы задержку включить? :)
Тут еще и двух страниц не набралось, а вы ленитесь прочитать предыдущие комментарии. Смотрите #14.
vk007, добавил паузу. Все отлично! Теперь хочу график отключить. Он мне без надобности :) достаточно атмосферное давление показать
vk007, забыл сказать Большое Спасибо за суперские часы!
Давно искал такие! На матрицах! У других функционал слабоват и шрифты не красивые!
Моим друзьям тоже понравилась! Уже двое захотели себе собрать. :)
Ну зачем так орать? Вроде давно на форуме, знаете, что так здесь не принято.((((
Найдите в скетче блок, отвечающий за вывод давления на экран - он начинается с комментария
// +++++ Давление +++++
И вместо него вставьте следующий код
01
if
(bmpOK && (AlarmNotActive() || !beeper))
02
{
03
StringToSprite(
"\xAE\xA0mmHg"
);
04
ScrollVertical(0, 31, 0);
05
delay(500);
06
PresToString(0.51 + BMP.readPressure() * 760.0 / 101325.0);
07
StringToSprite(string_buffer);
08
ScrollVertical(9, 31, 1);
09
delay(1000);
10
for
(
byte
i = 0; i < 32; i++) sprite_buffer[i] = 0;
11
}
Также из сетапа можете удалить блок
if
(bmpOK)
{
...
}
А по моему важно знать не само значение давления (на меня оно никак не влияет), а то, как оно меняется, чтобы прикидывать изменение погоды. Поэтому график нужен. Тем более время его показа незначительно.
Спассбо за помощ!
Скетч подправил! Все работает как надо! Без графика!
Yucan, Если нужен график то его можно включить обратно. строки программы только закоментировал на всякий случай
vk007, еще одну хотелку хочу поставить!
Чтобы каждый час когда например 12-00. на любой свободный порт логическая 1 появилась на 30 секунд(время буду точно подбирать потом по секундно) . буду мп3 плеер подключать
будет типа кукушки :)
еще одну хотелку хочу поставить!
Дык, кто ж вам запретит - делайте! Спрашивать разрешение не обязательно. Можете даже не одну сделать, а вообще перекроить скетч под свои желания. С тем функционалом, что там уже есть, пара килобайт кода туда еще влезет, а если скетч еще и прооптимизировать...
***
я только паять умею
Добрые люди! Помогите пожалуйста с кодом. Чтобы в каждый час (пример в 12-00, 13-00 и.т.д.) на свободном порте появилась логическая "1" на 30 секунд (чтобы это время можно было настраивать) для Кукушки
Заранее Спасибо!
За почти 4 года, что Вы на форуме можно было бы уже хоть немного научиться программировать. Ну правда.
Могу дать направление, в каком стоит попробовать двигаться. В DS3231 есть аж 2 будильника, и оба они свободные (в часах я писал свои будильники). Любой из них может быть настроен на срабатывание в том числе ежечасно. Вот и воспользуйтесь этим. При срабатывании будильника на ноге SQW модуль выставит низкий уровень (при соответствующей настройке). Этот сигнал можно использовать как прерывание для ардуинки. Ну а дальше чистый полет фантазии...
Правда, библиотека, которую использует скетч, не умеет работать с будильниками. Поэтому придется или использовать другую библиотеку для работы с часовым модулем (которая умеет работать с будильниками) и подправить весь скетч под нее, или посмотреть, как работают с будильниками в этой другой библиотеке, и дописать код для будильника самому.
а нельзя как на бейсике. что то подобное
где h - Это часы
if h=0 then let pin5=1
else
if h=1 then let pin5=1
else
if h=2 then let pin5=1
else
if h=3 then let pin5=1
а нельзя как на бейсике
Можно как угодно, но алгоритм и логика ведь должны быть в любом случае правильными.
А по вашей логике "pin5=1" будет вечно, чему бы h не равнялось.
ну да. верно. логика тут не верна. я просто накинул. что можно простым способом переделать. и часы не нужно сканировать. надо сканировать минуты и секунды.
типа
h=часы, m=минуты, sek=секунды, kuku=включение и отключение кукушки
так вроде должа работать 30 секунд каждый час.
if m=0 and sek<=30 then kuku=1 else kuku=0
а если нужно только в определенные часы то
if h=1 and m=0 and sek<=30 then kuku=1 else kuku=0
if h=12 and m=0 and sek<=30 then kuku=1 else kuku=0
Ну сейчас да. Почти так, как вам нужно.
Но есть одно но. Такой алгоритм не пригоден для существующего скетча, вернее, не совсем пригоден. Кукушка не всегда будет срабатывать. Вот если бы часы показывали только время, а так там навешано отображение кучи другой информации. Если смена часа произойдет в момент показа времени, то кукушка сработает, иначе врядли вы ее дождетесь.
Представьте, сейчас 11:59:55 и тут наступает время отображения дополнительной информации: дата, обе температуры, влажность, давление. И даже если вы у себя отключили вывод макс/мин температуры и график давления, то все-равно за 5 сек эта инфа не успеет пробежать по экрану. А если еще учесть, что вы уменьшили скорость скроллинга? А если это последние дни декабря и добавится "до нового года осталось..."? А если разряжена батарейка? А если день рождения любимой тещи и вы так ее любите, что накатали текст поздравлялки, который еле влез во все 16 сообщений? Тут не то что 5 сек, тут и нескольких минут не хватит.
Даже если использовать флаг (было ку-ку в этом часу или нет) и куковать уже после вывода доп.инфы - ну вернутся часы на отображение времени, скажем, в 12:03 и выдадут "ку-ку". Как будет выглядеть это "ку-ку" в 12:03 этой слегка подгулявшей кукушки?
Т.е., или в корне переделывать скетч на короткий луп, что немного хлопотно (проще написать все с нуля), или воспользоваться средствами DS3231, как я описывал немного раньше, что проще - досточно добавить нужную настройку будильника DS3231 и завести функцию обработки прерывания от будильника. Будильник DS3231 не зависит от нашего лупа и сработает в нужное время, не зависимо, что будет на экране наших часов.
Но есть еще один вариант. Велосипедный, но вариант - сделать так, как в скетче сделаны будильники.
Будильник в часах, работающих от сети 220В, то еще удовольствие. Если не было электричества, когда должен был сработать будильник - значит проспал. Поэтому будильники делались одними из последних по принципу "пускай уже будет" и все переделывать на короткий луп уже не хотелось. Еще я не хотел привязываться к какому-то конкретному модулю RTC - DS1307 или DS3231. Т.к. в DS1307, насколько мне известно (могу и ошибаться), нет выхода прерывания. А хотелось, чтобы была возможность сделать часы на обоих модулях. Потому и такой велосипед.
Так вот, в скетче перед каждым выводом какой-либо информации идет проверка, а не пора ли включить сигнал будильника. И если пора, то игнорируем то, что еще не успели показать, возвращаемся к отображению времени и включаем будильник. Таким образом, задержка хоть и может быть, но она небольшая - считаные секунды.
Можете пойти и таким путем, вместе с будильником проверять еще и нули минут и включать кукушку.
Только меня интересует один вопрос - зачем устанавливать на пине нужный уровень, длительностью определенное (да еще и изменяемое) время? MP3-модули ведь работают по команде, дали команду - проигрался файл.
плеер у меня простой. https://ru.aliexpress.com/item/TF-card-MP3-decoder-board-with-2W-power-d.... лог 1 нужна для имеено такого плеера. у него нет i2c только кнопки можно приделать. запишу туда 1 файл ку-ку т он будет включаться при появлении 5 вольт
Кто может помочь? Выкинул sht, пытаюсь втиснуть bme280, в результате везде нули... ЧЯДНТ? куда копать?
0001
/*** Dot Matrix Clock ************************************************************\
0002
* Для нормального отображения кириллицы и пиктограмм необходимо перед компиляцией *
0003
* в файле preferences.txt установить preproc.substitute_unicode=false *
0004
\************************************************************************* VK007 */
0005
0006
#include <Wire.h>
0007
#include <RTClib.h>
0008
#include <Adafruit_BME280.h>
0009
#include <OneWire.h>
0010
#include <DallasTemperature.h>
0011
#include <LedControl.h>
0012
#include <EEPROM.h>
0013
#include "fonts.h"
0014
0015
#define DS3231 // тип RTC (DS3231 или DS1307)
0016
#define RUS // язык (RUS, UKR, BLR, ENG)
0017
0018
#define ONE_WIRE_BUS 9 // уличный ds18b20
0019
#define BEEPER_PIN 8 // пищалка (с генератором)
0020
#define UP_PIN 7 // кнопка ВВЕРХ/ВПРАВО
0021
#define OK_PIN 6 // кнопка ОК
0022
#define DOWN_PIN 5 // кнопка ВНИЗ/ВЛЕВО
0023
#define DIN_PIN 10 // DIN 1-й матрицы
0024
#define CLK_PIN 11 // CLK матриц
0025
#define CS_PIN 13 // CS матриц
0026
#define BATT_PIN A6 // напряжение батарейки часов
0027
#define SENSOR_PIN A7 // фотодатчик
0028
0029
#define TIME_SHOW_MSEC 30000UL // продолжительность отображения времени (30 сек)
0030
#define PRESSURE_UPDATE_MSEC 7200000UL // интервал обновления графика давления (7 200 000 мс = 2 часа)
0031
#define PRESSURE_VALUE_SHIFT 560 // разница между измеренным и сохраняемым значением давления
0032
// чтобы уместить в byte (диапазон значений давления 560 - 814 мм)
0033
#define ALARMS_ADDR 256 // будильники (256..276 = 21 байт, 7х3 (вкл/выкл, часы, минуты)
0034
#define MESSAGES_ADDR 288 // сообщения (288..1023 = 736 байт, 16х46 (день, месяц, текст до 44 символов))
0035
0036
const
float
voltage_divider_coefficient = 3.2;
// коэффициент делителя напряжения
0037
const
float
Vref = 1.043;
// опорное напряжение
0038
0039
OneWire oneWire(ONE_WIRE_BUS);
0040
DallasTemperature Dallas(&oneWire);
0041
#ifdef DS1307
0042
RTC_DS1307 RTC;
0043
#else
0044
RTC_DS3231 RTC;
0045
#endif
0046
Adafruit_BME280 bme;
0047
LedControl lc = LedControl(DIN_PIN, CLK_PIN, CS_PIN, 4);
0048
DateTime NOW;
0049
byte
HOUR_OLD;
0050
byte
MINUTE_OLD;
0051
boolean bmeOK, dallasOK;
0052
boolean beeper = 1;
0053
unsigned
int
counter;
0054
byte
pressure_addr;
0055
char
string_buffer[52];
0056
byte
screen_buffer[32];
0057
byte
sprite_buffer[255];
0058
byte
sprite_length;
0059
float
t_min, t_max;
0060
byte
t_min_h, t_min_m, t_max_h, t_max_m;
0061
const
char
daysOfTheWeek[7][4] = {
"Sun"
,
"Mon"
,
"Tue"
,
"Wed"
,
"Thu"
,
"Fri"
,
"Sat"
};
0062
#ifdef RUS
0063
const
char
sunday[] PROGMEM =
"воскресенье"
;
0064
const
char
monday[] PROGMEM =
"понедельник"
;
0065
const
char
tuesday[] PROGMEM =
"вторник"
;
0066
const
char
wednesday[] PROGMEM =
"среда"
;
0067
const
char
thursday[] PROGMEM =
"четверг"
;
0068
const
char
friday[] PROGMEM =
"пятница"
;
0069
const
char
saturday[] PROGMEM =
"суббота"
;
0070
const
char
january[] PROGMEM =
"января"
;
0071
const
char
february[] PROGMEM =
"февраля"
;
0072
const
char
march[] PROGMEM =
"марта"
;
0073
const
char
april[] PROGMEM =
"апреля"
;
0074
const
char
may[] PROGMEM =
"мая"
;
0075
const
char
june[] PROGMEM =
"июня"
;
0076
const
char
july[] PROGMEM =
"июля"
;
0077
const
char
august[] PROGMEM =
"августа"
;
0078
const
char
september[] PROGMEM =
"сентября"
;
0079
const
char
october[] PROGMEM =
"октября"
;
0080
const
char
november[] PROGMEM =
"ноября"
;
0081
const
char
december[] PROGMEM =
"декабря"
;
0082
const
char
yyyy[] PROGMEM =
" года"
;
0083
const
char
message_UNY[] PROGMEM =
" до Нового года"
;
0084
const
char
message_HNY[] PROGMEM =
"С Новым годом!"
;
0085
const
char
days1[] PROGMEM =
" день"
;
0086
const
char
days2_4[] PROGMEM =
" дня"
;
0087
const
char
days5_0[] PROGMEM =
" дней"
;
0088
const
char
hours1[] PROGMEM =
" час"
;
0089
const
char
hours2_4[] PROGMEM =
" часа"
;
0090
const
char
hours5_0[] PROGMEM =
" часов"
;
0091
const
char
minutes1[] PROGMEM =
" минута"
;
0092
const
char
minutes2_4[] PROGMEM =
" минуты"
;
0093
const
char
minutes5_0[] PROGMEM =
" минут"
;
0094
const
char
seconds1[] PROGMEM =
" секунда"
;
0095
const
char
seconds2_4[] PROGMEM =
" секунды"
;
0096
const
char
seconds5_0[] PROGMEM =
" секунд"
;
0097
#endif
0098
0099
const
char
*
const
months[] PROGMEM = {january, february, march, april, may, june, july, august, september, october, november, december};
0100
const
char
*
const
dow[] PROGMEM = {sunday, monday, tuesday, wednesday, thursday, friday, saturday};
0101
const
char
*
const
dimension[] PROGMEM = {days1, days2_4, days5_0, hours1, hours2_4, hours5_0, minutes1, minutes2_4, minutes5_0, seconds1, seconds2_4, seconds5_0};
0102
0103
//----------------------------------------------------------------------------------------------
0104
// Установка яркости дисплея по фотодатчику
0105
//----------------------------------------------------------------------------------------------
0106
void
SetBrightness()
0107
{
0108
byte
brightness = map(constrain(analogRead(SENSOR_PIN), 200, 900), 200, 900, 0, 15);
0109
for
(
byte
i = 0; i < 4; i++)
0110
lc.setIntensity(i, brightness);
0111
}
0112
//----------------------------------------------------------------------------------------------
0113
// Выводит на экран текущее время
0114
// первый параметр - тип скролла:
0115
// 0 - вывод без эффектов
0116
// 1 - последняя цифра (единицы минут)
0117
// 2 - две последние цифры (минуты)
0118
// 3 - три последние цифры (единицы часов и минуты)
0119
// 4 - все цифры (часы и минуты)
0120
// 5 - вертикальный скролл каждой цифры по-очереди (начиная с первой слева)
0121
// второй параметр - направление: 0 - вниз, 1 - вверх
0122
//----------------------------------------------------------------------------------------------
0123
void
DisplayTime(
byte
scroll_mode, boolean dir)
0124
{
0125
NOW = RTC.now();
0126
for
(
byte
i = 0; i < 32; i++) sprite_buffer[i] = 0;
0127
for
(
byte
i = 1; i < 7; i++)
0128
if
(NOW.hour() / 10) sprite_buffer[i] = pgm_read_byte_near(font_digit + (NOW.hour() / 10) * 6 + i - 1);
0129
for
(
byte
i = 8; i < 14; i++)
0130
sprite_buffer[i] = pgm_read_byte_near(font_digit + (NOW.hour() % 10) * 6 + i - 8);
0131
for
(
byte
i = 18; i < 24; i++)
0132
sprite_buffer[i] = pgm_read_byte_near(font_digit + (NOW.minute() / 10) * 6 + i - 18);
0133
for
(
byte
i = 25; i < 31; i++)
0134
sprite_buffer[i] = pgm_read_byte_near(font_digit + (NOW.minute() % 10) * 6 + i - 25);
0135
switch
(scroll_mode)
0136
{
0137
case
0: { Show(0);
break
; }
0138
case
1: { ScrollVertical( 24, 31, dir);
break
; }
0139
case
2: { ScrollVertical( 17, 31, dir);
break
; }
0140
case
3: { ScrollVertical( 8, 31, dir);
break
; }
0141
case
4: { ScrollVertical( 0, 31, dir);
break
; }
0142
case
5:
0143
{
0144
sprite_buffer[15] = B01100110;
0145
sprite_buffer[16] = B01100110;
0146
ScrollVertical( 0, 7, dir);
0147
ScrollVertical( 8, 14, dir);
0148
ScrollVertical(15, 16, dir);
0149
ScrollVertical(17, 23, dir);
0150
ScrollVertical(24, 31, dir);
0151
break
;
0152
}
0153
}
0154
HOUR_OLD = NOW.hour();
0155
MINUTE_OLD = NOW.minute();
0156
}
0157
//----------------------------------------------------------------------------------------------
0158
// Возвращает адрес символа в массиве со шрифтом
0159
//----------------------------------------------------------------------------------------------
0160
const
int
char_addr[] = {1, 513, 646, 0, 1183, 184, 1117, 1149, 86, 1165, 100, 1201, 1141, 1123, 1174, 59, 451, 1192, 287, 511, 192, 1157, 1129, 1111, 9, 1135, 51, 1223, 0, 0, 0, 66};
0161
int
CharAddress(
byte
ccc)
0162
{
0163
if
(ccc < 32)
return
0;
0164
if
(ccc < 127)
return
(ccc - 32) * 7;
0165
if
(ccc < 160)
return
0;
0166
if
(ccc < 192)
return
char_addr[ccc - 160];
0167
else
return
(ccc - 97) * 7;
0168
}
0169
//----------------------------------------------------------------------------------------------
0170
// Формирует из строки изображение (сохраняет в массиве - sprite_buffer)
0171
// второй параметр - промежуток между символами (в точках), необязательно (по умолчанию = 1)
0172
//----------------------------------------------------------------------------------------------
0173
void
StringToSprite(
char
*str,
byte
space = 1)
0174
{
0175
for
(
byte
j = 0; j <
sizeof
(sprite_buffer); j++) sprite_buffer[j] = 0;
0176
byte
i = 0;
0177
sprite_length = 0;
0178
while
(str[i] !=
'\0'
&& sprite_length <
sizeof
(sprite_buffer))
0179
{
0180
for
(
byte
j = 1; j <= pgm_read_byte_near(font + CharAddress(str[i])) && sprite_length <
sizeof
(sprite_buffer); j++)
0181
sprite_buffer[sprite_length++] = pgm_read_byte_near(font + CharAddress(str[i]) + j);
0182
for
(
byte
j = 0; j < space && sprite_length <
sizeof
(sprite_buffer); j++)
0183
sprite_length++;
0184
if
(space > 0 && str[i] ==
'7'
&& (str[i + 1] ==
'4'
|| str[i + 1] ==
','
|| str[i + 1] ==
'.'
))
0185
sprite_length--;
0186
i++;
0187
}
0188
sprite_length -= space;
0189
}
0190
//----------------------------------------------------------------------------------------------
0191
// Переводит значение температуры из float в строку нужного формата (сохраняет в string_buffer)
0192
// второй параметр необязательный - добавлять или нет в конце строки символ 'C' (по умолчанию = 1)
0193
//----------------------------------------------------------------------------------------------
0194
void
TempToString(
float
temp, boolean mode = 1)
0195
{
0196
byte
i = 1;
0197
byte
int_temp = 0.051 + abs(temp);
0198
byte
frac_temp =
int
((0.051 + abs(temp)) * 10) % 10;
0199
if
(int_temp == 0 && frac_temp == 0)
0200
string_buffer[0] =
'0'
;
0201
else
0202
{
0203
if
(temp < 0)
0204
string_buffer[0] =
'-'
;
0205
else
0206
string_buffer[0] =
'+'
;
0207
if
(int_temp > 9)
0208
{
0209
string_buffer[i++] = int_temp / 10 +
'0'
;
0210
string_buffer[i++] = int_temp % 10 +
'0'
;
0211
}
0212
else
0213
string_buffer[i++] = int_temp +
'0'
;
0214
string_buffer[i++] =
','
;
0215
string_buffer[i++] = frac_temp +
'0'
;
0216
}
0217
string_buffer[i++] =
'°'
;
0218
if
(mode) string_buffer[i++] =
'C'
;
0219
string_buffer[i] =
'\0'
;
0220
}
0221
//----------------------------------------------------------------------------------------------
0222
// Переводит значение влажности из float в строку нужного формата (сохраняет в string_buffer)
0223
//----------------------------------------------------------------------------------------------
0224
void
HumToString(
float
hum)
0225
{
0226
string_buffer[0] =
'\xB7'
;
0227
string_buffer[1] =
'\xA0'
;
0228
byte
i = 2;
0229
byte
int_hum = 0.51 + hum;
0230
if
(int_hum > 9)
0231
{
0232
string_buffer[i++] = int_hum / 10 +
'0'
;
0233
string_buffer[i++] = int_hum % 10 +
'0'
;
0234
}
0235
else
0236
string_buffer[i++] = int_hum +
'0'
;
0237
string_buffer[i] =
'%'
;
0238
string_buffer[i + 1] =
'R'
;
0239
string_buffer[i + 2] =
'H'
;
0240
string_buffer[i + 3] =
'\0'
;
0241
}
0242
//----------------------------------------------------------------------------------------------
0243
// Переводит значение давления из int в строку нужного формата (сохраняет в string_buffer)
0244
//----------------------------------------------------------------------------------------------
0245
void
PresToString(
int
int_pres)
0246
{
0247
string_buffer[0] =
'\xAE'
;
0248
string_buffer[1] =
' '
;
0249
string_buffer[4] = int_pres % 10 +
'0'
;
0250
int_pres = int_pres / 10;
0251
string_buffer[3] = int_pres % 10 +
'0'
;
0252
string_buffer[2] = int_pres / 10 +
'0'
;
0253
string_buffer[5] =
'\0'
;
0254
}
0255
//----------------------------------------------------------------------------------------------
0256
// Вспомогательная функция для Tminmax() - центрирует картинку с температурой/временем
0257
//----------------------------------------------------------------------------------------------
0258
void
ShiftT(boolean mode)
0259
{
0260
byte
shift = (26 - sprite_length)/2 + 6;
0261
for
(
byte
i = 1; i <= sprite_length; i++)
0262
sprite_buffer[sprite_length + shift - i] = sprite_buffer[sprite_length - i];
0263
for
(
byte
i = 5; i < shift; i++)
0264
sprite_buffer[i] = 0;
0265
for
(
byte
i = 0; i < 5; i++)
0266
sprite_buffer[i] = pgm_read_byte_near(font + CharAddress(mode ?
'¶'
:
'№'
) + i + 1);
0267
sprite_length += shift;
0268
}
0269
//----------------------------------------------------------------------------------------------
0270
// Выводит на экран минимальную/максимальную температуру
0271
// параметр - 0 (min температура), 1 (max температура)
0272
//----------------------------------------------------------------------------------------------
0273
void
Tminmax(boolean mode)
0274
{
0275
TempToString(mode ? t_max : t_min, 0);
0276
StringToSprite(string_buffer);
0277
ShiftT(mode);
0278
for
(
byte
i = 0; i < 8; i++)
0279
{
0280
ScrollVerticalOneRow(0, 5, mode);
0281
ScrollVerticalOneRow(6, 31, !mode);
0282
Show(0);
0283
}
0284
delay(1500);
0285
string_buffer[0] = (mode ? t_max_h : t_min_h) / 10 +
'0'
;
0286
string_buffer[1] = (mode ? t_max_h : t_min_h) % 10 +
'0'
;
0287
string_buffer[2] =
':'
;
0288
string_buffer[3] = (mode ? t_max_m : t_min_m) / 10 +
'0'
;
0289
string_buffer[4] = (mode ? t_max_m : t_min_m) % 10 +
'0'
;
0290
string_buffer[5] = 0;
0291
StringToSprite(string_buffer);
0292
ShiftT(mode);
0293
ScrollVertical(6, 31, !mode);
0294
delay(1500);
0295
}
0296
//----------------------------------------------------------------------------------------------
0297
// Используется для вывода в бегущей строке "обратного отсчета"
0298
//----------------------------------------------------------------------------------------------
0299
void
ShowCountdown(
byte
num,
byte
ndim)
0300
{
0301
string_buffer[0] = num < 10 ?
' '
: num / 10 +
'0'
;
0302
string_buffer[1] = num % 10 +
'0'
;
0303
string_buffer[2] = 0;
0304
StringToSprite(string_buffer);
0305
ScrollBufferToScreen(0);
0306
#ifdef ENG
0307
if
(num != 1) ndim++;
0308
#else
0309
if
(string_buffer[1] >
'1'
&& string_buffer[1] <
'5'
&& string_buffer[0] !=
'1'
) ndim++;
0310
else
if
(string_buffer[1] >
'4'
|| string_buffer[1] ==
'0'
|| string_buffer[0] ==
'1'
) ndim += 2;
0311
#endif
0312
strcpy_P(string_buffer, (
char
*)pgm_read_word(&(dimension[ndim])));
0313
StringToSprite(string_buffer);
0314
ScrollBufferToScreen(0);
0315
}
0316
//----------------------------------------------------------------------------------------------
0317
// Выводит изображение из спрайт-буфера на экран со сдвигом влево всего содержимого (экран + спрайт-буфер)
0318
// если указан параметр 0, то на экране останется "хвост" картинки/текста
0319
// если 1 - то картинка полностью "уедет" за левый край экрана
0320
//----------------------------------------------------------------------------------------------
0321
void
ScrollBufferToScreen(boolean mode)
0322
{
0323
for
(
byte
i = 0; i < sprite_length; i++)
0324
ScrollScreenBufferOneLeft(1);
0325
if
(mode)
0326
for
(
byte
i = 0; i < 32; i++)
0327
ScrollScreenBufferOneLeft(0);
0328
}
0329
//----------------------------------------------------------------------------------------------
0330
// Выводит в центр экрана изображение из спрайт-буфера (со сдвигом влево)
0331
//----------------------------------------------------------------------------------------------
0332
void
SpriteToCenterScreen()
0333
{
0334
for
(
byte
i = 0; i <= (32 - sprite_length) / 2; i++)
0335
ScrollScreenBufferOneLeft(0);
0336
for
(
byte
i = 0; i < sprite_length / 2 + 16; i++)
0337
ScrollScreenBufferOneLeft(1);
0338
}
0339
//----------------------------------------------------------------------------------------------
0340
// Сдвигает экран на одну точку влево
0341
// если параметр 0, то сдвигается только экран (последняя колонка очищается)
0342
// если 1 - то сдвигается экран + спрайт-буфер (в последнюю колонку переносятся данные из спрайт-буфера)
0343
//----------------------------------------------------------------------------------------------
0344
void
ScrollScreenBufferOneLeft(boolean mode)
0345
{
0346
for
(
byte
row = 0; row < 32; row++)
0347
screen_buffer[row] = screen_buffer[row + 1];
0348
if
(mode)
0349
{
0350
screen_buffer[31] = sprite_buffer[0];
0351
for
(
byte
i = 0; i < sprite_length - 1; i++)
0352
{
0353
sprite_buffer[i] = sprite_buffer[i + 1];
0354
sprite_buffer[i + 1] = 0;
0355
}
0356
}
0357
else
0358
screen_buffer[31] = 0;
0359
Show(0);
0360
}
0361
//----------------------------------------------------------------------------------------------
0362
// Вертикальный скролл на один ряд экранного буфера (без отображения на экране)
0363
// данные из экранного буфера вытесняются данными из аналогичной области спрайт-буфера (ячейки 0 - 31)
0364
// первые два параметра - с какой колонки скроллировать и по какую (0...31)
0365
// третий - направление: 1 - вверх, 0 - вниз
0366
//----------------------------------------------------------------------------------------------
0367
void
ScrollVerticalOneRow(
byte
from,
byte
to, boolean dir)
0368
{
0369
for
(
byte
row = from; row < to + 1; row++)
0370
{
0371
if
(dir)
0372
{
0373
screen_buffer[row] >>= 1;
0374
bitWrite(screen_buffer[row], 7, bitRead(sprite_buffer[row], 0));
0375
sprite_buffer[row] >>= 1;
0376
}
0377
else
0378
{
0379
screen_buffer[row] <<= 1;
0380
bitWrite(screen_buffer[row], 0, bitRead(sprite_buffer[row], 7));
0381
sprite_buffer[row] <<= 1;
0382
}
0383
}
0384
}
0385
//----------------------------------------------------------------------------------------------
0386
// Вертикальный скролл (на все 8 точек) части экрана
0387
// данные на экране (из экранного буфера) вытесняются данными из аналогичной области спрайт-буфера (ячейки 0 - 31)
0388
// первые два параметра - с какой колонки скроллировать и по какую (0...31)
0389
// третий - направление: 1 - вверх, 0 - вниз
0390
//----------------------------------------------------------------------------------------------
0391
void
ScrollVertical(
byte
from,
byte
to, boolean dir)
0392
{
0393
for
(
byte
i = 0; i < 8; i++)
0394
{
0395
ScrollVerticalOneRow(from, to, dir);
0396
Show(0);
0397
}
0398
}
0399
//----------------------------------------------------------------------------------------------
0400
// Вывод содержимого буфера на экран
0401
// параметр - тип буфера: 0 - из экранного, 1 - из спрайт-буфера
0402
//----------------------------------------------------------------------------------------------
0403
void
Show(boolean mode)
0404
{
0405
for
(
byte
row = 0; row < 32; row++)
0406
lc.setRow(row / 8, row % 8, mode ? sprite_buffer[row] : screen_buffer[row]);
0407
}
0408
//----------------------------------------------------------------------------------------------
0409
// Мерцание определенной матрицы (0...3)
0410
//----------------------------------------------------------------------------------------------
0411
void
Blink(
byte
n)
0412
{
0413
byte
c_brightness = 0;
0414
char
direction = 1;
0415
while
(digitalRead(OK_PIN) && digitalRead(UP_PIN) && digitalRead(DOWN_PIN))
0416
{
0417
byte
brightness = map(constrain(analogRead(SENSOR_PIN), 200, 900), 200, 900, 0, 15);
0418
for
(
byte
i = 0; i < 4; i++) lc.setIntensity(i, n == i ? c_brightness : brightness);
0419
if
(c_brightness == 0) direction = 1;
0420
if
(c_brightness == 15) direction = -1;
0421
c_brightness += direction;
0422
delay(20);
0423
}
0424
}
0425
//----------------------------------------------------------------------------------------------
0426
// Мигающий курсор
0427
// в параметрах - начало и конец курсора (0...31)
0428
//----------------------------------------------------------------------------------------------
0429
void
Cursor(
byte
from,
byte
to)
0430
{
0431
boolean on = 1;
0432
while
(digitalRead(OK_PIN) && digitalRead(UP_PIN) && digitalRead(DOWN_PIN))
0433
{
0434
counter = 0;
0435
if
((millis() % 500 < 250) == on)
0436
{
0437
for
(
byte
i = from; i <= to; i++)
0438
lc.setLed(i / 8, i % 8, 0, on);
0439
on = !on;
0440
}
0441
SetBrightness();
0442
}
0443
}
0444
//----------------------------------------------------------------------------------------------
0445
// Выдает короткий звук (щелчок) на пищалку
0446
//----------------------------------------------------------------------------------------------
0447
void
Beep()
0448
{
0449
digitalWrite(BEEPER_PIN, 1);
0450
delay(2);
0451
digitalWrite(BEEPER_PIN, 0);
0452
}
0453
//----------------------------------------------------------------------------------------------
0454
// Выдает короткий звук (щелчок) на пищалку и ждет отпускания кнопки
0455
//----------------------------------------------------------------------------------------------
0456
void
ButtonPressed()
0457
{
0458
Beep();
0459
while
(!digitalRead(OK_PIN) || !digitalRead(UP_PIN) || !digitalRead(DOWN_PIN)) delay(50);
0460
}
0461
//----------------------------------------------------------------------------------------------
0462
// Проверка будильника
0463
//----------------------------------------------------------------------------------------------
0464
boolean AlarmNotActive()
0465
{
0466
NOW = RTC.now();
0467
return
!(EEPROM.read(NOW.dayOfTheWeek() * 3 + ALARMS_ADDR) == 1 && NOW.hour() == EEPROM.read(NOW.dayOfTheWeek() * 3 + ALARMS_ADDR + 1) && NOW.minute() == EEPROM.read(NOW.dayOfTheWeek() * 3 + ALARMS_ADDR + 2));
0468
}
0469
//----------------------------------------------------------------------------------------------
0470
// Настройка времени
0471
//----------------------------------------------------------------------------------------------
0472
void
SetupTime()
0473
{
0474
NOW = RTC.now();
0475
char
HOUR = NOW.hour();
0476
char
MINUTE = NOW.minute();
0477
byte
pos = 0;
0478
while
(pos < 2)
0479
{
0480
string_buffer[0] =
' '
;
0481
string_buffer[1] =
' '
;
0482
byte
i = 2;
0483
if
(HOUR / 10 == 1) string_buffer[i++] =
'\xA0'
;
0484
string_buffer[i++] = HOUR / 10 +
'0'
;
0485
string_buffer[i++] = HOUR % 10 +
'0'
;
0486
if
(HOUR % 10 == 1) string_buffer[i++] =
'\xA0'
;
0487
string_buffer[i++] =
':'
;
0488
if
(MINUTE / 10 == 1) string_buffer[i++] =
'\xA0'
;
0489
string_buffer[i++] = MINUTE / 10 +
'0'
;
0490
string_buffer[i++] = MINUTE % 10 +
'0'
;
0491
string_buffer[i] =
'\0'
;
0492
StringToSprite(string_buffer);
0493
Show(1);
0494
Cursor(pos == 0 ? 6 : 18, pos == 0 ? 14 : 26);
0495
if
(!digitalRead(UP_PIN))
0496
{
0497
if
(!counter) Beep();
0498
if
(!counter || counter > 4)
0499
{
0500
if
(pos == 0)
0501
{
0502
HOUR++;
if
(HOUR > 23) HOUR = 0;
0503
}
0504
else
0505
{
0506
MINUTE++;
if
(MINUTE > 59) MINUTE = 0;
0507
}
0508
}
0509
counter++;
0510
delay(100);
0511
}
0512
if
(!digitalRead(DOWN_PIN))
0513
{
0514
if
(!counter) Beep();
0515
if
(!counter || counter > 4)
0516
{
0517
if
(pos == 0)
0518
{
0519
HOUR--;
if
(HOUR < 0) HOUR = 23;
0520
}
0521
else
0522
{
0523
MINUTE--;
if
(MINUTE < 0) MINUTE = 59;
0524
}
0525
}
0526
counter++;
0527
delay(100);
0528
}
0529
if
(!digitalRead(OK_PIN))
0530
{
0531
ButtonPressed();
0532
pos++;
0533
}
0534
}
0535
NOW = RTC.now();
0536
RTC.adjust(DateTime(NOW.year(), NOW.month(), NOW.day(), HOUR, MINUTE, 0));
0537
}
0538
//----------------------------------------------------------------------------------------------
0539
// Настройка даты
0540
//----------------------------------------------------------------------------------------------
0541
void
SetupDate()
0542
{
0543
NOW = RTC.now();
0544
int
YEAR = NOW.year();
0545
char
MONTH = NOW.month();
0546
char
DAY = NOW.day();
0547
byte
pos = 0;
0548
while
(pos < 3)
0549
{
0550
string_buffer[0] =
'\xA0'
;
0551
byte
i = 1;
0552
if
(DAY / 10 == 1) string_buffer[i++] =
'\xA0'
;
0553
string_buffer[i++] = DAY / 10 +
'0'
;
0554
string_buffer[i++] = DAY % 10 +
'0'
;
0555
if
(DAY % 10 == 1) string_buffer[i++] =
'\xA0'
;
0556
string_buffer[i++] =
'\xA0'
;
0557
if
(MONTH / 10 == 1) string_buffer[i++] =
'\xA0'
;
0558
string_buffer[i++] = MONTH / 10 +
'0'
;
0559
string_buffer[i++] = MONTH % 10 +
'0'
;
0560
if
(MONTH % 10 == 1) string_buffer[i++] =
'\xA0'
;
0561
string_buffer[i++] =
'\xA0'
;
0562
if
((YEAR - 2000) / 10 == 1) string_buffer[i++] =
'\xA0'
;
0563
string_buffer[i++] = (YEAR - 2000) / 10 +
'0'
;
0564
string_buffer[i++] = (YEAR - 2000) % 10 +
'0'
;
0565
string_buffer[i] =
'\0'
;
0566
StringToSprite(string_buffer);
0567
Show(1);
0568
if
(pos == 0) Cursor(1, 9);
0569
else
0570
if
(pos == 1) Cursor(12, 20);
0571
else
Cursor(23, 31);
0572
if
(!digitalRead(UP_PIN))
0573
{
0574
if
(!counter) Beep();
0575
if
(!counter || counter > 4)
0576
{
0577
if
(pos == 0)
0578
{
0579
DAY++;
if
(DAY > 31) DAY = 1;
0580
}
0581
else
0582
{
0583
if
(pos == 1)
0584
{
0585
MONTH++;
if
(MONTH > 12) MONTH = 1;
0586
}
0587
else
0588
{
0589
YEAR++;
if
(YEAR > 2099) YEAR = 2000;
0590
}
0591
}
0592
}
0593
counter++;
0594
delay(100);
0595
}
0596
if
(!digitalRead(DOWN_PIN))
0597
{
0598
if
(!counter) Beep();
0599
if
(!counter || counter > 4)
0600
{
0601
if
(pos == 0)
0602
{
0603
DAY--;
if
(DAY < 1) DAY = 31;
0604
}
0605
else
0606
{
0607
if
(pos == 1)
0608
{
0609
MONTH--;
if
(MONTH < 1) MONTH = 12;
0610
}
0611
else
0612
{
0613
YEAR--;
if
(YEAR < 2000 || YEAR > 2099) YEAR = 2099;
0614
}
0615
}
0616
}
0617
counter++;
0618
delay(100);
0619
}
0620
if
(!digitalRead(OK_PIN))
0621
{
0622
ButtonPressed();
0623
pos++;
0624
}
0625
}
0626
if
((DAY == 31 && (MONTH == 4 || MONTH == 6 || MONTH == 9 || MONTH == 11)) || (MONTH == 2 && ((DAY > 28 && (YEAR % 4)) || (DAY > 29 && !(YEAR % 4)))))
0627
{
0628
DAY = 1; MONTH++;
0629
}
0630
NOW = RTC.now();
0631
RTC.adjust(DateTime(YEAR, MONTH, DAY, NOW.hour(), NOW.minute(), NOW.second()));
0632
}
0633
//----------------------------------------------------------------------------------------------
0634
// Настройка будильников
0635
//----------------------------------------------------------------------------------------------
0636
void
SetupAlarms()
0637
{
0638
byte
ndow = 1;
0639
byte
pos = 0;
0640
byte
state = 0;
0641
char
HOUR = 0;
0642
char
MINUTE = 0;
0643
while
(pos < 4)
0644
{
0645
if
(pos == 0)
0646
{
0647
if
(ndow == 8)
0648
{
0649
state = 0; HOUR = 0; MINUTE = 0;
0650
}
0651
else
0652
{
0653
state = EEPROM.read(ndow < 7 ? ndow * 3 + ALARMS_ADDR : ALARMS_ADDR) == 1;
0654
HOUR = EEPROM.read(ndow < 7 ? ndow * 3 + ALARMS_ADDR + 1 : ALARMS_ADDR + 1);
0655
MINUTE = EEPROM.read(ndow < 7 ? ndow * 3 + ALARMS_ADDR + 2 : ALARMS_ADDR + 2);
0656
}
0657
}
0658
if
(HOUR < 0 || HOUR > 23 || MINUTE < 0 || MINUTE > 59)
0659
{
0660
HOUR = 0; MINUTE = 0;
0661
}
0662
string_buffer[0] =
'!'
;
0663
string_buffer[1] = state ?
'±'
:
'¤'
;
0664
byte
i = 2;
0665
if
(HOUR / 10 == 1) string_buffer[i++] =
'\xA0'
;
0666
string_buffer[i++] = HOUR / 10 +
'0'
;
0667
string_buffer[i++] = HOUR % 10 +
'0'
;
0668
if
(HOUR % 10 == 1) string_buffer[i++] =
'\xA0'
;
0669
string_buffer[i++] =
':'
;
0670
if
(MINUTE / 10 == 1) string_buffer[i++] =
'\xA0'
;
0671
string_buffer[i++] = MINUTE / 10 +
'0'
;
0672
string_buffer[i++] = MINUTE % 10 +
'0'
;
0673
string_buffer[i] =
'\0'
;
0674
StringToSprite(string_buffer);
0675
sprite_buffer[0] = ndow < 8 ? 1 << (ndow - 1) : B01111111;
0676
Show(1);
0677
switch
(pos)
0678
{
0679
case
0: { Cursor(0, 1);
break
; }
0680
case
1: { Cursor(2, 9);
break
; }
0681
case
2: { Cursor(11, 19);
break
; }
0682
case
3: { Cursor(23, 31);
break
; }
0683
}
0684
if
(!digitalRead(UP_PIN))
0685
{
0686
if
(!counter) Beep();
0687
if
(!counter || counter > 4)
0688
{
0689
switch
(pos)
0690
{
0691
case
0: { ndow--;
if
(ndow < 1) ndow = 8;
break
; }
0692
case
1: { state = !state;
break
; }
0693
case
2: { HOUR++;
if
(HOUR > 23) HOUR = 0;
break
; }
0694
case
3: { MINUTE++;
if
(MINUTE > 59) MINUTE = 0;
break
; }
0695
}
0696
}
0697
counter++;
0698
delay(100);
0699
}
0700
if
(!digitalRead(DOWN_PIN))
0701
{
0702
if
(!counter) Beep();
0703
if
(!counter || counter > 4)
0704
{
0705
switch
(pos)
0706
{
0707
case
0: { ndow++;
if
(ndow > 8) ndow = 1;
break
; }
0708
case
1: { state = !state;
break
; }
0709
case
2: { HOUR--;
if
(HOUR < 0) HOUR = 23;
break
; }
0710
case
3: { MINUTE--;
if
(MINUTE < 0) MINUTE = 59;
break
; }
0711
}
0712
}
0713
counter++;
0714
delay(100);
0715
}
0716
if
(!digitalRead(OK_PIN))
0717
{
0718
ButtonPressed();
0719
pos++;
0720
}
0721
}
0722
if
(ndow == 7) ndow = 0;
0723
if
(ndow < 7)
0724
{
0725
EEPROM.write(ndow * 3 + ALARMS_ADDR, state);
0726
EEPROM.write(ndow * 3 + ALARMS_ADDR + 1, HOUR);
0727
EEPROM.write(ndow * 3 + ALARMS_ADDR + 2, MINUTE);
0728
}
0729
else
0730
for
(
byte
i = 0; i < 7; i++)
0731
{
0732
EEPROM.write(i * 3 + ALARMS_ADDR, state);
0733
EEPROM.write(i * 3 + ALARMS_ADDR + 1, HOUR);
0734
EEPROM.write(i * 3 + ALARMS_ADDR + 2, MINUTE);
0735
}
0736
}
0737
//----------------------------------------------------------------------------------------------
0738
// Вспомогательная функция для SerialSetup()
0739
//----------------------------------------------------------------------------------------------
0740
void
SetAlarmTime(
byte
n)
0741
{
0742
EEPROM.write(n * 3 + ALARMS_ADDR + 1, string_buffer[8]);
0743
EEPROM.write(n * 3 + ALARMS_ADDR + 2, string_buffer[9]);
0744
Serial
.print(F(
"Set time alarm "
));
0745
Serial
.print(n, DEC);
0746
Serial
.print(F(
" ("
));
0747
Serial
.print(daysOfTheWeek[n]);
0748
Serial
.print(F(
"): "
));
0749
Serial
.print(string_buffer[3]);
0750
Serial
.print(string_buffer[4]);
0751
Serial
.print(
":"
);
0752
Serial
.print(string_buffer[5]);
0753
Serial
.print(string_buffer[6]);
0754
if
(string_buffer[7])
0755
{
0756
EEPROM.write(n * 3 + ALARMS_ADDR, string_buffer[7] ==
'+'
? 1 : 0);
0757
Serial
.print(string_buffer[7] ==
'+'
? F(
" on"
) : F(
" off"
));
0758
}
0759
Serial
.println();
0760
}
0761
//----------------------------------------------------------------------------------------------
0762
// Настройка через Serial
0763
//----------------------------------------------------------------------------------------------
0764
void
SerialSetup()
0765
{
0766
while
(
Serial
.available())
Serial
.read();
0767
Serial
.setTimeout(50);
0768
Serial
.println(F(
"Thhmmss - set time (e.g. T094500 = 09:45:00)"
));
0769
Serial
.println(F(
"DddMMyy - set date (e.g. D050418 = 05 Apr 2018)"
));
0770
Serial
.println(F(
"Ax=hhmmz - set alarm, x = 0(or 7) - 6 (Sun/Boc - Sat/Cy6) or * (all alarms)"
));
0771
Serial
.println(F(
"\t z = + (on), - (off) or nothing (state does not change)"
));
0772
Serial
.println(F(
"\t (e.g. A*=0700+ = set alarm on for 07:00 every day of the week)"
));
0773
Serial
.println(F(
"Ax+\t- alarm on"
));
0774
Serial
.println(F(
"Ax-\t- alarm off"
));
0775
Serial
.println(F(
"A\t- list of alarm clocks"
));
0776
Serial
.println(F(
"Mn=ddMMtext - save message (n = 0 - 9, A - F; text max 44 characters)"
));
0777
Serial
.println(F(
"\t (e.g. M0=2509Happy Birthday!)"
));
0778
Serial
.println(F(
"Mn-\t- delete message"
));
0779
Serial
.println(F(
"Mn\t- show message"
));
0780
Serial
.println(F(
"M\t- list of messages"
));
0781
Serial
.println(F(
"OK\n"
));
0782
StringToSprite(
"\xA9<\xAD>\xB5"
);
0783
Show(1);
0784
while
(digitalRead(OK_PIN) && digitalRead(UP_PIN) && digitalRead(DOWN_PIN))
0785
{
0786
if
(
Serial
.available())
0787
{
0788
delay(20);
0789
string_buffer[
Serial
.readBytes(string_buffer,
sizeof
(string_buffer) - 1)] = 0;
0790
delay(20);
0791
while
(
Serial
.available()) {
Serial
.read(); delay(5); }
0792
Serial
.println(string_buffer);
0793
boolean OK = 1;
0794
bitClear(string_buffer[0], 5);
0795
switch
(string_buffer[0])
0796
{
0797
case
'T'
:
0798
{
0799
string_buffer[7] = (string_buffer[1] -
'0'
) * 10 + (string_buffer[2] -
'0'
);
0800
string_buffer[8] = (string_buffer[3] -
'0'
) * 10 + (string_buffer[4] -
'0'
);
0801
string_buffer[9] = (string_buffer[5] -
'0'
) * 10 + (string_buffer[6] -
'0'
);
0802
if
(
byte
(string_buffer[7]) < 24 &&
byte
(string_buffer[8]) < 60 &&
byte
(string_buffer[9]) < 60)
0803
{
0804
NOW = RTC.now();
0805
RTC.adjust(DateTime(NOW.year(), NOW.month(), NOW.day(), string_buffer[7], string_buffer[8], string_buffer[9]));
0806
Serial
.print(F(
"Set time: "
));
0807
Serial
.print(string_buffer[1]);
0808
Serial
.print(string_buffer[2]);
0809
Serial
.print(
":"
);
0810
Serial
.print(string_buffer[3]);
0811
Serial
.print(string_buffer[4]);
0812
Serial
.print(
":"
);
0813
Serial
.print(string_buffer[5]);
0814
Serial
.println(string_buffer[6]);
0815
}
0816
else
OK = 0;
0817
break
;
0818
}
0819
case
'D'
:
0820
{
0821
string_buffer[7] = (string_buffer[1] -
'0'
) * 10 + (string_buffer[2] -
'0'
);
0822
string_buffer[8] = (string_buffer[3] -
'0'
) * 10 + (string_buffer[4] -
'0'
);
0823
string_buffer[9] = (string_buffer[5] -
'0'
) * 10 + (string_buffer[6] -
'0'
);
0824
if
(string_buffer[7] > 0 && !(string_buffer[7] > 31 || (string_buffer[7] > 30 && (string_buffer[8] == 4 || string_buffer[8] == 6 || string_buffer[8] == 9 || string_buffer[8] == 11)) || (string_buffer[8] == 2 && ((string_buffer[7] > 28 && (string_buffer[9] % 4)) || (string_buffer[7] > 29 && !(string_buffer[9] % 4))))) && string_buffer[8] > 0 && string_buffer[8] < 13 &&
byte
(string_buffer[9]) < 100)
0825
{
0826
NOW = RTC.now();
0827
RTC.adjust(DateTime(2000 + string_buffer[9], string_buffer[8], string_buffer[7], NOW.hour(), NOW.minute(), NOW.second()));
0828
Serial
.print(F(
"Set date: "
));
0829
Serial
.print(string_buffer[1]);
0830
Serial
.print(string_buffer[2]);
0831
Serial
.print(
"."
);
0832
Serial
.print(string_buffer[3]);
0833
Serial
.print(string_buffer[4]);
0834
Serial
.print(F(
".20"
));
0835
Serial
.print(string_buffer[5]);
0836
Serial
.println(string_buffer[6]);
0837
}
0838
else
OK = 0;
0839
break
;
0840
}
0841
case
'A'
:
0842
{
0843
if
(string_buffer[1] == 0)
0844
for
(
byte
i = 1; i < 8; i++)
0845
{
0846
Serial
.print(F(
"Alarm "
));
0847
Serial
.print(i, DEC);
0848
Serial
.print(F(
" ("
));
0849
Serial
.print(daysOfTheWeek[i % 7]);
0850
Serial
.print(F(
"): "
));
0851
string_buffer[2] = EEPROM.read(i % 7 * 3 + ALARMS_ADDR + 1);
0852
string_buffer[3] = EEPROM.read(i % 7 * 3 + ALARMS_ADDR + 2);
0853
if
(
byte
(string_buffer[2]) < 24 &&
byte
(string_buffer[3]) < 60)
0854
{
0855
if
(string_buffer[2] < 10)
Serial
.print(
"0"
);
0856
Serial
.print(string_buffer[2], DEC);
0857
Serial
.print(
":"
);
0858
if
(string_buffer[3] < 10)
Serial
.print(
"0"
);
0859
Serial
.print(string_buffer[3], DEC);
0860
Serial
.println(EEPROM.read(i % 7 * 3 + ALARMS_ADDR) == 1 ? F(
" on"
) : F(
" off"
));
0861
}
0862
else
Serial
.println(F(
"not set"
));
0863
}
0864
else
0865
{
0866
string_buffer[1] = string_buffer[1] -
'0'
;
0867
if
(string_buffer[1] == 7) string_buffer[1] = 0;
0868
if
(
byte
(string_buffer[1]) < 7 || string_buffer[1] == -6)
0869
{
0870
if
(string_buffer[2] ==
'='
)
0871
{
0872
string_buffer[8] = (string_buffer[3] -
'0'
) * 10 + (string_buffer[4] -
'0'
);
0873
string_buffer[9] = (string_buffer[5] -
'0'
) * 10 + (string_buffer[6] -
'0'
);
0874
if
(
byte
(string_buffer[8]) < 24 &&
byte
(string_buffer[9]) < 60 && (string_buffer[7] ==
'+'
|| string_buffer[7] ==
'-'
|| string_buffer[7] == 0))
0875
{
0876
if
(string_buffer[1] == -6)
for
(
byte
i = 0; i < 7; i++) SetAlarmTime(i);
0877
else
SetAlarmTime(string_buffer[1]);
0878
}
0879
else
OK = 0;
0880
}
0881
else
0882
{
0883
if
(string_buffer[2] ==
'+'
|| string_buffer[2] ==
'-'
)
0884
{
0885
if
(string_buffer[1] == -6)
0886
{
0887
for
(
byte
i = 0; i < 7; i++) EEPROM.write(i * 3 + ALARMS_ADDR, string_buffer[2] ==
'+'
? 1 : 0);
0888
Serial
.print(F(
"All alarms "
));
0889
}
0890
else
0891
{
0892
EEPROM.write(string_buffer[1] * 3 + ALARMS_ADDR, string_buffer[2] ==
'+'
? 1 : 0);
0893
Serial
.print(F(
"Alarm "
));
0894
Serial
.print(string_buffer[1], DEC);
0895
Serial
.print(F(
" ("
));
0896
Serial
.print(daysOfTheWeek[string_buffer[1]]);
0897
Serial
.print(F(
") "
));
0898
}
0899
Serial
.println(string_buffer[2] ==
'+'
? F(
"on"
) : F(
"off"
));
0900
}
0901
else
OK = 0;
0902
}
0903
}
0904
else
OK = 0;
0905
}
0906
break
;
0907
}
0908
case
'M'
:
0909
{
0910
if
(string_buffer[1] == 0)
0911
{
0912
for
(
char
i = 0; i < 16; i++)
0913
{
0914
Serial
.print(F(
"Message "
));
0915
Serial
.print(i < 10 ?
char
(i +
'0'
) :
char
(i - 10 +
'A'
));
0916
Serial
.print(F(
": "
));
0917
string_buffer[2] = EEPROM.read(i * 46 + MESSAGES_ADDR);
0918
string_buffer[3] = EEPROM.read(i * 46 + MESSAGES_ADDR + 1);
0919
if
(string_buffer[2] > 0 && string_buffer[2] < 32 && string_buffer[3] > 0 && string_buffer[3] < 13)
0920
{
0921
if
(string_buffer[2] < 10)
Serial
.print(
"0"
);
0922
Serial
.print(string_buffer[2], DEC);
0923
Serial
.print(
"."
);
0924
if
(string_buffer[3] < 10)
Serial
.print(
"0"
);
0925
Serial
.print(string_buffer[3], DEC);
0926
Serial
.print(
" "
);
0927
for
(
byte
c = 0; c < 44; c++)
0928
{
0929
char
read_char = EEPROM.read(i * 46 + MESSAGES_ADDR + 2 + c);
0930
if
(read_char != 0)
Serial
.print(read_char);
0931
else
break
;
0932
}
0933
Serial
.println();
0934
}
0935
else
Serial
.println(F(
"not set"
));
0936
}
0937
}
0938
else
0939
{
0940
if
(string_buffer[1] >=
'a'
) bitClear(string_buffer[1], 5);
0941
if
((string_buffer[1] >=
'0'
&& string_buffer[1] <=
'9'
) || (string_buffer[1] >=
'A'
&& string_buffer[1] <=
'F'
))
0942
{
0943
string_buffer[1] = string_buffer[1] >
'9'
? string_buffer[1] -
'A'
+ 10 : string_buffer[1] -
'0'
;
0944
if
(string_buffer[2] ==
'='
)
0945
{
0946
string_buffer[0] = (string_buffer[3] -
'0'
) * 10 + (string_buffer[4] -
'0'
);
0947
string_buffer[2] = (string_buffer[5] -
'0'
) * 10 + (string_buffer[6] -
'0'
);
0948
if
(string_buffer[0] > 0 && string_buffer[0] < 32 && string_buffer[2] > 0 && string_buffer[2] < 13 && string_buffer[7])
0949
{
0950
EEPROM.write(string_buffer[1] * 46 + MESSAGES_ADDR, string_buffer[0]);
0951
EEPROM.write(string_buffer[1] * 46 + MESSAGES_ADDR + 1, string_buffer[2]);
0952
for
(
byte
c = 0; c < 44; c++)
0953
{
0954
EEPROM.write(string_buffer[1] * 46 + MESSAGES_ADDR + 2 + c, string_buffer[c + 7]);
0955
if
(string_buffer[c + 7] == 0)
break
;
0956
}
0957
Serial
.print(F(
"Message "
));
0958
Serial
.print(string_buffer[1] < 10 ?
char
(string_buffer[1] +
'0'
) :
char
(string_buffer[1] - 10 +
'A'
));
0959
Serial
.println(F(
" saved"
));
0960
}
0961
else
OK = 0;
0962
}
0963
else
0964
{
0965
if
(string_buffer[2] == 0)
0966
{
0967
if
(EEPROM.read(string_buffer[1] * 46 + MESSAGES_ADDR) > 0 && EEPROM.read(string_buffer[1] * 46 + MESSAGES_ADDR) < 32 && EEPROM.read(string_buffer[1] * 46 + MESSAGES_ADDR + 1) > 0 && EEPROM.read(string_buffer[1] * 46 + MESSAGES_ADDR + 1) < 13)
0968
{
0969
string_buffer[
sizeof
(string_buffer) - 1] = string_buffer[1];
0970
for
(
byte
c = 0; c < 44; c++)
0971
{
0972
string_buffer[c] = EEPROM.read(string_buffer[
sizeof
(string_buffer) - 1] * 46 + MESSAGES_ADDR + 2 + c);
0973
if
(string_buffer[c] == 0)
break
;
0974
}
0975
StringToSprite(string_buffer);
0976
ScrollBufferToScreen(1);
0977
StringToSprite(
"\xA9<\xAD>\xB5"
);
0978
Show(1);
0979
}
0980
else
0981
{
0982
Serial
.print(F(
"Message "
));
0983
Serial
.print(string_buffer[1] < 10 ?
char
(string_buffer[1] +
'0'
) :
char
(string_buffer[1] - 10 +
'A'
));
0984
Serial
.println(F(
" not set"
));
0985
}
0986
}
0987
else
0988
{
0989
if
(string_buffer[2] ==
'-'
)
0990
{
0991
EEPROM.write(string_buffer[1] * 46 + MESSAGES_ADDR, 0);
0992
Serial
.print(F(
"Message "
));
0993
Serial
.print(string_buffer[1] < 10 ?
char
(string_buffer[1] +
'0'
) :
char
(string_buffer[1] - 10 +
'A'
));
0994
Serial
.println(F(
" deleted"
));
0995
}
0996
else
OK = 0;
0997
}
0998
}
0999
}
1000
else
OK = 0;
1001
}
1002
break
;
1003
}
1004
default
: OK = 0;
1005
}
1006
Serial
.println(OK ? F(
"OK\n"
) : F(
"Error\n"
));
1007
}
1008
}
1009
ButtonPressed();
1010
}
1011
//==============================================================================================
1012
void
setup
()
1013
{
1014
Wire.begin();
1015
RTC.begin();
1016
Dallas.begin();
1017
dallasOK = Dallas.getDeviceCount();
1018
bme.begin();
1019
Serial
.begin(57600);
1020
for
(
byte
i = 0; i < 4; i++)
1021
{
1022
lc.shutdown(i,
false
);
1023
lc.clearDisplay(i);
1024
}
1025
SetBrightness();
1026
pinMode(DOWN_PIN, INPUT);
1027
pinMode(UP_PIN, INPUT);
1028
pinMode(OK_PIN, INPUT);
1029
pinMode(BEEPER_PIN, OUTPUT);
1030
#ifdef DS1307
1031
if
(!RTC.isrunning())
1032
{
1033
SetupTime(); SetupDate();
1034
}
1035
#else
1036
if
(RTC.lostPower())
1037
{
1038
SetupTime(); SetupDate();
1039
}
1040
#endif
1041
if
(dallasOK)
1042
{
1043
Dallas.requestTemperatures();
1044
t_min = Dallas.getTempCByIndex(0);
1045
t_max = t_min;
1046
NOW = RTC.now();
1047
t_min_h = NOW.hour();
1048
t_min_m = NOW.minute();
1049
t_max_h = t_min_h;
1050
t_max_m = t_min_m;
1051
}
1052
1053
int
i = 0;
1054
while
(i < 256)
1055
{
1056
if
(EEPROM.read(i) == 255)
1057
{
1058
pressure_addr = i;
1059
break
;
1060
}
1061
i++;
1062
}
1063
}
1064
//==============================================================================================
1065
void
loop
()
1066
{
1067
unsigned
long
current_millis = millis();
1068
DisplayTime(5, 0);
1069
boolean flag_blink = 1;
1070
if
(!beeper) beeper = AlarmNotActive();
1071
unsigned
long
time_previous_millis = millis();
1072
while
((millis() - time_previous_millis < TIME_SHOW_MSEC && digitalRead(UP_PIN) && digitalRead(DOWN_PIN)) || (beeper && !AlarmNotActive()))
1073
{
1074
SetBrightness();
1075
if
((millis() - time_previous_millis) % 2000 < 1000)
1076
{
1077
if
(!flag_blink)
1078
{
1079
lc.setRow(1, 7, B01100110);
1080
lc.setRow(2, 0, B01100110);
1081
flag_blink = 1;
1082
if
(!AlarmNotActive() && beeper) digitalWrite(BEEPER_PIN, 1);
1083
}
1084
}
1085
else
1086
{
1087
if
(flag_blink)
1088
{
1089
lc.setRow(1, 7, 0);
1090
lc.setRow(2, 0, 0);
1091
screen_buffer[15] = 0;
1092
screen_buffer[16] = 0;
1093
flag_blink = 0;
1094
NOW = RTC.now();
1095
if
(MINUTE_OLD != NOW.minute())
1096
DisplayTime(1 + (MINUTE_OLD / 10 != NOW.minute() / 10) + (HOUR_OLD % 10 != NOW.hour() % 10) + (HOUR_OLD / 10 != NOW.hour() / 10), 1);
1097
digitalWrite(BEEPER_PIN, 0);
1098
}
1099
}
1100
1101
if
(beeper && (!digitalRead(OK_PIN) || !digitalRead(UP_PIN) || !digitalRead(DOWN_PIN)) && !AlarmNotActive())
1102
{
1103
beeper = 0;
1104
ButtonPressed();
1105
}
1106
1107
// +++++ Настройки +++++
1108
if
(!digitalRead(OK_PIN))
1109
{
1110
ButtonPressed();
1111
StringToSprite(
"\xA9\xAC\xA7\xB5"
);
1112
ScrollVertical(0, 31, 1);
1113
for
(
byte
i = 0; i < 32; i++) screen_buffer[i] = 0;
1114
byte
pos_menu = 0;
1115
while
(pos_menu < 4)
1116
{
1117
Blink(pos_menu);
1118
if
(!digitalRead(UP_PIN))
1119
{
1120
ButtonPressed();
1121
pos_menu++;
1122
}
1123
if
(!digitalRead(DOWN_PIN))
1124
{
1125
ButtonPressed();
1126
pos_menu--;
1127
}
1128
if
(!digitalRead(OK_PIN))
1129
{
1130
ButtonPressed();
1131
SetBrightness();
1132
switch
(pos_menu)
1133
{
1134
case
0: { SetupTime();
break
; }
1135
case
1: { SetupDate();
break
; }
1136
case
2: { SetupAlarms();
break
; }
1137
case
3: { SerialSetup();
break
; }
1138
}
1139
}
1140
StringToSprite(
"\xA9\xAC\xA7\xB5"
);
1141
Show(1);
1142
}
1143
SetBrightness();
1144
DisplayTime(5, 0);
1145
time_previous_millis = millis();
1146
}
1147
}
1148
digitalWrite(BEEPER_PIN, 0);
1149
1150
// +++++ Дата +++++
1151
if
(AlarmNotActive() || !beeper)
1152
{
1153
StringToSprite(
" "
, 28);
1154
ScrollVertical(0, 31, 0);
1155
strcpy_P(string_buffer, (
char
*)pgm_read_word(&(dow[NOW.dayOfTheWeek()])));
1156
StringToSprite(string_buffer);
1157
ScrollBufferToScreen(0);
1158
StringToSprite(
" "
, 0);
1159
ScrollBufferToScreen(0);
1160
if
(NOW.day() > 9)
1161
{
1162
string_buffer[0] = NOW.day() / 10 +
'0'
;
1163
string_buffer[1] = NOW.day() % 10 +
'0'
;
1164
string_buffer[2] =
'\0'
;
1165
}
1166
else
1167
{
1168
string_buffer[0] = NOW.day() +
'0'
;
1169
string_buffer[1] =
'\0'
;
1170
}
1171
StringToSprite(string_buffer);
1172
ScrollBufferToScreen(0);
1173
StringToSprite(
" \xA0"
);
1174
ScrollBufferToScreen(0);
1175
strcpy_P(string_buffer, (
char
*)pgm_read_word(&(months[NOW.month() - 1])));
1176
StringToSprite(string_buffer);
1177
ScrollBufferToScreen(0);
1178
string_buffer[0] =
' '
;
1179
string_buffer[1] =
'2'
;
1180
string_buffer[2] =
'0'
;
1181
string_buffer[3] = (NOW.year() - 2000) / 10 +
'0'
;
1182
string_buffer[4] = (NOW.year() - 2000) % 10 +
'0'
;
1183
string_buffer[5] =
'\0'
;
1184
StringToSprite(string_buffer);
1185
ScrollBufferToScreen(0);
1186
for
(
byte
i = 0; i <= strlen_P(yyyy); i++)
1187
string_buffer[i] = pgm_read_byte_near(yyyy + i);
1188
StringToSprite(string_buffer);
1189
ScrollBufferToScreen(1);
1190
}
1191
1192
// +++++ Вывод сообщений +++++
1193
if
(AlarmNotActive() || !beeper)
1194
{
1195
// отсчет до НГ
1196
if
(NOW.month() == 12 && NOW.day() > 20)
1197
{
1198
DateTime NY (NOW.year() + 1, 1, 1, 0, 0, 0);
1199
unsigned
long
difference = NY.unixtime() - NOW.unixtime();
1200
byte
difference_hour = difference / 3600;
1201
byte
difference_min = difference / 60 % 60;
1202
byte
difference_sec = difference % 60;
1203
if
(NOW.day() == 31)
1204
{
1205
if
(!difference_hour && !difference_min) ShowCountdown(difference_sec, 9);
1206
else
1207
{
1208
if
(difference_hour)
1209
{
1210
ShowCountdown(difference_hour, 3);
1211
if
(difference_min)
1212
{
1213
StringToSprite(
" \xA0\xA0"
);
1214
ScrollBufferToScreen(0);
1215
}
1216
}
1217
if
(difference_min) ShowCountdown(difference_min, 6);
1218
}
1219
}
1220
else
ShowCountdown(31 - NOW.day(), 0);
1221
for
(
byte
i = 0; i <= strlen_P(message_UNY); i++)
1222
string_buffer[i] = pgm_read_byte_near(message_UNY + i);
1223
StringToSprite(string_buffer);
1224
ScrollBufferToScreen(1);
1225
}
1226
// С Новым годом!
1227
if
(NOW.day() == 1 && NOW.month() == 1)
1228
{
1229
for
(
byte
i = 0; i <= strlen_P(message_HNY); i++)
1230
string_buffer[i] = pgm_read_byte_near(message_HNY + i);
1231
StringToSprite(string_buffer);
1232
ScrollBufferToScreen(1);
1233
}
1234
// Пользовательские сообщения из EEPROM
1235
boolean mes = 0;
1236
for
(
byte
i = 0; i < 16 && AlarmNotActive(); i++)
1237
{
1238
if
(NOW.day() == EEPROM.read(i * 46 + MESSAGES_ADDR) && NOW.month() == EEPROM.read(i * 46 + MESSAGES_ADDR + 1))
1239
{
1240
mes = 1;
1241
for
(
byte
c = 0; c < 44; c++)
1242
{
1243
string_buffer[c] = EEPROM.read(i * 46 + MESSAGES_ADDR + 2 + c);
1244
if
(string_buffer[c] == 0)
break
;
1245
}
1246
StringToSprite(string_buffer);
1247
ScrollBufferToScreen(0);
1248
StringToSprite(
" \xA0\xA0"
);
1249
ScrollBufferToScreen(0);
1250
}
1251
}
1252
if
(mes)
1253
{
1254
StringToSprite(
" "
, 0);
1255
ScrollBufferToScreen(1);
1256
}
1257
}
1258
1259
// +++++ Уличная температура +++++
1260
if
(AlarmNotActive() || !beeper)
1261
{
1262
StringToSprite(
"\xA0\xA6\xA0\xBB"
);
1263
for
(
byte
i = 0; i < 8; i++)
1264
{
1265
ScrollVerticalOneRow(0, 6, 1);
1266
ScrollVerticalOneRow(7, 31, 0);
1267
Show(0);
1268
}
1269
if
(dallasOK)
1270
{
1271
Dallas.requestTemperatures();
1272
float
temperature = Dallas.getTempCByIndex(0);
1273
TempToString(temperature);
1274
StringToSprite(string_buffer);
1275
SpriteToCenterScreen();
1276
delay(1000);
1277
if
(NOW.hour() < t_min_h || NOW.hour() < t_max_h)
1278
{
1279
t_min = temperature;
1280
t_max = temperature;
1281
t_min_h = NOW.hour();
1282
t_min_m = NOW.minute();
1283
t_max_h = t_min_h;
1284
t_max_m = t_min_m;
1285
}
1286
else
1287
{
1288
if
(t_min > temperature)
1289
{
1290
t_min = temperature;
1291
t_min_h = NOW.hour();
1292
t_min_m = NOW.minute();
1293
}
1294
if
(t_max < temperature)
1295
{
1296
t_max = temperature;
1297
t_max_h = NOW.hour();
1298
t_max_m = NOW.minute();
1299
}
1300
}
1301
Tminmax(0);
1302
Tminmax(1);
1303
}
1304
else
1305
{
1306
delay(700);
1307
StringToSprite(
"???°C"
);
1308
SpriteToCenterScreen();
1309
delay(1000);
1310
}
1311
}
1312
// +++++ Температура в помещении +++++
1313
1314
StringToSprite(
"\xA0\xA6\xA0\xA0\xAB"
);
1315
for
(
byte
i = 0; i < 8; i++)
1316
{
1317
ScrollVerticalOneRow(0, 6, 0);
1318
ScrollVerticalOneRow(7, 31, 1);
1319
Show(0);
1320
}
1321
delay(300);
1322
TempToString(bme.readTemperature());
1323
StringToSprite(string_buffer);
1324
SpriteToCenterScreen();
1325
delay(1000);
1326
1327
1328
// +++++ Влажность в помещении +++++
1329
1330
HumToString(bme.readHumidity());
1331
StringToSprite(string_buffer);
1332
for
(
byte
i = 0; i < 8; i++)
1333
{
1334
ScrollVerticalOneRow(0, 6, 1);
1335
ScrollVerticalOneRow(7, 31, 0);
1336
Show(0);
1337
}
1338
delay(1500);
1339
1340
// +++++ Давление +++++
1341
static
unsigned
long
pressure_previous_millis;
1342
if
(current_millis - pressure_previous_millis >= PRESSURE_UPDATE_MSEC)
1343
{
1344
pressure_previous_millis = current_millis;
1345
EEPROM.write(pressure_addr++, (0.51 + bme.readPressure() * 760.0 / 101325.0) - PRESSURE_VALUE_SHIFT);
1346
EEPROM.write(pressure_addr, 255);
1347
}
1348
StringToSprite(
"\xAE\xA0mmHg"
);
1349
ScrollVertical(0, 31, 0);
1350
delay(500);
1351
PresToString(0.51 + bme.readPressure() * 760.0 / 101325.0);
1352
StringToSprite(string_buffer);
1353
ScrollVertical(9, 31, 1);
1354
delay(1000);
1355
float
scale = 1.0;
// масштаб графика (для большого разброса)
1356
byte
shift = 0;
// сдвиг к середине (для малого разброса)
1357
byte
value = EEPROM.read(
byte
(pressure_addr - 1));
1358
byte
pressure_min = value;
1359
byte
pressure_max = value;
1360
for
(
byte
i = 2; i < 24; i++)
1361
{
1362
value = EEPROM.read(
byte
(pressure_addr - i));
1363
if
(pressure_min > value) pressure_min = value;
1364
if
(pressure_max < value && value != 255) pressure_max = value;
1365
}
1366
byte
pressure_range = pressure_max - pressure_min + 1;
1367
if
(pressure_range > 8)
1368
{
1369
scale = 8.0 / pressure_range;
1370
shift = 0;
1371
}
1372
else
1373
{
1374
scale = 1.0;
1375
shift = 4 - (pressure_range / 2);
1376
}
1377
for
(
byte
i = 1; i < 24; i++)
1378
{
1379
value = EEPROM.read(
byte
(pressure_addr - i));
1380
if
(value != 255)
1381
{
1382
byte
bar = scale * (value - pressure_min);
1383
sprite_buffer[32 - i] = 255 << (7 - bar - shift);
1384
}
1385
else
sprite_buffer[32 - i] = i % 2 ? B00010000 : 0;
1386
}
1387
ScrollVertical(9, 31, 1);
1388
for
(
byte
i = 0; i < 32; i++) sprite_buffer[i] = 0;
1389
delay(1200);
1390
1391
// +++++ Проверка батарейки RTC +++++
1392
if
(AlarmNotActive() || !beeper)
1393
{
1394
analogReference(INTERNAL);
for
(
byte
i = 0; i < 4; i++) { analogRead(BATT_PIN); delay(20); }
1395
float
Vbatt = analogRead(BATT_PIN) * Vref * voltage_divider_coefficient / 1023.0;
1396
analogReference(DEFAULT);
for
(
byte
i = 0; i < 4; i++) { analogRead(SENSOR_PIN); delay(20); }
1397
if
(Vbatt <= 2.3 || !digitalRead(OK_PIN) || !digitalRead(UP_PIN) || !digitalRead(DOWN_PIN))
1398
{
1399
for
(
byte
i = 0; i < 4; i++) string_buffer[i] =
' '
;
1400
string_buffer[4] =
'\xA0'
; string_buffer[5] =
'\xA0'
;
1401
byte
v = Vbatt * 10;
1402
string_buffer[6] = v / 10 +
'0'
;
1403
string_buffer[7] =
','
;
1404
string_buffer[8] = v % 10 +
'0'
;
1405
string_buffer[9] =
'V'
;
1406
string_buffer[10] =
'\0'
;
1407
StringToSprite(string_buffer);
1408
sprite_buffer[1] = B00111110;
1409
for
(
byte
i = 2; i < 10; i++) sprite_buffer[i] = B00100010;
1410
sprite_buffer[10] = B00110110;
1411
sprite_buffer[11] = B00011100;
1412
ScrollVertical(0, 31, 1);
1413
time_previous_millis = millis();
1414
while
(millis() - time_previous_millis < 6000)
1415
{
1416
if
(Vbatt > 2.3)
1417
for
(
byte
i = 2; i <= map(constrain(v, 23, 36), 23, 36, 3, 10); i++)
1418
lc.setRow(i / 8, i % 8, B00111110);
1419
else
1420
{
1421
if
((millis() % 2000 < 1000) == flag_blink)
1422
{
1423
lc.setRow(0, 2, flag_blink ? B00100010 : B00111110);
1424
lc.setRow(0, 3, flag_blink ? B00100010 : B00111110);
1425
flag_blink = !flag_blink;
1426
}
1427
}
1428
SetBrightness();
1429
}
1430
}
1431
ScrollVertical(0, 31, 0);
1432
}
1433
}
1434
//==============================================================================================
Сам датчик с использованной вами библиотекой работает?
Кто может помочь? Выкинул sht, пытаюсь втиснуть bme280, в результате везде нули... ЧЯДНТ? куда копать?
Вы офигели? Думаете кто-то станет разбираться, что вы там изменили в 1400 строчках?
Кто ж сразу новое оборудование в огромную программу пихает? Надо было для начала написать проверочный скетч для датчика, короткий, строк на 15-20. Убедится, что все работает. Или, если не работает - искать ошибку.. Или спросить на форуме -со скетчем в 15 строк и форум бы выстрее помог.
Блин.Я не фигел.
Одним подавай кусок кода, другим подавай весь код.Всем не угодишь. Кому то лень написать что то не унизительное?
И да, еси чо, я проверял датчик, загружал скетч. Татчик опрашивается и показывает значения в мониторе последовательного порта. Или вы думаете, что настолько руки обьектно ориентированы?
Конечно работает. Проверял.Подозреваю, что ошибка кроется где то в внесении данных в буфер и выводе их на экран.
Дайте ссылку на используемую вами библиотеку Adafruit_BME280.
Всем спасибо за помощь. Скетч рабочий. Единственное, что изменил: указал адрес инициализации bme - bme.begin (0x76). Заменил ардуино и скомпилировал на другой машине.
Можно использовать в качестве замены при использовани bme280 вместо dht и sht.
Подскажите для BMP180(280) питния 5 вольт не много? По даташиту у них максимум 4,25 вольта....
Питание для БМП/бме идеально 3.3 вольта. Если юзаем нано-берем с ноги стабилизатора,если про мини-с амс117-3.3