Arduino управление реле скетч

Библиотека для управления реле на Ардуино. 7 программ работы реле без delay().

Библиотека предназначена для управления любыми устройствами основанными на изменении состояния входа: реле, светодиоды, пьезоэлектрические источники звука и т.д. В библиотеке реализовано 7 программ управления реле:

  • включить реле
  • выключить реле
  • включить реле на время
  • выключить реле на время
  • мигать по маске с заданной длительностью импульса
  • пищать при использовании пьезоэлектрического источника звука по маске с заданной длительностью импульса и частотой
  • переключить реле

Все программы использующие временные задержки реализованы с помощью моей библиотеки Timer без использования функции delay(), ссылка нее будет внизу страницы.

При подключении библиотеки в скетче появляется возможность создавать объекты класса Relay. Каждый созданный объект по-сути является самостоятельным реле. Номера программ для управления реле следующие:

Для создания экземпляров класса используется 4 конструктора.
Самый простой принимает всего 2 аргумента:

Данный конструктор подходит для программ 0, 2 и 6.
Конструктор для программ 1 и 3 имеет следующий вид:

Для мигания по маске, программа 4, используем следующий конструктор:

Для того чтобы извлекать звуки из пассивной пьезопищалки с помощью программы 5, используем конструктор с самым большим числом параметров:

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

Не считая сеттеров и геттеров класс содержит следующие доступные методы:

Обратите внимание, что тип возвращаемого значения метода getState() — тип данных ENUM, с именем relayState. Я использовал его для того, чтобы код был более читабельным.

Обратиться к данным значениям из скетча можно через оператор доступа ::
Пример:

Теперь о том, как создавать маску для мигания реле или для баззера.

ВНИМАНИЕ! «воспроизведение» идет справа налево и крайним левым значением в вашей маске должна быть единица!

Для примера будем использовать сигнал «SOS». Как известно, данный сигнал передается следующим образом «…—…». Методом setInterval() или через конструктор мы задаем длительность одного импульса. Сделаем так, чтобы точки и паузы были по 1 импульсу, а тире и паузы между буквами по 2. Получаем в бинарной последовательности следующую строку: 1010100110110110010101. Теперь добавим паузу в 4 импульса для паузы в передаче. Вот что получилось: 10101001101101100101010000. Далее, не забывая что у нас длина маски 32 разряда (т.е. все что до левой единицы забывается нулями), делим на квартеты и переводим в 16тиричную систему:
0000.0010.1010.0110.1101.1001.0101.0000 = 0x02A6D950
Если у вас возникают сложности — воспользуйтесь конвертером, коих в сети достаточно.
Вот, собственно мы и получили маску для сигнала SOS, которую мы передаем в конструкторе или устанавливаем с помощью метода setPattern().

Ниже приведен тестовый скетч для управления реле в ардуино. В нем мы создаем 4 реле под разные программы и управляем ими через интерфейс RS-232 (com port).

Внимание! С программой 5 (баззер) одновременно может работать только одно реле (один пин). Если вы создадите несколько таких реле — запускайте их по очереди. Так же для ардуино УНО лучше не использовать для этих целей ШИМ выходы : 3 и 11 пины.

На этом все. Пользуйтесь на здоровье.
Извините, в настоящее время нет доступных опросов.
Связанные статьи:
Ардуино. Задержка без delay() с помощью millis(). Библиотека Timer.

Источник

Ардуино: модуль реле

Мы уже знаем как управлять слабым светодиодом и даже мощным двигателем с помощью Ардуино. Но как быть, если мы задумаем управлять устройствами, подключенными к бытовой сети? Напомню, что даже небольшая настольная лампа питается от источника переменного тока с напряжением 220 Вольт. Обычный полевой транзистор, который мы использовали в схеме с двигателем уже не подойдет.

Чтобы управлять мощной нагрузкой да еще и с переменным током воспользуемся реле. Это такое электромеханическое устройство, которое механическим способом замыкает цепь нагрузки с помощью электромагнита. Посмотрим на внутренности:

Принцип действия реле следующий. Подаем напряжение на электромагнитную катушку. В катушке возникает поле, которое притягивает металлическую лапку. В свою очередь, лапка механически замыкает контакты нагрузки.

У реле есть два основных применения. Во-первых, мы можем подав всего 5 Вольт на катушку, замкнуть цепь очень мощной нагрузки. Например, реле, используемое в уроках для Ардуино, может включить свет в доме или отключить забытый утюг. Во-вторых, некоторые виды реле могут одновременно замкнуть и разомкнуть сразу несколько разных цепей с разным напряжением.

Подключение реле к Ардуино

На этом уроке мы будем работать не с отдельным реле, а с целым релейным модулем. Помимо самого реле, модуль содержит еще и оптоэлектронную развязку с транзистором, которые защищают выводы Ардуино от скачков напряжения на катушке.

У одинарного модуля реле есть всего три контакта. Подключим их по следующей схеме.

Реле GND VCC In
Ардуино Уно GND +5V 3

Кстати, вход реле является инвертированным. Это означает, что высокий уровень на контакте In выключит катушку реле, а низкий уровень — включит.

Принципиальная схема

Внешний вид макета

Программа для Ардуино

Напишем простую программу, которая будет включать лампу на 3 секунды, а затем гасить на 1 секунду.

Загружаем программу на Ардуино. Теперь подключаем питание к лампе и к реле. Наконец, подаем питание на контроллер.

Автоматический светильник или уличный фонарь

С помощью контроллера, реле и датчика света можно сделать несложный автоматический светильник. Контроллер будет зажигать лампу в момент, когда уровень света на датчике станет меньше заданного значения.

В качестве датчика используем готовый модуль на основе фоторезистора. Подключим все три устройства по следующей схеме.

Принципиальная схема

Внешний вид макета

Программа автоматического светильника

Аналоговый вывод датчика дает значения в диапазоне от 0 до 1023. Причем, 0 — для максимального уровня света и 1023 для полной темноты.

Сначала нам нужно определиться при каком уровне света включать лампу, а при каком выключать. В нашей лаборатории при свете дня датчик показывает значение L = 120, а ночью около L = 700. Будем включать реле при L > 600, и выключать при L

Ардуино: модуль реле : 8 комментариев

А какой резистор преобразует напряжение в 3 вольта?

Источник

Урок 8 — Подключаем реле к Arduino. Пример работы и скетч

Подключить реле к Arduino достаточно просто. Для примера мы будем использовать Скетч и подключения из урока: Урок2. Нажатие кнопки без ложных срабатываний.Устраняем дребезг кнопки

В схеме вместо светодиода с резистором подключим реле. Вот так выглядит схема подключения реле к Arduino UNO . К другим версиям например Arduino NANO схема не будет иметь отличий.

Как видим, схема не многим отключается от исходного примера.

Реле может управлять различными бытовыми приборами.

Пара фоток сделанных при снятии видео по данному уроку: Подключение реле к Arduino.

Скетч можно взять из Урок 2. Нажатие кнопки без ложных срабатываний. Устраняем дребезг кнопки без изменений.

Для более красивого и читабельного кода заменим переменную ledPin на relayPin . Так же заменим вспомогательную переменную ledOn на relayOn. У нас получиться вот такой скетч управления реле.

Вы должны понимать, что управлять реле можно и буз Arduino . Данный пример приведен для ознакомления.

Если подключить реле через кнопку с фиксацией . Вот по такой схеме.

То у нас все будет работать отлично. В качестве источника питания 5В можно использовать MICRO USB адаптер 5pin, при подключении от компьютера или адаптера. Так же можно подключить через понижающий трансформатор, например вот такой.

Вывод: Урок показывает как можно с помощью Arduino упровлять реле. Но в простых схемах управления реле использовать платформу Arduino или другой микроконтроллер не целесообразно.

Подписывайтесь на мой канал на Youtube и вступайте в группы в Вконтакте и Facebook.

Спасибо за внимание!

Понравилась статья? Поделитесь ею с друзьями:

Источник

Arduino и реле

Описание

Электромагнитное реле – универсальный способ коммутировать нагрузку. Универсальность в том, что реле имеет чисто механический контакт, то есть физически замыкает контакты. Это позволяет коммутировать нагрузку как переменного, так и постоянного тока в широком диапазоне напряжений: от 0 до сетевого, то есть 220 Вольт. По току производитель обещает 10 А, то есть можно коммутировать например 2 кВт обогреватель. Само реле напрямую к микроконтроллеру подключать нельзя, поэтому для управления силовая схема развязывается с логической, соответственно китайцы выпускают несколько типов модулей реле:

В наборе идёт красный модуль с настройкой логического уровня (жёлтый джампер-перемычка между буквами H и L). В центре – самый дешёвый модуль с минимальной обвязкой, высокого уровня. И справа – тоже неплохой модуль, но низкого уровня, что не всегда удобно использовать. Примечание: реле высокого уровня переключается при высоком сигнале на логический вход, а низкого – низком. Все модули реле имеют три пина на одном конце и три на другом:

Слева находятся пины питания и управления самого реле:

  • VCC (DC+, +) – питание
  • GND (DC-, -) – “земля”
  • IN (S) – логический управляющий сигнал

Справа находятся выходы самого реле, это одна контактная группа с переключением:

  • COM (Common) – общий контакт
  • NO (Normal Open) – нормально разомкнутый относительно COM контакт
  • NC (Normal Close) – нормально замкнутый относительно COM контакт

Работает это следующим образом: само реле (синяя коробочка на плате) питается от VCC и GND и подключается на питание схемы, так как реле потребляет около 60 мА при переключении. Но управляется реле логическим сигналом от микроконтроллера, который подаётся на пин IN. На выходе реле наблюдается следующая картина: у неактивного реле замкнуты контакты COM и NC. При активации реле контакт переключается и COM замыкается с NO.

Реле высокого уровня будет включаться и потреблять ток при подаче высокого сигнала (5, 3.3V), а низкого – при подаче низкого (GND, 0V). Чисто логически удобнее использовать реле высокого уровня: подали высокий сигнал – реле включилось. Мы кстати разбирали реле вот в этом уроке. И вот в этом:

Подключение

Примеры

Для активации реле достаточно подать высокий сигнал (для реле из набора) на логический вход. Для примера и проверки подойдёт и классический пример “мигания светодиодом”:

Источник

Программируемое реле на Ардуино

Идея банальна, понадобился контроллер для управления нагрузкой в доме:
1. Котел отопления.
2. Накопительный бойлер для водоснабжения.
3. Насос в скважине.

Читал массу увлекательных статей на тему ХХ на Ардуино, читая которые четко фиксировал в голове мысль «хочу Ардуино». Прикинув стоимость компонентов и готовых решений, посчитал явную выгоду от внедрения Ардуино.

Итак, программа минимум:

1. 4 реле, часы (RTC), ЖК экран;
2. Режимы работы каждого реле: включено, выключено, суточный таймер, одноразовое включение;
3. Кнопки управления для настройки времени и режимов реле;

В доме установлен двухтарифный счетчик, поэтому бойлер нагревает воду с 23 до 7 утра. Аналогично отопление: два из трех тэнов, по моей задумке будут включаться ночью. Управление температурой пока остается родное на штатном пульте. Одноразовое включение в качестве резерва пойдет на насос, программируем включение, например, на набор емкости или прокачку скважины, после чего реле переходит в режим выключено. Основная особенность: изготовлено законченное устройство, управляемое кнопками, и не требующее подключения к ПК.

Конечно, хотелось в перспективе все повесить на контроллер, так как для отопления целесообразно сделать 3 режима работы: день с 7 до 23 в целях экономии, ночь, разогрев к утреннему отключению с 5..6 до 7. Но пока реализована программа минимум.

Аппаратная часть:

При изготовлении была задача получить как можно более дешевое изделие, поэтому максимально присутствует колхоз. На Али были заказаны стартовый комплект для arduino Uno R3, 4 релейный модуль, жк-экран I2C 20*4, часы RTC DS1307 I2C, цифровой датчик температуры и влажности Dht21.

Поскольку все это видел первый раз пришлось осваивать. Общие понятия почерпнул с помощью гугла из:
http://habrahabr.ru/company/masterkit/blog/257747/
http://arduino.ru/Reference

Красивую схему подключения сделать не могу, не в чем. Во Fritzing к примеру, из компонентов только сам микроконтроллер.

Подключение реле и кнопок проблем не вызвало, единственно включил подтягивающие резисторы. Это есть в руководстве. В подключении ЖК экрана помогла ссылка https://arduino-info.wikispaces.com/LCD-Blue-I2C#v3. Потребовалось регулировка подстроечным резистором, «из коробки» экран не горел совсем, чем вызвал у меня легкое замешательство.

Часы потребовали только батарейку, подключил по типовой схеме http://zelectro.cc/RTC_DS1307_arduino

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

Подключение нескольких кнопок к аналоговому входу описано по ссылке http://arduino.net.ua/Arduino_articles/Arduino_proekty/Podkljuchenie%20knopok%20k%20odnomu%20analogovomu%20vhodu/, там же в комментариях описано как включить подтягивающие резисторы «pinMode (A2, INPUT_PULLUP);»

Управление классическое, «мониторное»: кнопки «меню», «+»,»-«, «set».

Взял монтажный щиток на 6 автоматов:

Поставил монтажные стойки под модули:

Прикрутил реле, часы, контроллер:

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

Блок питания взял от какого-то роутера Dlink, 5В 2А, ломать голову не стал запаял прямо на него USB провод:

Вырезал из пластика панель для крепления экрана:

Установил экран. Закрепил монтажными стойками, под клавиатурой — винт. Стойки подобраны по высоте с расчетом, что в них будет упираться крышка щитка, придавая жесткость конструкции. Втулка на блоке реле предотвращает продавливание платы вниз при нажатии кнопок.

Кнопки изначально планировал подключить к цифровым входам, но внезапно нашел модуль клавиатуры от монитора, который подошел как родной (схема кнопок от монитора).

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

Фото готового устройства:

Мигающий светодиод также присутствует.

В данный момент реле висит «на соплях», управляет бойлером, окончательный монтаж будет произведен после установки проводки и контакторов для котла отопления. Фазу с колодки тоже надо убрать, конечно, при монтаже проводки. Сейчас некогда, надо делать наружные работы по дому. Затраты на детали составили около 2 тысяч рублей.

Программная часть:

Программная часть далась нелегко: 90% времени ушло на написание меню, годный код удалось осилить только с третьей версией прошивки.

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

Второй подход был переводом кода на принципы ООП. За основу был взят определенный класс TMenu, от которого наследовались непосредственно элементы меню.

Вкратце. Указателю CurrentMenu присваивается адрес текущего элемента меню Основные элементы класса это бит ItemIsValue, который определяет является ли текущий элемент подменю или изменяемым значением и функции OnKey(), Increment(), Decrement() и Print(). Также класс меню содержит указатель на родительское меню и массив указателей. В общем использование наследования позволяло сделать произвольное многоуровневое меню, в принципе можно сказать, что это динамическое меню, только в в данной реализации оно формируется один раз при инициализации. Во всяком случае код легко редактируется, добавляются элементы меню. Жестокая реальность поставила меня на место. В UNO R3 на всю эту роскошь не хватает памяти.

Третий подход — урезка второго. Главное отличие одно — конкретный объект класса меню содержит либо вложенные меню, либо переменные — редактируемые значения, тип которых задан классом.

Итак, Определен класс:

Класс содержит:
— число элементов меню (подменю или переменная), указатель на родительское меню (если указатель равен 0, то достигнут верх);
MenuName имя меню;
ItemIsValue описан выше
— номер позиции курсора в меню (CurrentItem);
— указатель на массив указателей Items. Адреса подменю. Если меню содержит редактируемые элементы, это значение равно 0;
— функция Print() вызывается из цикла loop от имени текущего меню «CurrentMenu->Print();» таким образом отрисовывается экран с нужным текстом.
— функция OnKey(byte KeyNum) также вызывается из цикла loop в блоке подавления дребезга контактов, он же декодер клавиатуры от монитора.
— функции ChangeItem(byte value), virtual void Increment(void), virtual void Decrement(void) вызываются из OnKey() и обрабатывают кнопки «+» и «-«. ChangeItem() — это переборка элементов меню, Increment() и Decrement() — полиморфные, переборка значений текущей переменной.
— функция CheckDateTime(DateTime OldDate, int Increment, byte DatePart) проверяет введенную дату и время. Распознается вискозный год и количество дней в месяце 28/29, 30, 31. Исходя из логики в функцию передается текущая дата, +1 или -1 и индекс части даты/времени (0 — год, 5 — секунды)

Навигация по меню реализована присвоением адреса объекта указателю CurrentMenu:
— CurrentMenu = CurrentMenu->Items[CurrentMenu->CurrentItem]; вход в выбранное меню
— CurrentMenu = CurrentMenu->Parent; переход в предыдущее меню

Логика работы:

Цикл loop непрерывно опрашивает клавиатуру, проверяет настройки реле и мигает светодиодом.

Клавиатура опрашивается в качестве рудимента и по цифровым входам 2-6 (menu,-,+,set), к этим кодам пересчитываются значения аналоговых портов.
— при нажатии на кнопку «menu» вне меню происходит вызов меню, в противном случае переход на меню вверх;
— при нажатии «+» или «-» происходит циклическая переборка элементов меню или циклическое изменение текущего параметра. При нажатии кнопки «‘set» вход в выбранное меню либо сохранение значения переменной во флеш с одновременным выбором следующего значения.

Дребезг подавляется программно, каждой кнопке присваивается счетчик нажатия и отпускания, который увеличивается в случае нажатия или отпускания. Опрос проводится 3 раза с интервалом 15 мс. Счетчик нажатия или отпускания увеличивается на 1 либо сбрасывается. Таким образом распознается дребезг как нажатия так и отпускания. Состояние отпускания фиксируется для однократного срабатывания при удержании кнопки.

В настройках реле проверяется режим работы, в режиме «Daily» вводится и проверяется только время, с точностью до минут. Правильно распознается время включения больше времени выключения, например, включение в 23 и выключение в 7. В режиме «Оnce» задается дата и время. Для удобства настройки планирую подключить пятую кнопку и задать на нее функцию установки текущей даты и времени в режиме редактирования.

Это вкратце. Небольшие функции классов объявлены, как правило при объявлении класса, заголовочные файлы и библиотеки не используются. Код и так небольшой.

#include
#include
#include

#include
#define LEFT 0
#define CENTER 1
#define RIGHT 2

#define RelayModesCount 4
#define KeyFirst 2
#define KeyLast 6

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
RTC_DS1307 RTC; // RTC Modul
DHT dht(7, DHT21); // pin, type
volatile boolean Blinker = true;
volatile long BlinkerTime;
volatile byte ButtonPress[8];
const String RelayModeNames[] = <«OFF», «ON», «Once», «Daily»>;

int aKey1 = 0;
int aKey2 = 0;

boolean DoBlink(void)
<
boolean Result = false;
long NBlinkerTime = millis();
if (Blinker)
<
if (NBlinkerTime — BlinkerTime > 200)
<
digitalWrite(8, HIGH);
BlinkerTime = NBlinkerTime;
Blinker = false;
Result = true;
>
>
else
<
if (NBlinkerTime — BlinkerTime > 300 )
<
digitalWrite(8, LOW);
BlinkerTime = NBlinkerTime;
Blinker = true;
>

>
return Result;
>
String BlinkString(String string, byte Cur, byte ItemsCount)
<
String result = string;
byte len = string.length();
if (!Blinker && Cur == ItemsCount)
<
for (byte i = 0; i 1000) <
OldDateTime = TmpDateTime;
*SetDateTime = *SetDateTime + 1;
>;
>;
>;
class TRelayMenu: public TMenu
<
public:
byte RelayNumber;
byte RelayMode;
// byte Shedule=0;
boolean OnceBit;
DateTime RelayOn;
DateTime RelayOff;
TRelayMenu(TMenu *ParentMenu, byte NewNumber, String NewName) <
MenuName = new String(NewName);
CurrentItem = 0; _ItemsCount = 11; Parent = ParentMenu; Items = 0; ItemsName = 0; ItemIsValue = true, OnceBit = false;
RelayNumber = NewNumber;
RelayMode = 0;
RelayOn = DateTime(2015, 1, 1, 23, 00, 00);
RelayOff = DateTime(2015, 1, 1, 07, 00, 00);
>;
void Print(void);
void Increment(void) <
if (!CurrentItem) <
RelayMode++;
if ( RelayMode >= RelayModesCount) RelayMode = 0;
>
else if (CurrentItem 127) RelayMode = RelayModesCount — 1;
>
else if (CurrentItem AddItem(TimeMenu);

byte p_address;
DateTime DTFlesh;
for (int i = 0; i AddItem(RelayMenu[i]);

p_address = i * 16;

DTFlesh = DateTime(int(EEPROM.read(p_address + 1) + 2000), EEPROM.read(p_address + 2), EEPROM.read(p_address + 3), EEPROM.read(p_address + 4), EEPROM.read(p_address + 5), 0 );
RelayMenu[i]->RelayOn = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);

DTFlesh = DateTime(int(EEPROM.read(p_address + 6) + 2000), EEPROM.read(p_address + 7), EEPROM.read(p_address + 8), EEPROM.read(p_address + 9), EEPROM.read(p_address + 10), 0 );
RelayMenu[i]->RelayOff = RelayMenu[i]->CheckDateTime(DTFlesh, 0, 0);
>

void LcdPrint(byte string, String str, byte Align)
<
byte StrTrim1;
byte StrTrim2;
lcd.setCursor(0, string); //Start at character 0 on line 0
switch (Align)
<
case RIGHT:

case CENTER:
StrTrim1 = byte((20 — str.length()) / 2);
StrTrim2 = 20 — str.length() — StrTrim1;
for (byte k = 0; k RelayMode] + » R2-» + RelayModeNames[RelayMenu[1]->RelayMode];
LcdPrint(0, Ddate, CENTER);
Ddate = » R3-» + RelayModeNames[RelayMenu[2]->RelayMode] + » R4-» + RelayModeNames[RelayMenu[3]->RelayMode];
LcdPrint(1, Ddate, CENTER);
Ddate = String (NowDate.year()) + «/» + String(NowDate.month()) + «/» + String(NowDate.day()) + » » + String (NowDate.hour()) + «:» + String(NowDate.minute()) + «:» + String(NowDate.second());
LcdPrint(2, Ddate, CENTER);
Ddate = «Temp » + String (int(dht.readTemperature())) + «C, Hum » + String(int(dht.readHumidity())) + «%»;
LcdPrint(3, Ddate, CENTER);

void TTimeMenu::Print(void)
<
SecondTimer();
String Ddate = BlinkString(String((*SetDateTime).year()), CurrentItem, 0) + «/» +
BlinkString(String( (*SetDateTime).month()), CurrentItem, 1) + «/» +
BlinkString(String((*SetDateTime).day()), CurrentItem, 2) + » «;
LcdPrint(1, Ddate, CENTER);
Ddate = BlinkString(String ((*SetDateTime).hour()), CurrentItem, 3) + «:» +
BlinkString(String((*SetDateTime).minute()), CurrentItem, 4) + «:» +
BlinkString(String((*SetDateTime).second()), CurrentItem, 5);
LcdPrint(2, Ddate, CENTER);

LcdPrint(3, » «, CENTER);
RelayCheck();
>

void TMenu::OnKey(byte KeyNum)
<
switch (KeyNum)
<
case 3: // — if (ItemIsValue) Decrement();
else ChangeItem(-1);
break;
case 4: // +
if (ItemIsValue) Increment();
else ChangeItem(1);
break;
case 5: // SET
if (ItemIsValue)
<
OnSet();
ChangeItem(+1);
>
else // вход в подменю
<
if (Items && ItemsCount())
<
if (CurrentMenu->ItemsCount())
<
CurrentMenu = CurrentMenu->Items[CurrentMenu->CurrentItem];
CurrentMenu->CurrentItem = 0;
>
>
>
break;
default: // 2 -menu
if (Parent) CurrentMenu = CurrentMenu->Parent; //(TMenu *) &NoMenu;
else
<
CurrentMenu = SelectMenu;
CurrentMenu->CurrentItem = 0;
>
>
>

void TMenu::ChangeItem(byte value)
<
CurrentItem += value;
if (CurrentItem > 128) CurrentItem = ItemsCount() — 1;
else if (CurrentItem > ItemsCount() — 1) CurrentItem = 0;
>

boolean TMenu::AddItem(TMenu *NewItem)
<
if (!Items) Items = new TMenu *[_ItemsCount = 1];
else Items = (TMenu **)realloc((void *)Items, (_ItemsCount = _ItemsCount + 1) * sizeof(void *));
Items[_ItemsCount — 1] = NewItem;
>

DateTime TMenu::CheckDateTime(DateTime OldDate, int Increment, byte DatePart)
<
int DTmin[6] = <2000, 1, 1, 0, 0, 0>;
int DTmax[6] = <2199, 12, 31, 23, 59, 59>;

int DT[6];
int diff;

DT[0] = OldDate.year();
DT[1] = OldDate.month();
DT[2] = OldDate.day();
DT[3] = OldDate.hour();
DT[4] = OldDate.minute();
DT[5] = OldDate.second();
DT[DatePart] = DT[DatePart] + Increment;

if (DT[1] == 1 || DT[1] == 3 || DT[1] == 5 || DT[1] == 7 || DT[1] == 8 || DT[1] == 10 || DT[1] == 12) DTmax[2] = 31;
else if (DT[1] == 2)
<
if ((DT[0] % 4 == 0 && DT[0] % 100 != 0) || (DT[0] % 400 == 0)) DTmax[2] = 29;
else DTmax[2] = 28;
>
else DTmax[2] = 30;

for (byte i = 0; i DTmax[i]) DT[i] = DTmin[i];
else if (DT[i] 3) shift = CurrentItem — 3;
for (byte i = 0; i > » + * (Items[i + shift]->MenuName) + » MenuName), CENTER);
>
RelayCheck();
>

String DData;
NowDate = RTC.now();
LcdPrint(0, (*MenuName) + «[» + BlinkString(RelayModeNames[RelayMode], CurrentItem, 0) + «]», CENTER);
DData = «On:»;
switch (RelayMode)
<
case 3: //Daily
// DData = DData + » «;
if (CurrentItem > 0 && CurrentItem 5 && CurrentItem TimeOff )
<
if (NowTime = TimeOn ) result = true;
else result = false;
>
else
<
if (NowTime = TimeOn ) result = true;
else result = false;
>;
return result;

void RelayCheck (void)
<
boolean OnceBitCheck;
for (byte i = 0; i RelayMode)
<
case 1: //relay 0n
digitalWrite(i + 10, LOW);

break;
case 2: //Once;
OnceBitCheck = (NowDate.unixtime() > RelayMenu[i]->RelayOn.unixtime() && NowDate.unixtime() RelayOff.unixtime());

if (OnceBitCheck) RelayMenu[i]->OnceBit = true;
else if (RelayMenu[i]->OnceBit)
<
RelayMenu[i]->RelayMode = 0;
byte p_address = RelayMenu[i]->RelayNumber * 16;
EEPROM.write(p_address, RelayMenu[i]->RelayMode);
>
digitalWrite(i + 10, !OnceBitCheck);
break;
case 3: //Daily
digitalWrite(i + 10, !(RelayMenu[i]->CheckDaily()));
break;
default: //relay 0ff
digitalWrite(i + 10, HIGH);
>
>
>

Вот такая получилась поделка, избавившая меня от необходимости вставать в 7 утра и ложиться в 23, при этом не забывая щелкать тумблерами. На промышленные стандарты не претендую, инкапсуляцию данных в коде делать не стал, глобальные переменные также оставил.

Были опасения в точности хода часов, но пока существенного отклонения не заметил.

Источник

Adblock
detector