Часы, будильник, таймер на Arduino. v1.0

Фото 1/3 Часы, будильник, таймер на Arduino. v1.0
Есть в наличии. Отгрузка со склада в Москве 1-2 рабочих дня.
3 290 × = 3 290

Спецификация набора

То, что у вас уже есть, вы можете удалить в корзине.

НаименованиеЦенаКол-во
CR1225, Элемент питания литиевый (1шт) 3В 50 1
Troyka-Temperature Humidity Sensor DHT11, Цифровой датчик температуры и влажности 290 1
0.96inch OLED (A), OLED дисплей с разрешением 128х64px, интерфейсы SPI/I2C, изогнутый контакный разъем 760 1
Troyka-3D Joystick, 3D-джойстик для Arduino проектов 480 1
Troyka-Buzzer, Пьезодинамик 4кГц 80дБ для Arduino проектов 140 1
Troyka-Relay, Релейный модуль на основе RTD14005 16А/250В (7А/30В) для Arduino проектов 590 1
Troyka-RTC, Часы реального времени на оcнове DS1307 для Arduino проектов 590 1
Iskra Mini (без ног), Программируемый контроллер на базе ATmega328 (аналог Arduino Mini) 390 1

Описание

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

часы с использованием модуля реального времени

В качестве железа будем использовать Амперкины тройки, искру и дюймовый OLED дисплей.

Дисплей

0.96inch OLED (A)
0.96inch OLED (A) - это встраиваемый двухцветный (желтый/синий) OLED дисплей с интерфейсом I2C/SPI. Разрешение экрана 128х64 пикселей, а угол обзора более 160 градусов.
Размеры платы 29мм х 33 мм.

Контроллер

Iskra Mini
Iskra Mini — полноценная Arduino-платформа, только маленькая: всего 33×20 мм.

Обратите внимание, что на плате нет собственного USB-порта.
Поэтому для её прошивки понадобится посредник!
Им может быть другой контроллер Arduino

Характеристики Iskra Mini

  • Микроконтроллер: ATmega328
  • Тактовая частота: 16 МГц
  • Флеш-память: 32 КБ (2 КБ используются загрузчиком)
  • Оперативная память SRAM: 2 КБ
  • Энергонезависимая память EEPROM: 1 КБ
  • Рабочее напряжение: 5 В
  • Входное напряжение: 5,3–12 В
  • Портов ввода-вывода общего назначения: 20
  • Портов с поддержкой ШИМ: 6
  • Портов, подключённых к АЦП: 8 (4 из них на нераспаянных выводах)
  • Разрядность АЦП: 10 бит
  • Аппаратные интерфейсы: UART, SPI, I²C (на нераспаянных выводах)
  • Максимальный ток одного вывода: 40 мА
  • Максимальный ток с пина +5V: 150 мА

Цифровой датчик температуры и влажности

Troyka-Temperature Humidity Sensor DHT11
Troyka-Temperature Humidity Sensor DHT11.
Данные температуры и влажности датчик отдаёт по одному проводу в виде цифрового сигнала. Это позволяет передавать данные на расстояние до нескольких десятков метров.
В сердце модуля — популярная среди любителей сенсорная сборка DHT11. Он работает по собственному протоколу. На борту модуля — популярная среди любителей сенсорная сборка DHT11.

Характеристики

  • Напряжение питания: 3–5 В
  • Потребляемый ток при запросе данных: 2,5 мА
  • Потребляемый ток в ожидании: 100 мкА
  • Диапазон температур: 0–50 °С
  • Погрешность температуры: ±2 °С
  • Диапазон влажности: 20–90%
  • Погрешность влажности: ±5%
  • Габариты: 25×25 мм

3D-джойстик

3D Joystick
3D Joystick - сделает управление нашим устройством быстрым и удобным.
Модуль-джойстик схож с «грибочком» на манипуляторах PlayStation и XBox. Он комбинирует в себе двухосный джойстик и тактовую кнопку. В нейтральном положении аналоговый сигнал соответствует половине напряжения питания. При перемещении джойстика в одну сторону напряжение будет нарастать, а при движении джойстика в другую сторону — падать. Таким образом, можно получать точное положение ручки джойстика и реагировать на угол наклона, а не только на сам факт наклона ручки. Хотя в этом проекте мы используем только факт наклона.

Характеристики

  • Напряжение питания: 3–5 В
  • Интерфейс по осям X, Y: аналоговый, линейный
  • Интерфейс кнопки: цифровой, бинарный
  • Габариты: 25×25 мм

Управление джойстиком

Нажатие влево - вход в меню настроек
изменяемое значение подсвечивается
нажатие вверх - изменение значения
нажатие вправо - переход к следующему значению
при настройки будильника слева появляется значок "а"
нажатие влево - выход из меню с сохранением изменений
время будильника сохраняется в энергонезависимой памяти

Нажатие вниз - вкл/откл будильника

Когда сработал будильник
первое нажатие на кнопку - отключение пищалки
второе нажатие на кнопку - отключение реле

Пьезодинамик

Buzzer
В нашем проекте нужно пищать. Воспользуемся модулем Buzzer.

Характеристики

  • Номинальная частота: 4 кГц
  • Интенсивность: 80 дБ
  • Номинальное рабочее напряжение: 5 В
  • Габариты: 25,4×25,4 мм

Релейный модуль

Модуль Relay
Модуль Relay это просто механический рубильник, которым можно управлять при помощи микроконтроллера, такого как Arduino. С помощью реле можно включать и выключать электроприборы, которые подключены к бытовой электросети 220 В. На модуле расположен светодиод, который всегда подскажет — замкнуто реле или нет.
У этого реле есть есть не только нормально разомкнутый (NO) контакт, но и нормально замкнутый (NC). Это удобно.

Характеристики

  • Номинальное напряжение питания: 5 В
  • Номинальное напряжение сигнала: 3–5 В
  • Максимальный ток коммутации: 16 А
  • Коммутируемое переменное напряжение (пиковое): 250 В
  • Потребляемый ток: 87 мА
  • Рабочая температура: −40…+85 °C
  • Магнитная система катушки: моностабильная
  • Рекомендованная частота переключения: до 1 Гц
  • Электрическая износостойкость (NO) контакта: 30×10³ переключений
  • Электрическая износостойкость (NC) контакта: 10×10³ переключений
  • Габариты: 50,8×25,4 мм

Часы реального времени

RTC
Модуль RTC - сделан на основе популярного чипа DS1307. Он общается с управляющей электроникой по протоколу I²C / TWI.
Слот предназначен для часовой батарейки размера CR1225 на 3В. Без неё модуль не работает даже с внешним питанием.

Характеристики

  • Напряжение внешнего питания: 4,5–5,5 В
  • Напряжение питания батарейки: 2–3,5 В
  • Потребляемый ток: 500 нА (≈6 месяцев на батарейке)
  • Выходной интерфейс: I²C
  • Габариты: 25,4×25,4 мм

Элемент питания

CR1225 – литиевая батарейка

Характеристики

  • Напряжение: 3В
  • Типоразмер cr1225

Технические параметры

Индикация Дата, месяц, часы, минуты, температура, влажность
Точность времени, секунд/сутки 2
Диапазон температур 0–50 °С
Погрешность температуры ±2 °С
Диапазон влажности 20–90%
Погрешность влажности ±5%
Максимальный ток коммутации 16 А
Коммутируемое переменное напряжение (пиковое) 250 В
Номинальное напряжение питания 5 В

Электрическая схема

Электрическая схема

Монтажная схема

В этом проекте нет.

Печатная плата

В этом проекте нет.

Скетч. Код программы

#include <DS1307RTC.h>
#include <Time.h>
#include <Wire.h>
#include <PinChangeInt.h>
#include <EEPROM.h>
#include "clock.h"
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <TroykaDHT11.h>
#include <TimerOne.h>
#include <Tone.h>


volatile boolean JoyStickZPressFlag = false;
byte AlarmHour = 7;
byte AlarmMinute = 0;
boolean AlarmFlag;
boolean AlarmSetFlag;
volatile boolean UpdateScreenFlag = false;
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
DHT11 dht(TEMP_SEN_PIN);
Tone Buzzer;


void setup()
{
  digitalWrite(JOYSTICK_Z_PIN, HIGH);
  PCintPort::attachInterrupt(JOYSTICK_Z_PIN, &JOYSTICK_Z_PIN_ISR, FALLING);

  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);

  //pinMode(BUZZER_PIN, OUTPUT);
  //digitalWrite(BUZZER_PIN, LOW);
  Buzzer.begin(BUZZER_PIN);

  AlarmHour = EEPROM.read(ALARM_HOUR_ADR);
  if (AlarmHour > 23)
    AlarmHour = 7;

  AlarmMinute = EEPROM.read(ALARM_MINT_ADR);
  if (AlarmMinute > 59)
    AlarmMinute = 0;

  AlarmFlag = EEPROM.read(ALARM_FLAG_ADR);
  if (AlarmFlag > 1)
    AlarmFlag = ALARM_FLAG_DEFAULT;
    

  Wire.begin();
  tmElements_t CurTime;
  RTC.read(CurTime);
  
  dht.begin();
  
  display.begin(SSD1306_SWITCHCAPVCC);
  UpdateScreenFlag = true;

  //период обновления экрана по прерыванию таймера
  Timer1.initialize(8000000);
  Timer1.attachInterrupt(TimerOne_ISR);
}
//---------------------------------
void loop()
{    
  static tmElements_t CurrentTime;

  if (UpdateScreenFlag) //если обновление экрана
  {
    RTC.read(CurrentTime); //чтение времени с RTC
    display.clearDisplay(); //очистка дисплея
    UpdateTime(&CurrentTime); //обновление времени
    UpdateDate(&CurrentTime); //обновление даты
    UpdateTemp(); //обновление показаний температуры и влажности
    if (AlarmFlag) //если включен будильник
    {//отображение символа "а"
      display.setTextSize(ALARM_SIZE);
      display.setCursor(ALARM_HOR_POS, ALARM_VER_POS);
      display.print("a");
    }
    
    display.display(); //отображение на дисплее обновленной информации 

    if (AlarmFlag) //если включен будильник
      CheckAlarm(&CurrentTime); //проверка времени

    UpdateScreenFlag = false; //стирание флага обновления экрана
  }

  switch(ScanJoyStick()) //проверка нажатия джойстивка
  {
    case JOYSTICK_LEFT_: //если влево
      ChangeSettings(); //меню настроек
    break;

    case JOYSTICK_DOWN_: //если вниз
      ChangeAlarmState(&CurrentTime); //вкл/откл будильник
    break;

    default:
    break;
  }
    
  if ((JoyStickZPressFlag) && (digitalRead(RELAY_PIN))) //если нажата кнопка джойстика
  {
    delay(100);
    if (!digitalRead(JOYSTICK_Z_PIN))
    {
      static byte JoyStickZPressCnt = 0;
      
      if (JoyStickZPressCnt == 0) //если первое нажатие
      {
        //digitalWrite(BUZZER_PIN, LOW);
        Buzzer.stop(); //выключение пищалки
        JoyStickZPressCnt++;
      }
      else if (JoyStickZPressCnt == 1) //если второе нажатие
      {
        digitalWrite(RELAY_PIN, LOW); //выключение реле
        JoyStickZPressCnt = 0;
      }
      
      JoyStickZPressFlag = false; //стирание флага нажатия кнопки джойстика
    }
  }
}
//---------------------------------
void UpdateTime(tmElements_t* TimeVal)
{
  display.setTextColor(WHITE); //установка неинверсного отображения
  display.setTextSize(TIME_SIZE); //установка размера текста
  display.setCursor(HOUR_HOR_POS, HOUR_VER_POS); //установка курсора
  //вывод времени
  if (TimeVal->Hour < 10)
    display.print("0");
  display.print(TimeVal->Hour);
  display.print(":");

  if (TimeVal->Minute < 10)
    display.print("0");
  display.print(TimeVal->Minute);
}
//---------------------------------
void UpdateDate(tmElements_t* TimeVal)
{
  display.setTextColor(WHITE);
  display.setTextSize(TEMP_SIZE);
  display.setCursor(DATE_HOR_POS, DATE_VER_POS);
 //вывод даты
  if (TimeVal->Day < 10)
    display.print("0");
  display.print(TimeVal->Day);
  display.print("/");

  if (TimeVal->Month < 10)
    display.print("0");
  display.print(TimeVal->Month);
}
//---------------------------------
void UpdateTemp()
{
  display.setTextColor(WHITE);
  display.setTextSize(TEMP_SIZE);
  display.setCursor(TEMP_HOR_POS, TEMP_VER_POS);
  
  if (dht.read() == DHT_OK) //если чтение данных без ошибок
  { //вывод температуры и влажности
    display.print("t ");
    display.print(dht.getTemperatureC());
    display.print("C");
    display.print("  h ");
    display.print(dht.getHumidity());
    display.print("%");
  }

  else //иначе
  { //вывод надписи "Chip & Dip"
    display.print("Chip & Dip");
  }
}
//---------------------------------
void CheckAlarm(tmElements_t* TimeVal)
{ //если будильник не включен и совпадение времени будильника с текущим временем
  if ((!AlarmSetFlag) && (TimeVal->Hour == AlarmHour) && (TimeVal->Minute == AlarmMinute))
  {
    digitalWrite(RELAY_PIN, HIGH); //включение реле
    //digitalWrite(BUZZER_PIN, HIGH);
    Buzzer.play(NOTE_A3); //включение пищалки
    AlarmSetFlag = true; //установка флага включения будильника
  }
  //иначе
  else if ((AlarmSetFlag) && ((TimeVal->Hour != AlarmHour) || (TimeVal->Minute != AlarmMinute)))
    AlarmSetFlag = false; //стирание флага включения будильника
}
//---------------------------------
void ChangeSettings()
{
    tmElements_t tm;
    RTC.read(tm);
    
    byte TimeParts[6] = {tm.Hour, tm.Minute, AlarmHour, AlarmMinute, tm.Day, tm.Month};
    byte TimeMAXVals[6] = {23, 59, 23, 59, 31, 12};
    byte CurTimePart = 0;
    boolean ExitSetUp = false;

    //отображение начального экрана настроек:
    //значение часов отображается инверсно
    display.clearDisplay();
    UpdateTemp();
    UpdateDate(&tm);
    display.setTextSize(TIME_SIZE);
    display.setCursor(HOUR_HOR_POS, HOUR_VER_POS);
    display.setTextColor(BLACK, WHITE); //инверсное отображение

    if (TimeParts[0] < 10)
      display.print("0");
    display.print(TimeParts[0]);

    display.setTextColor(WHITE);
    display.print(":");

    if (TimeParts[1] < 10)
      display.print("0");
    display.print(TimeParts[1]);
    
    display.display();

    delay(500);

    //цикл меню настроек
    while (!ExitSetUp)
    {
      delay(150);
      
      switch(ScanJoyStick()) //проверка нажатия джойстивка
      {
        case JOYSTICK_UP_: //если вверх
        { //изменение значения на один
          TimeParts[CurTimePart]++;
          if (TimeParts[CurTimePart] > TimeMAXVals[CurTimePart])
          {
            TimeParts[CurTimePart] = 0;

            if (CurTimePart > 3)
              TimeParts[CurTimePart] = 1;
          }
        }
        break;

        case JOYSTICK_RIGHT_: //если вправо
        { //переход к следующему значению
          CurTimePart++;
          if (CurTimePart > 5)
            CurTimePart = 0;
        }
        break;
        
        case JOYSTICK_LEFT_: //если влево
          ExitSetUp = true; //выход из меню
        break;
      }
      //отображение на экране
      //изменяемое значение отображается инверсно
      //при настройке будильника отображается символ "а"
      //изменяемое значение определяет переменная CurTimePart:
      //CurTimePart = 0 - часы времени
      //CurTimePart = 1 - минуты времени
      //CurTimePart = 2 - часы будильника
      //CurTimePart = 3 - минуты будильника
      //CurTimePart = 4 - день
      //CurTimePart = 5 - месяц, см. определение массива TimeParts[]
      display.clearDisplay();
      
      if (CurTimePart <= 3)
      {
        UpdateTemp();
        display.setCursor(DATE_HOR_POS, DATE_VER_POS);
        if (TimeParts[4] < 10)
            display.print("0");
        display.print(TimeParts[4]);
        display.print("/");
        if (TimeParts[5] < 10)
          display.print("0");
        display.print(TimeParts[5]);
        display.setTextSize(TIME_SIZE);
        display.setCursor(HOUR_HOR_POS, HOUR_VER_POS);
      
        if ((CurTimePart%2) == 0)
        {
          display.setTextColor(BLACK, WHITE); //инверсное отображение
          if (TimeParts[CurTimePart] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart]);

          display.setTextColor(WHITE);
          display.print(":");

          if (TimeParts[CurTimePart + 1] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart + 1]);
        }

        else
        {
          if (TimeParts[CurTimePart - 1] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart - 1]);
          display.print(":");
          display.setTextColor(BLACK, WHITE); //инверсное отображение
          if (TimeParts[CurTimePart] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart]);
        }
      }

      else
      {
        display.setTextColor(WHITE);
        display.setTextSize(TIME_SIZE);
        display.setCursor(HOUR_HOR_POS, HOUR_VER_POS);
        if (TimeParts[2] < 10)
          display.print("0");
        display.print(TimeParts[2]);
        display.print(":");
        if (TimeParts[3] < 10)
          display.print("0");
        display.print(TimeParts[3]);
        UpdateTemp();

        display.setCursor(DATE_HOR_POS, DATE_VER_POS);

        if (CurTimePart == 4)
        {
          display.setTextColor(BLACK, WHITE); //инверсное отображение
          if (TimeParts[CurTimePart] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart]);

          display.setTextColor(WHITE);
          display.print("/");
          if (TimeParts[CurTimePart + 1] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart + 1]);
        }

        else
        {
          if (TimeParts[CurTimePart - 1] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart - 1]);
          display.print("/");
          display.setTextColor(BLACK, WHITE); //инверсное отображение
          if (TimeParts[CurTimePart] < 10)
            display.print("0");
          display.print(TimeParts[CurTimePart]);
        }
      }

      if (CurTimePart > 1)
      {
        display.setTextColor(WHITE);
        display.setTextSize(ALARM_SIZE);
        display.setCursor(ALARM_HOR_POS, ALARM_VER_POS);
        display.print("a");
      }

      display.display();
    }

    //будильник
    AlarmHour = TimeParts[2];
    AlarmMinute = TimeParts[3];
    //запись в память
    EEPROM.write(ALARM_HOUR_ADR, AlarmHour);
    EEPROM.write(ALARM_MINT_ADR, AlarmMinute);
    
    //установка времени в RTC
    tm.Second = 0;   
    tm.Minute = TimeParts[1];
    tm.Hour = TimeParts[0];
    tm.Day = TimeParts[4];
    tm.Month = TimeParts[5];
    tm.Year = 16;
    RTC.write(tm);

  UpdateScreenFlag = true; //установка флага обновления экрана
  delay(500);
}
//---------------------------------
void ChangeAlarmState(tmElements_t* TimeVal)
{
  display.clearDisplay();
  
  if (!AlarmFlag) //если будильник выключен
  {
    AlarmFlag = true; //установка флага включения будильника
    //отображение символа "а"
    display.setTextSize(ALARM_SIZE);
    display.setCursor(ALARM_HOR_POS, ALARM_VER_POS);
    display.print("a");
  }

  else //иначе
  {
    AlarmFlag = false; //стирание флага включения будильника
  }

  EEPROM.write(ALARM_FLAG_ADR, AlarmFlag); //запись состояния будильника в память

  UpdateTemp();
  UpdateDate(TimeVal);
  UpdateTime(TimeVal);
  display.display();

  delay(500);
}
//---------------------------------
byte ScanJoyStick()
{
  byte Direction = JOYSTICK_RELEASED;
  unsigned int X_Val = analogRead(JOYSTICK_X_PIN);
  unsigned int Y_Val = analogRead(JOYSTICK_Y_PIN);
  
  if ((Y_Val >= 900) && (X_Val >= 400))
  {
    Direction = JOYSTICK_UP_;
  }
  else if ((Y_Val <= 400) && (X_Val >= 400))
  {
    Direction = JOYSTICK_DOWN_;
  }
  else if ((Y_Val >= 400) && (X_Val >= 900))
   {
    Direction = JOYSTICK_RIGHT_;
   }
  else if ((Y_Val >= 400) && (X_Val <= 400))
  {
    Direction = JOYSTICK_LEFT_;
  }
  
  return Direction;
} 
//---------------------------------
void JOYSTICK_Z_PIN_ISR()
{
  JoyStickZPressFlag = true; //установка флага нажатия кнопки джойстика
}
//---------------------------------
void TimerOne_ISR()
{
  UpdateScreenFlag = true; //установка флага обновления экрана
}

Техническая документация

Комментарии