Содержание

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

Проекты на 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 всего три ноги и расположены они слева. Можно ли использовать его в этом проекте?

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