Повелитель времени или очередное изобретение велосипеда


Введение.

Опять весна, набухли почки, на деревьях разумеется, а не от пива. Пора проснуться и вознести почести всемогущему богу Arduino, явить очередное чудо сотворенное с его помощью. Кроме шуток, я вообще предлагаю создать пантеон святых микроэлектроники и канонизировать Arduino как чудотворца и властителя дум.
Ну да ладно, потрепались и хватит. Если вы читали мои предыдущие статьи, то могли получить представление о моём «творчестве» и понять что уровень мой чуть выше дилетанта. Да, да, я вовсе не стесняюсь этого звания ибо таких как я — пробующих и ищущих довольно много и именно для нашей братии явился на свет Arduino — бесподобный. Время летит и уже Raspberry Pi не кажется новичкам каким то монстром, да и ESP8266 — из сопутствующего модуля для Arduino превратился в самостоятельный элемент протиснувшись даже в Arduino IDE.
Но Arduino — как первая любовь, по прежнему будоражит моё сознание, тем более их у меня в ящике лежит ещё куча, включая и тот что я выиграл на прошлой Кибервесне Это я так не умираю от скромности, ибо оказаться в такой компании призёров, для новичка это большая честь, спасибо редакции сайта за это.
И так, в один прекрасный вечер, захотелось как то обобщить все мои познания Arduino и создать нечто, что могло бы объединить в себе почти весь функционал Arduino и при этом выполнять какую то полезную функцию, последние было пожеланием жены ибо ей надоели валяющиеся по всюду проводочки и микросхемы. Идя на поводу на встречу пожеланиям домочадцев, решил, что таким полезным девайсом могут быть часы — будильник. Понимаю, на просторах интернета вы встретите огромное множество часов на базе Arduino со своими достоинствами и недостатками и тут я уж точно не буду первооткрывателем, от того и в название моей статьи я добавил — «очередное изобретение велосипеда». Но, порой всё же стоит опять изобрести велосипед, для того что бы уже окончательно убедиться в том, что лучше уже не получится или всё же может получится, что то новое и полезное, по просьбе жены.

Глава 1. Концепция.

Итак:

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

Ну как то вкратце это должно быть так.

Теперь можно подумать о компонентах:

  • Естественно, куда же без этого — сердце часов — Arduino, в конкретном случае, я использовал Arduino Nano, полностью удовлетворяющий всем моим требованиям компактности и производительности.
  • Для того чтобы мерять время, на мой взгляд, лучше ни чего не придумали как RTC модуль.
  • Для красоты отображения возмём MAX7219 Red LED Dot Matrix Display Module 4 штуки, хотя в продаже имеются и готовые модули, так что кому что нравится.

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

Теперь же, поняв о чём идёт речь, можно перейти к деталям проекта и сосредоточиться на его программной части.

Глава 2. Общение.

Прежде чем начать городить программу управления всеми вышеописанными компонентами, научим наше «сердце» — Arduino Nano как то общаться с внешним миром. Для чего? Ну, хотя бы для того чтобы, хоть как то синхронизировать наши будущие часы-будильник с нашим текущим временем, а так же каким то образом настроить сиё чудо на время для нашей побудки, т.е. будильника.
Естественно, самый простой и самый популярный способ общения с Arduino является общение по средствам сериального порта.
Не буду в этой ситуации изобретать велосипед, а процитирую себя раннего. Приглашаю всех читателей перечитать мою статью и, поскольку, задачи в проектах сходные смело взять и скопипастить код в наш нынешний проект. А именно ту часть кода которая касается:

  • управлением «внутреннего модуля», путём отсылки на него команд и получения от него ответов через сериальный порт
  • формат а также чтение и запись будильников в EEPROM Arduino Nano
  • работа с RTC модулем
  • и всё что касается анализа текущего времени на предмет наступления события — будильника

В общем то на этом сходство моих проектов и оканчивается. Теперь перейдём к основному отличию, а именно индикации текущего времени.

Глава 3. Отображение.

Ну, не долго мудрствуя, попробуем отобразить наше время на MAX7219 Red LED Dot Matrix Display Module . За основу мною была взята библиотека LedControl, хоть и довольно старая, но после небольшой обработки напильником, т.е. ручками мною переработанная в новую библиотеку под названием LedControlX, как видите отличие только в одной букве, просто, в своей библиотеке мой класс LedControlX наследовал класс LedControl, так сказать основу управления и доработал вывод символов на панель. Если кого то более подробно интерисует содержимое библиотеки LedControlX приглашаю всех в комментарии, где я с удовольствием отвечу на все вопросы бытия и тому подобного.
Научившись отображать время, добавим немного динамики в этом процессе, для примера смотри видео выше. В скетче, за отображение и анимацию у нас отвечает функция digitalClockDisplay:

void digitalClockDisplay(){
  if(millis() - previousMillis >= 1000) {
    previousMillis = millis();
    bInvert = !bInvert;

    lc.buildChar(bInvert ? ':' : ' ', 13, 0, 1, digit6x8future);

    DateTime now = rtc.now();

    strTime[0] = char(now.minute() % 10 + 48);

    if(strTime[0] != strTime_old[0]){
      strTime[1] = char(now.minute() / 10 + 48);
      strTime[2] = char(now.hour() % 10 + 48);
      strTime[3] = char(now.hour() / 10 + 48);

      for(int posY = 7; posY >= 0; posY --) {
        for(int i = 0; i < 4; i++) {
          if(strTime[i] != strTime_old[i]){
            lc.buildChar(strTime[i], iPosX[i], posY, 1, digit6x8future);
            lc.buildChar(strTime_old[i], iPosX[i], posY - 8, 1, digit6x8future);
          }
        }

        lc.Update();
        delay(50);
      }

      for(int i = 0; i < 4; i++) strTime_old[i] = strTime[i];
    }

    lc.Update();
  }
}

Тут мы раз в секунду или раз за 1000 миллисекунд, кому как приятнее, включаем и выключаем двоеточие(:) - разделитель минут и часов. Затем используя класс DateTime, проверяем произошло ли изменение единиц минут(стрёмно звучит, но иначе не скажешь) у текущего времени, если таки да, то быстренько переводим все цифры тёкшего времени(часы-десятки, часы-единицы, минуты-десятки, минуты-единицы, хотя минуты единицы мы уже перевели до этого)в символы, для отображения. Следующий шаг формирует заполнение матрицы 8x32 (у нас же 4 матрицы 8x8 расположенные в ряд)этот процесс осуществляется библиотекой LedControlX а именно её функцией buildChar, которая в качестве параметра получает значение символа, необходимого отобразить на матрице, его позицию по горизонтали, его позицию по вертикали и указатель на соответствующий фонт, которым сей символ будет отображаться. Сразу оговорюсь, фонты - это всего лишь бинарные массивы, описывающие ASCI символы и хранящиеся в файле fonts.h их не так уж и много, но достаточно для того чтобы изобразить нечто красивое на примитивной матрице 8x8 точек.

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

Функция Update библиотеки LedControlX завершает начатое и отображает всю обновлённую матрицу.

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

Теперь достаточно поместить вызов этой процедуры внутрь функции loop и почти всё часы заработали. Почти - это потому, что мы не инициализировали объект класса LedControlX, да и сам модуль RTC тоже как то обделили установкой текущего времени.

Ну что ж, заглянем в функцию setup

void setup() {
  while (!Serial) ; // wait until Arduino Serial Monitor opens

  Serial.begin(57600);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (!rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
   for(int dev = 0; dev < lc.getDeviceCount(); dev ++) {
    lc.shutdown(dev, false);
    /* Set the brightness to a medium values */
    lc.setIntensity(dev, 1);
    /* and clear the display */
    lc.clearDisplay(dev);
   }
}

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

До скорой встречи!

P.S. Привожу ссылки на репозиторий откуда вы смело можете взять исходники библиотеки LedControlX и исходник самого скетча.


6 комментариев на «“Повелитель времени или очередное изобретение велосипеда”»

  1. Здравствуйте, понравился Ваш проект собрал схему, но у меня изображение на матрицах повёрнуто на 90 градусов.
    Подскажите как можно его развернуть в Вашем скетче? (просто совсем не программист, только начинаю изучать ардуино)

    • Странно, возможно сами матрицы установлены не верно. А их порядок следования нормальный? Т.е. он правильно показывает время лишь цифры повёрнуты на 90 градусов?

    • Спасибо за ответ, но просто матрицы у меня уже готовые 4 штуки в едином блоке вот такие

    • for(int posY = 7; posY >= 0; posY --) {
              for(int i = 0; i < 4; i++) {
                if(strTime[i] != strTime_old[i]){
                  lc.buildChar(strTime[i], posY, iPosX[i], 1, digit6x8future);
                  lc.buildChar(strTime_old[i], posY - 8, iPosX[i], 1, digit6x8future);
                }
              }
      
  2. А! Понял! Первое, что приходит на ум, так как проверить на железе не могу, надо будет заказать такую матрицу, просто надо поменять местами X и Y:

    void digitalClockDisplay(){
      if(millis() - previousMillis >= 1000) {
        previousMillis = millis();
        bInvert = !bInvert;
    
        lc.buildChar(bInvert ? ':' : ' ', 13, 0, 1, digit6x8future);
    
        DateTime now = rtc.now();
    
        strTime[0] = char(now.minute() % 10 + 48);
    
        if(strTime[0] != strTime_old[0]){
          strTime[1] = char(now.minute() / 10 + 48);
          strTime[2] = char(now.hour() % 10 + 48);
          strTime[3] = char(now.hour() / 10 + 48);
    
          for(int posY = 7; posY >= 0; posY --) {
            for(int i = 0; i < 4; i++) {
              if(strTime[i] != strTime_old[i]){
                lc.buildChar(strTime[i], posY, iPosX[i], 1, digit6x8future);
                lc.buildChar(strTime_old[i], posY - 8, iPosX[i], 1, digit6x8future);
              }
            }
    
            lc.Update();
            delay(50);
          }
    
          for(int i = 0; i < 4; i++) strTime_old[i] = strTime[i];
        }
    
        lc.Update();
      }
    }

    Не уверен, надо проверить…

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение