Будильник-шредер

Я постоянно просыпаю поэтому решил сделать устройство, которое будет меня штрафовать. Допустим мне надо встать в 7 утра. Внутрь будильника я кладу купюру. Если я не услышу сигнал - включается обратный отсчет, начинает мигать лампа и если я продолжаю дрыхнуть включается шреддер. И режет мои деньги в клочки. Как я сделал мой будильник-уичтожитель - сейчас расскажу.

Видеообзор

Что понадобится?

Чертежи и модель

Модель имеет недостатки и кое-где приходится поработать дрелью для того что бы установить например электронику или уголки для креплений. Но это видно только на стадии сборки так что будьте внимательны!

Исходный код

Прошейте плату Iskra Mega кодом программы:

smart_kettler.ino
int volume_bud = 20; // громкость воспроизведения файла
int shreder_time = 9000; // задаем время работы шредера
 
// подключаем библиотеки для плеера
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <SPI.h>
// библиотека для работы со сборкой силовых ключей
#include <AmperkaFET.h>
// пин выбора устройства на шине SPI
#define PIN_CS  8
FET mosfet(PIN_CS, 4);
const uint8_t numberTable[] = {0b11111100, 0b01100000, 0b11011010, 0b11110010, 0b01100110, 0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11110110, 0b00000001, 0b0000000};
 
// Подключаем библиотеку для работы с дисплеем
#include <QuadDisplay2.h>
// создаём объект класса QuadDisplay и передаём номер пина CS
QuadDisplay qd(29, 35, 31);
QuadDisplay qd_bud(37, 43, 39);
#include "TroykaRTC.h" // библиотека для работы с часами реального времени
#include <Wire.h>  // библиотека для работы I²C
 
#define LEN_TIME 12 // размер массива для времени
#define LEN_DATE 12 // размер массива для даты
#define LEN_DOW 12 // размер массива для дня недели
 
// кнопки
#define PIN_BUTTON_SET 23
#define PIN_BUTTON_UP 25
#define PIN_BUTTON_DOWN 27
#define PIN_BUTTON_OFF 45
 
// Лампочка -Troyka-Реле подключён к пину номер 53
#define RELAY_PIN 53
int RelayState = LOW;
 
// Мотор протяжки -Troyka-Реле подключён к пину номер 47
#define RELAY_motor 47
// Мотор шредера -Troyka-Реле подключён к пину номер 49
#define RELAY_shredder 49
 
 
// датчики линии
#define SENSOR_LINE_PIN1 A0
#define SENSOR_LINE_PIN2 A1
 
// создаём объект для работы с часами реального времени
RTC clock;
unsigned long lasttime;
int h, m = 0;
 
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);
 
byte hour_bud = 0;
byte minute_bud = 0;
byte budilnik = 15;
boolean is_once /* = true*/;
boolean is_once_timer /* = true*/;
boolean did_not_have_time /* = true*/;
 
void setup()
{
  SPI.begin();
  mosfet.begin();
  Serial.begin(9600);
  is_once = true;       //Устанавливаем флаг шредера
  is_once_timer = true; // устанавливаем флаг обратного отсчета
  did_not_have_time = true; // не успел нажать на кнопку- потерял деньги
  // инициализация дисплея
  qd.begin();
  qd_bud.begin();
  // инициализация часов
  clock.begin();
  // метод установки времени и даты в модуль вручную
  // clock.set(10,25,45,27,07,2005,THURSDAY);
  // метод установки времени и даты автоматически при компиляции
  // clock.set(__TIMESTAMP__);
  lasttime = millis();
 
  // Конфигурируем нужные пины на выход
  pinMode(RELAY_PIN, OUTPUT);
  int RelayState = LOW;             // этой переменной устанавливаем состояние светодиода
  digitalWrite(RELAY_PIN, LOW);
 
  // объявляем выходы моторов шредера и протяжки после чего выключаем их
  pinMode(RELAY_motor, OUTPUT);
  pinMode(RELAY_shredder, OUTPUT);
  digitalWrite(RELAY_motor, LOW);
  digitalWrite(RELAY_shredder, LOW);
 
  mySoftwareSerial.begin(9600);
  // открываем последовательный порт
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
 
  if (!myDFPlayer.begin(mySoftwareSerial))
  { //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true);
  }
  Serial.println(F("DFPlayer Mini online."));
  myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms
  //----Set volume----
  myDFPlayer.volume(volume_bud);  //Set volume value (0~30).
  myDFPlayer.volumeUp(); //Volume Up
  myDFPlayer.volumeDown(); //Volume Down
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
 
}
 
void (*resetFunc) (void) = 0;  // объявляем функцию перезагрузки
 
void loop()
{
 
  // переменные для датчиков линии
  int line1 = digitalRead(SENSOR_LINE_PIN1);
  int line2 = digitalRead(SENSOR_LINE_PIN2);
 
  int b_setup = digitalRead(PIN_BUTTON_SET);
  int b_up = digitalRead(PIN_BUTTON_UP);
  int b_down = digitalRead(PIN_BUTTON_DOWN);
  int b_off = digitalRead(PIN_BUTTON_OFF);
 
  // запрашиваем данные с часов
  clock.read();
  // считываем показания часов и минут в переменные
  int second = clock.getSecond();
  int hour = h = clock.getHour();
  int minute = m = clock.getMinute();
 
 
  // выводим время на дисплей
  if (millis() > lasttime + 1000)
  {
    lasttime = millis();
    qd.displayScore(hour, minute, true);
    qd_bud.displayClear();
    clearTime();
  }
  Serial.println(minute_bud);
  Serial.println(hour_bud);
 
  // если нажаты кнопки настраиваем время
  if ((millis() > lasttime + 250) && (b_up == HIGH || b_down == HIGH || b_setup == HIGH))
  {
    lasttime = millis();
    qd_bud.displayScore(hour_bud, minute_bud, true);
    sendTime(hour_bud, minute_bud);
    if (b_setup == HIGH) // если нажата кнопка настройки - устанавливаем часы будильника
    {
      if (b_up == HIGH) // прибавляем час
      {
        hour_bud++;
      }
      if (b_down == HIGH) // если нажата кнопка настройки - устанавливаем часы будильника
      {
        hour_bud = (hour_bud - 1);
      }
    }
    if (b_up == HIGH && b_setup == LOW) // прибавляем минуты
    {
      minute_bud++;
    }
    if (b_down == HIGH && b_setup == LOW) // если нажата кнопка настройки - устанавливаем часы будильника
    {
      minute_bud = (minute_bud - 1);
    }
    qd_bud.displayScore(hour_bud, minute_bud, true);
    sendTime(hour_bud, minute_bud);
  }
 
  // управление механизмом протяжки
  if (line1 == 1 && line2 == 0) // если купюра вставлена, включаем мотор механизма протяжки
  {
    digitalWrite(RELAY_motor, HIGH);
  }
 
  if (line2 == 1) // если купюра дошла до шгредера, выключаем мотор механизма протяжки
  {
    // выключаем первый мотор
    digitalWrite(RELAY_motor, LOW);
  }
 
  // включаем будильник в уставновленное время
  if (minute_bud == minute && hour_bud == hour && second == 1)
  {
    myDFPlayer.play(1);  //Play the first mp3
  }
 
  // запускаем цикл обратного отсчета
  if (minute_bud == minute && hour_bud == hour && is_once_timer == true && second > 1)
  {
    timer_budilnic();
  }
 
  // включаем шредер
  if (budilnik == 0 && is_once == true)
  {
    func_alarm();
    is_once = false; //Не забываем сбросить флаг
    is_once_timer = false;
  }
 
  //  управление нопкой
  if (b_off == LOW && did_not_have_time == true)
  {
    is_once = false; //Не забываем сбросить флаг
    is_once_timer = false;
    myDFPlayer.disableLoopAll(); //stop loop all mp3 files.
    hour_bud = 0;
    minute_bud = 0;
 
    // возвращаем в первоначальное состояние
    resetFunc();
  }
}
 
// обратный отсчет будильника
void timer_budilnic()
{
  if ((millis() > lasttime + 1000) && budilnik >= 0)
  {
    lasttime = millis();
    budilnik--;
    qd_bud.displayScore(0, budilnik, true);
    sendTime(budilnik);
 
    // если лампа не горит, то зажигаем, и наоборот
    if (RelayState == LOW)
      RelayState = HIGH;
    else
      RelayState = LOW;
 
    // устанавливаем состояния выхода, чтобы включить или выключить светодиод
    digitalWrite(RELAY_PIN, RelayState);
 
  }
}
 
// Функция включения шредера
void func_alarm()
{
  did_not_have_time = false;
  qd_bud.displayScore(0, 0, true);
  sendTime(0);
  qd.displayScore(h, m, true);
  // включаем шредер и ленту протяжки
  digitalWrite(RELAY_motor, HIGH);
  digitalWrite(RELAY_shredder, HIGH);
  unsigned long old_time = millis();
  while (millis - old_time < shreder_time) {
    qd.displayScore(h, m, true);
    sendTime(0);
  }
  // выключаем шредер и ленту протяжки
  digitalWrite(RELAY_motor, LOW);
  digitalWrite(RELAY_shredder, LOW);
  qd_bud.displayClear();
  old_time = millis();
  while (millis - old_time < shreder_time) {
    qd.displayScore(h, m, true);
    sendTime(0);
  }
  digitalWrite(RELAY_PIN, LOW); // выключаем свет
  // возвращаем в первоначальное состояние
  resetFunc();
 
}
 
uint8_t rev(uint8_t a)
{
  uint8_t b = 0;
  if (a & 0x80)
    b |= 0x01;
  if (a & 0x40)
    b |= 0x02;
  if (a & 0x20)
    b |= 0x04;
  if (a & 0x10)
    b |= 0x08;
  if (a & 0x08)
    b |= 0x10;
  if (a & 0x04)
    b |= 0x20;
  if (a & 0x02)
    b |= 0x40;
  if (a & 0x01)
    b |= 0x80;
  return b;
}
 
void sendTime(int minute) {
  uint8_t timeArray[4];
  timeArray[3] = minute / 1000;
  minute = minute % 1000;
  timeArray[2] = minute / 100;
  minute = minute % 100;
  timeArray[1] = minute / 10;
  timeArray[0] = minute % 10;
  for ( uint8_t i = 0; i < 4; i++) {
    mosfet.byteWrite(i, rev(numberTable[timeArray[i]]));
  }
}
void clearTime() {
  for ( uint8_t i = 0; i < 4; i++) {
    mosfet.byteWrite(i, rev(numberTable[11]));
  }
}
void sendTime(uint8_t hour, uint8_t minute) {
  uint8_t timeArray[4];
  timeArray[3] = hour / 10;
  timeArray[2] = hour % 10;
  timeArray[1] = minute / 10;
  timeArray[0] = minute % 10;
  for ( uint8_t i = 0; i < 4; i++) {
    mosfet.byteWrite(i, rev(numberTable[timeArray[i]]));
  }
}