Arduino таймер

Добрый день. Меня зовут Никита Сергеевич, мне 14 лет и в этом посте я имею желание рассказать вам о разработанном мною пол года назад устройстве (и приложении), потому что готовое устройство спаял и собрал мой отец. Хотя возможно такое устройство вы уже видели не раз, но мне это не мешает.

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





Готовое и собранное устройство может подать на указанный цифровой пин arduino 1 или 0 в период от и до указанного времени в точности до минут (вне периода подается значение противоположное указанному в приложении при добавлении таймера ).

Все параметры указываются в приложении. А вот отсюда поподробнее…

Есть приложение для android в котором необходимо подключиться к блютус модулю и добавить таймер. Приложение интуитивно понятное и думаю проблем с ним не возникнет.





.apk файл будет в папке этого проекта.

Необходимые элементы:

  1. arduino;
  2. rtc module ds1307;
  3. bluetooth module HC-05;
  4. соединительные элементы(например провода);
  5. прошивка для arduino; скетч на мой взгляд сложный и лучше в подробности не вдаваться.
  6. приложение для android;

Разбираемся с arduino и подключаемыми модулями.

Ага, пункты 1-4:



arduino - hc-05
         5v - vcc
      gnd - gnd
      TX1 - RXD
      RX0 - TXD

arduino - ds1307
         5v - 5v
      gnd - gnd
        A5 - scl
        A4 - sda

Не забываем при загрузке скетча отключать пин RX0 на arduino. Вы сказали «скетч»?

5.Скетч в студию:

#include <Wire.h>                                            //библиотека для работы с шиной i2c
#include <iarduino_RTC.h>                                    //библиотека для rtc модуля(если cчто, лежит в папке проекта(Timer->firmware_for_timer->iarduino_RTC))     
#include <EEPROM.h>                                          //библиотека для работы с энергонезависимой памятью

iarduino_RTC time(RTC_DS1307);                               //создание объекта для работы с модулем реального времени

int values;                                                  //переменная для получения данных

unsigned int to_minutes(unsigned int hours, unsigned int minutes)//функция для перевода часов и минут в минуты
{
  return (60*hours)+minutes;
}

void setup()
{
  time.begin();                                             //начало работы часов
  Serial.begin(9600);                                       //открытие сериал порта
 
}

void loop()
{
  if(Serial.available() > 0)                                //если что-то пришло
  {
    values = Serial.read();
    time.settime(0,-1, values);                             //считывание и установка часов
    delay(50);
    values = Serial.read();
    time.settime(0, values);                                //считывание и установка минут
    delay(50);

    //очищаем энергонезависимую память
    for (int i = 0 ; i < EEPROM.length() ; i++)
    {
      EEPROM.write(i, 0);
    }
    //////////////////////////////////
    
    values = Serial.read();                                 
    delay(50);
    
    //запись данных в энергонезависимую память, полученных с телефона
    while (values > 0)                                        //пока есть что получать
    {
      for(int i = 0; i < 7; ++i)
      {
        EEPROM.write(EEPROM.read(EEPROM.length() - 1) * 7 + i, Serial.read());
        delay(50);
      }

      EEPROM.write(EEPROM.length() - 1, EEPROM.read(EEPROM.length() - 1) + 1);

      values = Serial.read();
      delay(50);
    }
    /////////////////////////////////////////
  }

  //проход по каждому таймеру
  for(int i = 0; i < EEPROM.read(EEPROM.length() - 1); ++i)
  {
    if(EEPROM.read(i * 7 + 0) == 1)                                                                               //если таймер нужно проверять
    {
      bool find = 0;                                                                                              //флаг
      time.gettime();
      if((to_minutes(EEPROM.read(i * 7 + 1), EEPROM.read(i * 7 + 2)) <= to_minutes(time.Hours, time.minutes)) && //если пришло время для работы
         (to_minutes(EEPROM.read(i * 7 + 3), EEPROM.read(i * 7 + 4)) > to_minutes(time.Hours, time.minutes)))
      {
        pinMode(EEPROM.read(i * 7 + 5), OUTPUT);                                                                  //настраиваем пин таймера как выход
        digitalWrite(EEPROM.read(i * 7 + 5), EEPROM.read(i * 7 + 6));                                             //посылаем на пин нужное значение
      }                           
      else                                                                                                        //иначе если время не пришло
      {
        //ищем таймер с таким же пином
        for (int j = 0; j < EEPROM.read(EEPROM.length() - 1); ++j)
        {
          if(EEPROM.read(i * 7 + 5) == EEPROM.read(j * 7 + 5) && (i != j) && (EEPROM.read(j * 7 + 0) == 1))
          {
            //и если нашли таймер с таким же пином и если для него время пришло
            if((to_minutes(EEPROM.read(j * 7 + 1), EEPROM.read(j * 7 + 2)) <= to_minutes(time.Hours, time.minutes)) &&
               (to_minutes(EEPROM.read(j * 7 + 3), EEPROM.read(j * 7 + 4)) > to_minutes(time.Hours, time.minutes))) //если пришло время для работы
            {
              pinMode(EEPROM.read(i * 7 + 5), OUTPUT);                                                             //настраиваем пин таймера как выход
              digitalWrite(EEPROM.read(i * 7 + 5), EEPROM.read(j * 7 + 6));                                        //посылаем на пин нужное значение
              find = 1;                                                                                            //поднимаем флаг
            }
          }
        }

        if(find == 0)                                                                                              //если таймер с таким же пином не найден
        {
          pinMode(EEPROM.read(i * 7 + 5), OUTPUT);                                                                 //настраиваем пин таймера как выход
          digitalWrite(EEPROM.read(i * 7 + 5), !EEPROM.read(i * 7 + 6));                                           //посылаем на пин значение противоположное нужному
        }
      }
    }
  }
}

Но все это без приложения будет холодным и неподвижным как камень, поэтому идем дальше.

6.
Приложение интуитивно понятное и думаю проблем с ним не возникнет.
Но лучше разобраться сразу. При первом входе в приложение необходимо будет подключиться к блютус модулю, для этого нажимаем «синхронизировать устройство»
и выбираем наш модуль. При галочке «подключаться автоматически» телефон сам будет пытаться подключиться к блютус модулю, при открытии приложения(эту фишку взял у alex gyver).«таймеры» здесь список всех таймеров и их поиск по имени. При нажатии на имя таймера открывается экран изменения этого таймера. Здесь же(где список таймеров) в правом нижнем углу расположен "+" нажав на который открывается экран добавления таймера, где указывается:

  • его имя,
  • от какого времени(часы минуты),
  • до какого времени(часы минуты),
  • управляемый пин,
  • значение для него
  • и состояние(будет arduino включать его или не будет в нужное время).


Архив проекта;
Там же приложение.

На этом хочу поблагодарить за внимание и сказать что, если нашли какие-то косяки или баги — смело пишите об этом, будем исправлять.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 82

    0
    Как куры отнеслись к данному нововведению в их жизни? :)

    P.S. Никита Сергеевич, для вашего развития, могу порекомендовать к начальному прочтению пару книг по некоторому срезу понимания программирования.
    ЛЕО БРОУДИ «СПОСОБ МЫШЛЕНИЯ — Ф О Р Т ЯЗЫК И ФИЛОСОФИЯ ДЛЯ РЕШЕНИЯ ЗАДАЧ»
    Л.Броуди «Начальный курс программирования на языке Форт»

    Сам же начинал понимние идей заложенных в Форт дизайн языка с С.Н.БАРАНОВ Н.Р. НОЗДРУНОВ «ЯЗЫК ФОРТ И ЕГО РЕАЛИЗАЦИИ»

    Одна из популярных Форт-систем для AVR amForth, но для этого и других контроллеров есть и другие Форт системы.

    P.S. Здесь подборка другой Форт литературы
    а здесь Рускоязычный Форт-форум (активен с 2006г)

    Forth Haiku — «Развлекалочка» по мотивам Форт языка
      +4
      И зачем тут Форт? Для «автоматизации курятника» Питон имхо куда больше пригодится ;)
        +1
        Сказано же, для развития «бренной» души.
        А, Вы его пробовали понять?

        P.S. Здесь В Online книги Броуди по основам языка Форт (сейчас, правда, актуален стандарт 94г) приводится пример с сортировкой куринных яиц по размеру. :)
          +8
          О развитии души можно на пенсии думать, а в 14 лет учить стоит то, что реально пригодится ;)

          Top 10 languages to learn 2018:
          image

          Хотя список и немного спорный имхо, но Форта там по-любому нет.
            –4
            На пенсии уже поздно думать о душе (лучше заранее) :)

            Изучая «попсу», можно не пoлучить необходимые результаты по времени.
            Есть люди, которые смотрят на тренды, а есть кто выбирает свой путь и следует ему. :)
            P.S. Здесь Форт по версии EEE на 43-м текущем месте (был на 39), но об нём ещё не забыли
            Хотя деньги, конечно, платит энтерпрайз и менеджеры от него.

            Что из этого списка Вам действительно было полезно и Вы использовали в своей работе?
              –5
              Посмотрите это. Может узнаете что-то новое.
                +9
                Это хорошо, мне с моим С++ в ближайшие годы можно не ожидать молодых, мотивированных конкурентов со слабыми амбициями по зарплате!
                  +1

                  А их тут точно десять?

                    0
                    В 14 лет надо учить то, что нравится. И смотреть вокруг, чтобы иметь перспективу.

                    Потом такой роскоши уже не будет.

                    А учить то, что нужно вот прям сейчас, — так оно уже через 5 лет никому не нужно будет.
                    0

                    В применении к бытовой автоматике более интересна поддержка железа. К ардуине подключить термометр по i2c — несколько строчек кода, например. Если использовать С++. Как это будет выглядеть на forth?

                      +1
                      В применении к I2C в amForth
                      библиотека поддержки выглядит так

                      P.S. А, здесь, один из примеров её применения в репозитории кода
                      Ничего сложного, если понимать синтаксис и семантику Форт языка.
                        +2

                        Понятно, что раз программа может запускаться на микроконтроллере, и есть доступ к его регистрам — все можно написать. Но в случае С++ и ардуины всё уже написано, и оно под рукой. А ардуино + forth это закат солнца вручную. Искать решения на давно забытых форумах (последний пост в 2008 году) и на покойной rapidshare? Да и в чем профит от натягивания виртуальной стековой машины на процессор с регистрами тоже не совсем понятно.

                          +1
                          Есть много профита в изучении немейнстримновых концепций и языков — это сильно расширяет кругозор и весьма полезно практически. Иногда весьма с неожиданной стороны — например зная форт и немножко линала типичный джаваскриптер сможет наваять фортоподобный domain specific language на wasm для того чтобы крутить трехмерные модели на вебсайте заказчика без привлечения тяжеловесных emscripten и плюсовых библиотек.

                          Работать это будет быстрее. И будет иметь преимущество в переносимости и скорости написания по сравнению с чистым wasm. Еще одним из преимуществ является то, что форт реально красив с точки зрения элегантности технических решений — в процесс изучения можно случайно получить море удовольствия

                          Изучая только то что изучают другие вы вступаете в очень невыгодную для себя конкуренцию, по возможности избегайте этого.
                            0
                            Согласен
                              +1
                              Но, Форт некоторым разработчикам, почему то, как «кость в горле»
                              и пытаются заминусовать мои сообщения в данном треде и «поправить» карму. :)
                                0
                                Любое сообщество защищает себя от т.н. еретиков, это часто проще чем попытататься извлечь из еретических идей полезное для себя.
                        +4

                        Надо переименоваться в HHaskell и начать пиарить понятно что.

                          0

                          А IIdris — это будет уже следующий шаг?

                    +2
                    Таймеры для управления светом, это хорошо… Но не хватает привязки к восходу/заходу солнца.
                    Пару лет назад решал эту задачу, по этому позволю себе попиариться. Может и вам пригодится: github
                        0

                        Forth и arduino — странная комбинация.

                          +1
                          Программирование в стиле Ардуино (без изучения архитектурных особенностей контроллеров), ещё более странная вещь, но имеющая право на существование.
                            0

                            Программирование на любом языке высокого уровня не требует знания архитектурных особенностей железа. Это норма. Даже на С можно писать, не задумываясь о том, RISC или CISC платформа будет выполнять этот код.
                            А по поводу странного — можно просто сравнить количество проектов под Atmega на С, С++ и forth ;) Например, на Хабре. Или на примере объяснить, почему скетч из этой статьи на forth будет выглядеть лучше чем на С++.

                              +1
                              Сделать что то боле менее серьезное на микроконтроллере (тем более слабеньком) без знания архитектуры ИМХО практически невозможно.
                                0

                                Таймер для курятника — достаточно серьезный проект? ;)

                                  0
                                  Я как то делал таймер для курятника с режимом плавный рассвет закат, ШИМ, дисплей на динамической индикации, термостат, охранка, вентиляция, куча настроек и т.д. Это конечно не очень серьезно но тем не менее вполне себе в районе 1200 строк. Восьмая мега под завязку.
                            +1
                            Что же странного? Forth как раз изначально и разработан для контроллеров.
                              0

                              А потом что-то пошло не так и С оказалось удобнее.

                                0
                                Ничего не шло «не так», просто на С написали UNIX, который стал killer application потому что был переносим на разные архитектуры с меньшими усилиями. Это привело к скачку популярности — не потому что форт хуже чем си, а потому что рабочий метод популяризовать что-то — это облегчить людям жизнь. Популярность вовлекает контрибьюторов и язык развивается безотносительно того насколько он был хорош или плох на старте. Мое личное мнение — форт очень интересен, во время его изучения мне было куда интереснее, чем когда я изучал Си.
                          +4
                          Начинание хорошее, устройство полезное. Никита Сергеевич, так держать :)

                          Но на схеме видна только Ардуино, RTC и Bluetooth. А как собственно свет-то управляется — реле, транзистор, тиристор? И непонятен вопрос питания и электробезопасности — для устройства, работающего от сети, еще и в потенциально сырой среде, это важно.

                          Если уж управлять светом, то нужен датчик освещенности, чтобы не просто по таймеру его включать, а тогда когда он реально нужен. Ну и термодатчик тогда уж добавить — если в курятнике жарко/холодно, можно посылать уведомление (реальный случай, недавно в одном большом хозяйстве 2000 цыплят сдохли от жары +40).
                            +2
                            Отец попросил сделать «мозги» устройства. Все остальное он сделал сам. А насчет температуры и освещенности то такие задачи передо мною не стаяли. А так я думаю это не очень сложно организовать. Для полного комфорта можно и кондиционер запилить)))))))).
                              +6
                              Понятно, но раз уж выложены фото устройства и код, лучше иметь полную схему, для тех кто захочет повторить.

                              Пожелания по улучшению кода:

                              — продумать логику хранения переменных, например глобальная переменная value не нужна, ее нужно объявить там, где она реально используется, это облегчает поддержку и понимание кода.

                              — продумать работу с EEPROM, например, возможно, не нужно очищать всю память при записи лишь нескольких значений (for (int i = 0; i < EEPROM.length(); i++)). Eeprom кстати имеет ограниченное число циклов записей.

                              — Не очень понятны строки типа EEPROM.write(EEPROM.read(EEPROM.length() — 1) * 7 + i, Serial.read()); — это по замыслу, запись в конец блока памяти? Зачем делается EEPROM.read, если только что eeprom очищалась нулями? (или это хитрый сдвиг такой?). Кстати, признак хорошего тона в программировании это как раз такие вещи писать в комментариях, это облегчает понимание кода. Также если EEPROM.length() это константа, равная объему eeprom в Arduino, то ее как раз стоило бы объявить глобальной переменной типа int eeprom_len = EEPROM.length(), это облегчило бы читаемость кода и немного его ускорило (быстрее прочитать готовую переменную, чем обращаться каждый раз заново к функции).

                              Это не придирки, а пожелания на будущее, как сделать еще лучше.
                                0
                                Да тоже хотел про EEPROM написать… Насколько, я понял… EEPROM.length() это количество таймеров. В EEPROM для каждого таймера запись это 7 байт, хотя не факт, что байт, так как там все переменные int. И наверное, задумывалось, чтобы очищался только первый байт из 7. Потом там проверка идёт, что если он равен 1, то проверить не сработал ли таймер, иначе ничего не делать. Хотя скорее всего очистка EEPROM не работает, как задумано, поскольку очищает только первые байты до количества таймеров.
                                В общем и целом, очевидно, что архитектуры и моделирования работы программы сделано не было. Т. Е., использовался метод проб и ошибок. Но это очень нормально для 14 летнего начинающего программиста.

                                В качестве улучшений, надо ещё что то сделать с протоколом передачи, одно неловкое движение(чаще передавать, большее количество значений, сбой начала сообщения, хотя его тут как такого и нет. Я понял, что это просто последовательность значений таймеров, причём ни конца ни начала сообщения явно не определяется. ) и все рухнет.
                                Ну т. Е лучше сделать параметры для каждого таймера отдельно и задавать их отдельно и тогда не надо будет всю EEPROM переписывать при каждой настройке, а только конкретный параметр.

                                С другой стороны для 14 летнего подростка похвально… да и настраивать не так часто надо. Так что EEPROM на всю жизнь хватит. Молодец!
                                  0
                                  > Насколько, я понял… EEPROM.length() это количество таймеров

                                  EEPROM это встроенный класс в Arduino www.arduino.cc/en/Reference/EEPROM, и думаю, length() возвращает объем флеш-памяти на контроллере, т.е. это всегда константа. Проверять лень :)
                                    0

                                    Да, так и есть, я скобки пропустил, получается тогда, количество таймеров лежит по адресу EEPROM.length() — 1. Вначале оно обнуляется а потом увеличивается пока данные из последовательно го порта поступают.

                                +2

                                Стоять пишется через о :)

                              0
                              Прекрасный тег и ник
                                0
                                Мне симпатичен ваш подход: осваивать новое что-то делая. Успехов!
                                На схеме не заметил проводков, по которым, собственно, управляется лампочка в курятнике.
                                Трансформатор в блоке питания — это, думаю, устаревший опыт отца. И еще: не злоупотребляйте перезаписями в флеш-память.
                                  +1
                                  Трансформатор в блоке питания — это, думаю, устаревший опыт отца.

                                  Зато — почти «железобетонный».
                                    0
                                    Зато — почти «железобетонный».

                                    Не спорю, но добавьте сюда мостик, электролиты, микросхему стабилизатора и сравните с модулем понижающего преобразователя AC-DC объемом около 3 см3 со всевозможными защитами. Совсем не очевидно, что «железобетоннее» в целом.
                                      +1
                                      но добавьте… и сравните с ...

                                      И, весьма вероятно, фэйковой надёжностью. Так-что — варианты для выбора есть.
                                        0
                                        И, весьма вероятно, фэйковой надёжностью.

                                        Делать вывод о фейковой надежности модуля на том основании, что в его схеме есть «ненадежные» электролиты — сомнительная идея.
                                        Ресурс электролитического конденсатора зависит, в частности, от соотношения между постоянной, переменной (пульсацией) составляющими напряжения на конденсаторе и его номинальным напряжением.
                                        И если разработчик в официальной спецификации приводит величину надежности
                                        (MTBF 100000h), то — эта цифра обоснована.
                                        Другое дело — китайская реализация модуля, впрочем, как и всего остального…
                                  +8
                                  Крутизна, в 14 лет уже программы для микроконтроллеров пишете.
                                  Я ничего не соображаю в электронике, но есть у меня пара советов по организации кода. Организация кода даже в таком маленьком проекте очень важна, программу будет проще понять и даже вы сами когда захотите добавить тот же датчик температуры через полгода, быстрее поймете что же там как работает.
                                  Итак, во-первых и самое главное, в программе мало названий, относящихся к предметной области (управлению устройствами по таймерам), все названия очень асбтрактные и относятся к платформе (values, dititalWrite, EEPROM и т.п.). Нет даже ни одного названия timer. Из-за этого логика работы плохо понятна, даже в такой небольшой программе.
                                  iarduino_RTC time(RTC_DS1307);  

                                  Лучше назвать эту переменную clock. На это кстати даже намекает название класса RTC (Real Time Clock)
                                  int values; 

                                  Эта переменная используется только внутри функции loop, там её лучше и объявить. Глобальные переменные плохи тем, что их значение может меняться где угодно в программе, из-за этого разные функции оказываются слишком сильно связанны между собой, через глобальную переменную.
                                  Кроме того, название во множественном числе values предполагает массив значений, а тут оно только одно, лучше value или data
                                  Но в целом эта переменная вообще не нужна, ниже будет видно почему
                                  unsigned int to_minutes(unsigned int hours, unsigned int minutes)//функция для перевода часов и минут в минуты
                                  {
                                    return (60*hours)+minutes;
                                  }

                                  Вот например хорошая функция, все понятно что она делает благодаря названиям переменных и самой функции. Ну а коментарий тут вообще ненужен, он ничего нового не объясняет, все итак понятно из кода
                                  if(Serial.available() > 0)                                //если что-то пришло

                                  Опятьже, такие коментарии объясняющие очевидное только увеличивают размер текста необходимый для прочтения и не несут полезной информации
                                  Функция loop и делает слишком много работы, и устанавливает настройки с телефона в энергонезависимую память, и включает/выключает устройства по таймерам. Лучше разбить её на две, а лучше три или четыре
                                  Например
                                  
                                  void storeTimers()
                                  {
                                    for (int i = 0 ; i < EEPROM.length() ; i++)
                                      EEPROM.write(i, 0);
                                    unsigned int timers = 0;
                                    while (Serial.read() > 0) {                                       //пока есть что получать
                                      delay(50);
                                      for(int i = 0; i < 7; ++i) {
                                        EEPROM.write(timers * 7 + i, Serial.read());
                                        delay(50);
                                      }
                                      ++timers;
                                      EEPROM.write(EEPROM.length() - 1, timers);
                                    }
                                  }
                                  

                                  Как уже правильно написали, логика записи настроек таймеров не очень понятна, скорее всего работает запись настроект только одного таймера.
                                  Далее, комментарий типа
                                  if(EEPROM.read(i * 7 + 0) == 1)                                                                               //если таймер нужно проверять
                                  

                                  он как раз и написан потому что без него вообще непонятно чего к чему. Но, если добавить функцию с подходящим названием, коментарий становится ненужен. Вот например так
                                  bool enabled(int timer)
                                  {
                                    return EEPROM.read(i * 7) == 1;
                                  }
                                  

                                  Соответственно проверка превращается в
                                  if (enabled(i))

                                  Гораздо понятнее и не требуется коментарий
                                  Далее, повторяющиеся конструкции вроде
                                  if((to_minutes(EEPROM.read(i * 7 + 1), EEPROM.read(i * 7 + 2)) <= to_minutes(time.Hours, time.minutes)) && //если пришло время для работы
                                           (to_minutes(EEPROM.read(i * 7 + 3), EEPROM.read(i * 7 + 4)) > to_minutes(time.Hours, time.minutes)))
                                  и
                                  pinMode(EEPROM.read(i * 7 + 5), OUTPUT);                                                                  //настраиваем пин таймера как выход
                                          digitalWrite(EEPROM.read(i * 7 + 5), EEPROM.read(i * 7 + 6));                                             //посылаем на пин нужное значение

                                  тоже вынесем в функции
                                  
                                  bool ready(int timer)
                                  {
                                    return (to_minutes(EEPROM.read(timer * 7 + 1), EEPROM.read(timer * 7 + 2)) <= to_minutes(clock.Hours, clock.minutes)) &&
                                           (to_minutes(EEPROM.read(timer * 7 + 3), EEPROM.read(timer * 7 + 4)) > to_minutes(clock.Hours, clock.minutes));
                                  }
                                  
                                  void set(int timer, bool invert)
                                  {
                                    pinMode(EEPROM.read(timer * 7 + 5), OUTPUT);
                                    unsigned int val = EEPROM.read(timer * 7 + 6);
                                    digitalWrite(EEPROM.read(timer * 7 + 5), invert ? !val : val);
                                  }
                                  

                                  Итого получается следующий код
                                  #include <Wire.h>                                            
                                  #include <iarduino_RTC.h>                                    
                                  #include <EEPROM.h>                                          
                                  
                                  iarduino_RTC clock(RTC_DS1307);
                                  
                                  unsigned int to_minutes(unsigned int hours, unsigned int minutes)
                                  {
                                    return (60*hours)+minutes;
                                  }
                                  
                                  void setup()
                                  {
                                    time.begin();
                                    Serial.begin(9600);
                                  }
                                  
                                  // читает текущее время из последовательного порта
                                  void storeTime()
                                  {
                                    clock.settime(0, -1, Serial.read());
                                    delay(50);
                                    clock.settime(0, Serial.read());
                                  }
                                  
                                  // читает настройки таймеров из последовательного порта и сохраняет в энергонезависимой памяти
                                  void storeTimers()
                                  {
                                    for (int i = 0 ; i < EEPROM.length() ; i++)
                                      EEPROM.write(i, 0);
                                    unsigned int timers = 0;
                                    while (Serial.read() > 0) {
                                      delay(50);
                                      for(int i = 0; i < 7; ++i) {
                                        EEPROM.write(timers * 7 + i, Serial.read());
                                        delay(50);
                                      }
                                      ++timers;
                                      EEPROM.write(EEPROM.length() - 1, timers);
                                    }
                                  }
                                  
                                  bool enabled(int timer)
                                  {
                                    return EEPROM.read(timer * 7) == 1;
                                  }
                                  
                                  bool ready(int timer)
                                  {
                                    return (to_minutes(EEPROM.read(timer * 7 + 1), EEPROM.read(timer * 7 + 2)) <= to_minutes(clock.Hours, clock.minutes)) &&
                                           (to_minutes(EEPROM.read(timer * 7 + 3), EEPROM.read(timer * 7 + 4)) > to_minutes(clock.Hours, clock.minutes));
                                  }
                                  
                                  void set(int timer, bool invert)
                                  {
                                    pinMode(EEPROM.read(timer * 7 + 5), OUTPUT);
                                    unsigned int val = EEPROM.read(timer * 7 + 6);
                                    digitalWrite(EEPROM.read(timer * 7 + 5), invert ? !val : val);
                                  }
                                  
                                  void loop()
                                  {
                                    if(Serial.available() > 0) {
                                      storeTime();
                                      storeTimers();
                                    }
                                  
                                    //проход по каждому таймеру
                                    int timers = EEPROM.read(EEPROM.length() - 1);
                                    for(int timer = 0; timer < timers; ++timer) {
                                      if(enabled(timer)) {
                                        clock.gettime();
                                        if(ready(timer))
                                          set(timer, false);
                                        else {
                                          bool found = false;
                                          //ищем таймер с таким же пином
                                          for (int t = 0; t < timers && !found; ++t) {
                                            if ((t != timer) && enabled(t) && ready(t) &&
                                               EEPROM.read(timer * 7 + 5) == EEPROM.read(t * 7 + 5)) {
                                              set(t, false)
                                              found = true;
                                            }
                                          }
                                          if(!found)
                                            set(timer, true);
                                        }
                                      }
                                    }
                                  }

                                  Примерно так. Такой код намного легче понять и в нем не требуются коментарии, потому что все функции маленькие и имеют названия из предметной области. Надеюсь будет полезно, удачи.
                                  PS: Имя, ник и теги огонь
                                    +1

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


                                    Автору же хотелось бы ещё посоветовать, если есть желание заниматься электроникой и дальше, отходить от fritzing и потихоньку осваивать полноценные принципиальные схемы — они тоже куда читабельнее и понятнее в роли документации к проекту :-)

                                      0
                                      В архиве проекта есть. Можете скачать и посмотреть.
                                        0

                                        Если есть, тогда вообще отлично :-)


                                        Говоря про архив проекта — попробуйте использовать Github или Bitbucket. Так большему числу людей будет удобнее видеть код (например, я сейчас на работе и скачивание с яндекса заблокировано). Плюсом также — вся история изменений в проекте (если что-то сломалось или стало работать не так, можно найти, из-за чего), возможность вести список задач и проблем, собирать багрепорты, получать улучшения и доработки от других в виде пулл-реквестов.

                                      0
                                      Как вариант. Особенно если мы бы хотели сэкономить количество чтений EEPROM. Но с точки зрения упаковки всех настроек таймера в struct вообщем неважно есть там чтения пачки байт или нет, можно также int-ами читать, это все равно будет скрыто в функции чтения.
                                        +1

                                        К счастью чтения-то экономить не надо :-)

                                    0
                                    Главное что поставленную задачу прибор выполняет, но не проще ли было делать на
                                    ESP32? Там уже блютус встроен, плюс можно было поставить модуль камеры, датчик температуры, а в приложении настроит получение фотоотчета.
                                      +3

                                      Предлагаю дальнейшее развитие. Курам для увеличения яйценоскости увеличивают световой день и таймер для этого — хорошая штука. Но при этом хорошо бы и поставить себя на место если и не курицы, то хотя бы петуха — резкое отключение света — стресс. У меня в курятник заходят по мере захода солнца и не все сразу, а сильно по очереди. При этом садятся на насест пока видят. С учетом этой физиологической особенности (ака куриная слепота) хорошо бы сделать плавное гашение света в течении длительного времени, от 15 до 30 минут. Включение тоже было бы неплохо плавным, но не обязательно таким длительным, а, к примеру, в течении трех минут

                                        0

                                        Тут уже вопрос к силовой части, которая в проект не вошла. Если там просто реле, то особо яркостью не порулить.

                                          +1
                                          С помощью реле вполне себе можно рулить яркостью. Через ШИМ(Широтно-импульсная модуляция ). Только, чтобы это не напоминало трещотку, нужно твердотельное реле или диммирование через мосфет-транзистор. Вполне себе получается. Я себе сделал подобие часов с функцией «рассвет» ко времени будильника. Работает как с лампами накаливания, так и со светодиодами. Именно таким способом регулируется яркость всех светодиодных устройств.
                                            0
                                            А если за реле стоит светодиодная лапма на 220В?
                                              0
                                              Ответ все тот же. Твердотельное реле способно коммутировать до 40А при 220В (это чуть меньше 10КВт в максимуме). Мосфет-транзисторы чуть поменьше, но ватт 300 берут без проблем (с прикрученным радиатором на транзисторе).
                                              Ради эксперимента делал диммер для светодиодной лампы на цоколе Е27. Конструкция работает безупречно, разве что дороговата для простого диммера и размерами великовата).
                                                0
                                                Да, я забыл, с диммируемыми лампами должно работать.
                                                  0
                                                  Это работает с большинством ламп. В том-то и дело, что у меня — внешний диммер, не ограниченный размерами и схемотехникой. А в большинстве диммеров, которые встраиваются в подразетники, стоит обычный переменный резистор, и вот с ними светодиодные лампы не работают (кроме тех, которые поддерживают диммирование).
                                                    0
                                                    Спасибо, не знал подобных подробностей.
                                                      0

                                                      Не совсем переменник там. Переменник там бы очень дико грелся и не очень долго работал :-)
                                                      Там стоит тиристор и компаратор, который при нарастании напряжения по модулю выше какой-то точки отключает выход. То есть получаем на выходе не синусоиду, а как бы её огрызок.
                                                      Так как средней светодиодной лампе с её импульсником на входе до чисто активной нагрузки как пешком до Китая, то получаем полный набор спецэффектов от нерегулируемости и до мигания как накуренный стробоскоп на дискотеке.
                                                      Зато таким диммером, оставшимся после ремонта, вполне себе можно регулировать старый советский паяльник ватт на 40-60 — только термометр прикрутить, и колхозная паяльная станция готова :-)

                                                        0
                                                        Таки не во всех !) у меня дома в диммере стоит обычный переменный резистор с выключением (мощность самого резистора не помню, давно разбирал). Ограничение нагрузки (согласно надписи) — 150Вт. Вот и вся конструкция.
                                                          0
                                                          И оба заблуждаются (ну, или опечатываются).

                                                          Там стоит тиристор и компаратор, который при нарастании напряжения по модулю выше какой-то точки отключает выход.

                                                          Включает выход. Т.к. тиристор (симистор) — проще включить, чем выключить. Выключение делается автоматически, за счёт перехода сети через ноль.

                                                          … у меня дома в диммере стоит обычный переменный резистор… Ограничение нагрузки (согласно надписи) — 150Вт.

                                                          Не может быть потому, что для ограничения мощности на нагрузке до 75 Вт — на резисторе придётся сжечь сравнимую мощность.
                                            0
                                            Курам для увеличения яйценоскости увеличивают световой день ...

                                            Уточню — для увеличения производительности кур сутки в помещениях курятников птицефабрик без естественного освещения делят на два «световых дня». В результате на выходе — два яйца вместо одного.
                                            Продолжительность жизни курицы при таком режиме (0,5 года) — не в счет.
                                            Извините за повтор — не там разместил пост.
                                              0
                                              Курам для увеличения яйценоскости увеличивают световой день ...

                                              Уточню — для увеличения производительности кур сутки в помещениях курятников птицефабрик без естественного освещения делят на два «световых дня». В результате на выходе — два яйца вместо одного.
                                              Продолжительность жизни курицы при таком режиме (0,5 года) — не в счет.
                                              Извините за повтор — не там разместил пост.
                                              0
                                              Если вдаваться в подробности выращивания птиц, то лучше всего сделать плавное включение и отключение света (минут за 10). Тогда они меньше пугаются и лучше ведут себя по другим показателям. На птицефермах еще специально уменьшают «сутки» путем увеличения включений/отключений света.
                                                0
                                                1. Судя по кишочкам на фото, arduino nano питается по Vin пину. Сколько на нее подается? 9 V? С учетом того, что с ног она еще питает HC-05 и DC1307 и вкл/выкл реле.
                                                2. Нет ли ложных срабатываний при переключении реле? У меня с этим были проблемы одно время в проекте wi-fi розетки www.youtube.com/watch?v=QAulFZaALm4
                                                3. Влияет ли использование в коде функции delay(50), которая подвешивает код, на производительность и таймер?
                                                  0
                                                  1. Везде 5 вольт.
                                                  2. Обнаружены не были.
                                                  3. Все окей.
                                                    0
                                                    Кстати, тоже заинтересовало, почему delay вместо delayMicroseconds или millis…
                                                      0
                                                      Так разница между delay и delayMicroseconds только в передаваемых величинах (миллисекунды и микросекунды соответственно). А в millis'е нужды не увидел. И к тому же мне кажется вариант с delay наиболее компактен.
                                                        0
                                                        Да, верно, маху дал с delay и delayMicroseconds. Я вариант с delay использовал только для моргания светодиодами в самом начале. Ведь delay вешает намертво систему на паузу. Такое в более-менее серьезных проектах, как мне кажется, неприемлемо. Особенно, если используются таймеры. Но это мое мнение.
                                                          0
                                                          Я делал простейшую систему с атомарными «задачами». Задаче гарантируется, что она будет запускаться с определенным интервалом. Со своей стороны задача гарантирует, что она не будет использовать функций с задержками. Если задаче нужно подождать, то она просто пропускает необходимое число циклов. Просто, эффективно, и позволяет между опросами задач отправлять в сон контроллер для снижения энергопотребления.
                                                            0
                                                            Снижение энергопотребления это круто.
                                                    0
                                                    жесть. я в 14 лет гонял в дюка3д и игрули на Спектруме. Хоть и умел программировать. молодец! )
                                                      0
                                                      1 плата wemos, и вы получаете вменяемое устройство управляемое с телефона без лишних плат, правда желателен wi-fi ;)
                                                        +1
                                                        И пропустить все танцы с бубном?
                                                          0
                                                          Там тоже без танцев не обойтись ;)
                                                          Но удобно же. Благодаря встроенному WIFI — -1 модуль.
                                                          Очень много памяти (по сравнению с ардуиной), можно, к примеру, рассчитать заранее по дням время восхода-заката солнца, и включать свет когда это действительно нужно.
                                                            0
                                                            А в чем проблема расчитывать его раз в сутки?
                                                              0
                                                              Не проблема ;). Любую задачу можно решить более чем 1 способом.
                                                              Нужно немного упороться в астрономию. Или взять готовую, уже рассчитанную таблицу. Или спросить у openweathermap…
                                                                0
                                                                Уже расчитанная таблица будет зависеть от координат спрашивающего. Да еще и от года. Проще один раз написать функцию, тут я уже давал ссылку на реализацию.
                                                                Но лично я сейчас больше предпочитаю esp8266(nodemcu). Там тоже wifi на борту.
                                                                  0
                                                                  Координаты — константа ;)
                                                                  Год… На интервале в 20 лет вряд ли набежит значительная погрешность. А через 20 лет, возможно, на месте курятника будет бассейн или небоскреб.
                                                                  Формула тоже хорошо, если она есть, и если она правильная.
                                                        0
                                                        Так понимаю, проект уже публиковался community.alexgyver.ru/threads/tajmer-na-arduino.1039 Но сила Хабра — бесконечна!
                                                        0
                                                        Работа понра. Советы по коду уже сказаны, есть пара идей по реализации. По сути проект- не более чем таймер, куры тут не причем. Если сделать более специализированное устройство, то оно может прекрасно справляться с задачей без участия человека, что больше соответствует духу автоматизации. Машина должна работать без участия человека.
                                                        Курям, нужен день продолжительностью 14ч, так что это прекрасно автоматизируется. Вынести датчик освещенности вне курятника и записывать время рассвета, при закате вычислять продолжительность дня, если меньше 14 — то включать освещение для компенсации недостатка.

                                                        Only users with full accounts can post comments. Log in, please.