Бионический будильник

Проекты на Arduino Uno и Slot Shield

Сейчас в моде всякие умные или бионические будильники. Они заранее плавно добавляют свет в спальне — пробуждение становится гораздо комфортней.

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

В остальном — это классический будильник на Ардуино. Управляющая плата — оригинальная Arduino Uno. За время отвечает модуль часов реального времени. Для управления гаджетом используется четырёхкнопочная клавиатура.

Что потребуется

Видеоинструкция

Как собрать

Установите Troyka Slot Shield на Arduino Uno

Вставьте Quad Display в разъёмы E и F. Пин CS подключу к 10 пину Arduino.

Установите четырёхкнопочную клавиатуру в слот C. Сигнал первой кнопки подключите к пину 0, второй к 1, третьей к 4 и четвёртой к 5.

Часы реального времени вставьте в пины I²C разъёма B. Вставьте батарейку CR1225 в держатель на лицевой панели модуля.

Подключите пьезопищалку к пину 7 слота A.

Установите светодиодную матрицу в слот D и подключите к пину 8.

Скетч

Прошейте контроллер скетчем через Arduino IDE.

bionical-alarm.ino
// Подключаем библиотеку для работы с дисплеем
#include <QuadDisplay2.h>
// создаём объект класса QuadDisplay и передаём номер пина CS
QuadDisplay qd(10);
 
// библиотека для работы I²C
#include <Wire.h>
 
// библиотека для работы с часами реального времени
#include "TroykaRTC.h"
// создаём объект для работы с часами реального времени
RTC clock;
 
// библиотека для работы с кнопками
#include "TroykaButton.h"
 
// библиотека для работы с RGB-матрицей
#include <Adafruit_NeoPixel.h>
 
// пины к которым подключены кнопки
#define BUTTON_PIN_1  0
#define BUTTON_PIN_2  1
#define BUTTON_PIN_3  4
#define BUTTON_PIN_4  5
 
// пин к которому подключена пищалка
#define BUZZER_PIN  7
 
// номер пина, к которому подключена RGB-матрица
#define MATRIX_PIN 8
// количество светодиодов в матрице
#define LED_COUNT 16
 
// создаём объект класса Adafruit_NeoPixel
Adafruit_NeoPixel matrix = Adafruit_NeoPixel(LED_COUNT, MATRIX_PIN, NEO_GRB + NEO_KHZ800);
 
// создаём объект для работы с кнопкой
TroykaButton button1(BUTTON_PIN_1);
TroykaButton button2(BUTTON_PIN_2);
TroykaButton button3(BUTTON_PIN_3);
TroykaButton button4(BUTTON_PIN_4);
 
// создаем объект класса long для хранения счетчиков для света и звука
unsigned long lightTime = 0;
unsigned long buzzerTime = 0;
 
 
// переменные для хранения времени будильника
int hoursAlarm = 12;
int minutesAlarm = 59;
 
// переменные для хранения яркости цветов
int r;
int g;
 
// переменная для переключения между установкой часов и установкой будильника
boolean state = true;
// переменная для переключения света
boolean daylight = false;
 
void setup() {
  // инициализация дисплея
  qd.begin();
 
  // инициализация часов
  clock.begin();
  // метод установки времени и даты в модуль вручную
  // clock.set(10,25,45,20,05,2019,MONDAY);
  // метод установки времени и даты автоматически при компиляции
  clock.set(__TIMESTAMP__);
  // что бы время менялось при прошивке или сбросе питания
  // закомментируйте оба метода clock.set();
 
  // инициализация кнопок
  button1.begin();
  button2.begin();
  button3.begin();
  button4.begin();
  //инициализация выхода пищалки
  pinMode(BUZZER_PIN, OUTPUT);
 
  // инициализация RGB-матрицы
  matrix.begin();
  // гасим LED матрицу
  colorWipe(matrix.Color(0, 0, 0));
}
 
void loop() {
  // запрашиваем данные с часов
  clock.read();
  // считываем показания часов и минут в переменные
  int hours = clock.getHour();
  int minutes = clock.getMinute();
 
  // считывание данных с кнопок
  button1.read();
  button2.read();
  button3.read();
  button4.read();
 
// если кнопка «1» длительно зажата  
  if (button1.isHold()) {
    // меняем состояние будильника
    state = !state;
    // в зависимости от текущего состояние будильника
    if (!state) {
      qd.displayDigits(QD_A, QD_L, QD_NONE, QD_NONE);
    } else {
      qd.displayDigits(QD_t, QD_I, QD_NONE, QD_NONE);
    }
    // ждём пару секунд
    delay(2000);
  }
  // в зависимости от текущего режима работы будильника
  // «текущее время / время подъема»
  // если режим «текущее время»
  if (state) {
    // в зависимости от состояние кнопок
    // увеличиваем / уменьшаем часы и минуты
    if (button1.isClick()) {
      clock.setHour(hours + 1);
    } else if (button2.isClick()) {
      clock.setHour(hours - 1);
    } else if (button3.isClick()) {
      clock.setMinute(minutes - 1);
    } else if (button4.isClick()) {
      clock.setMinute(minutes + 1);
    }
 
    // запрашиваем данные с часов
    clock.read();
    // считываем показания часов и минут в переменные
    hours = clock.getHour();
    minutes = clock.getMinute();
    // выводим время на дисплей 
    qd.displayScore(hours, minutes, true);
 
    } else {
    // если режим «время подъема»
    // в зависимости от состояние кнопок
    // увеличиваем / уменьшаем часы и минуты
    if (button1.isClick()) {
      hoursAlarm++;
    } else if (button2.isClick()) {
      hoursAlarm--;
    } else if (button3.isClick()) {
      minutesAlarm--;
    } else if (button4.isClick()) {
      minutesAlarm++;
    }
    // запускаем защиту от перехода через 0
    parsingAlarmTime();
    // выводим будильник на дисплей
    qd.displayScore(hoursAlarm, minutesAlarm);
    }
 
  // за 5 минут до подъема
  while (hours == hoursAlarm && minutes == minutesAlarm-5) {
    // запускаем "рассвет"
    daylight = true;
    break;
  }
  // защита от пограничного случая включения
  while (hours+1 == hoursAlarm && minutesAlarm == 0) {
    // запускаем "рассвет"
    daylight = true;
    break;
  }
 
  // пришло время подъема? 
  while (hours == hoursAlarm && minutes == minutesAlarm) {
    if (millis() - buzzerTime > 1000) {
      // запускаем звуковую функцию подъема
      tone(BUZZER_PIN, 500, 100);
      buzzerTime = millis();
    }
    break;
  }
 
  // пора выключать будильник?
  while (hours == hoursAlarm && minutes == minutesAlarm+1) {
    // выключаем "рассвет"
    daylight = false;
    // выключаем подсветку
    colorWipe(matrix.Color(0, 0, 0));
    // обнуляем значения цвета
    r = 0;
    g = 0;
    break;
  }
  // защита от пограничного случая выключения
  while (hours-1 == hoursAlarm && minutesAlarm == 59) {
    // выключаем "рассвет"
    daylight = false;
    // выключаем подсветку
    colorWipe(matrix.Color(0, 0, 0));
    // обнуляем значения цвета
    r = 0;
    g = 0;
    break;
  }
 
  // пора зажигать свет?
  while (daylight) {
    // плавно зажигаем Зеленый
    if (r == 0 && g < 255) {
      if (millis() - lightTime > 400) {
        colorWipe(matrix.Color(r, g, 0));
        g++;
        lightTime = millis();
      }
    }
    // плавно добавляем Красный
    if (r < 255 && g == 255) {
      if (millis() - lightTime > 400) {
        colorWipe(matrix.Color(r, g, 0));
        r++;
        lightTime = millis();
      }
    }
    // плавно гасим Зеленый
    if (r == 255) {
      if (millis() - lightTime > 400) {
        colorWipe(matrix.Color(r, g, 0));
        if (g != 0){
          g--;
        }
        lightTime = millis();
      }
    }
    break;
  }
}
 
// функция защиты от перехода через 0
void parsingAlarmTime() {
  if (hoursAlarm > 23) {
    hoursAlarm = 0;
  } else if (hoursAlarm < 0) {
    hoursAlarm = 23;
  }
 
  if (minutesAlarm > 59) {
    minutesAlarm = 0;
  } else if (minutesAlarm < 0) {
    minutesAlarm = 59;
  }
}
 
// функция заполнения каждого сегмента LED матрици
void colorWipe(uint32_t c) {
  for (uint16_t i = 0; i < matrix.numPixels(); i++) {
    // заполняем текущий сегмент выбранным цветом
    matrix.setPixelColor(i, c);
    matrix.show();
  }
}

Часто задаваемые вопросы

Где скачать необходимые библиотеки и как их установить?
У моего модуля QuadDisplay всего три ноги и расположены они слева. Можно ли использовать его в этом проекте?

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