
В предыдущем уроке 18, мы подключили Trema RTC часы реального времени с Trema кнопками и LCD I2C дисплеем к arduino Uno, написали скетч, для установки времени при помощи кнопок.
Теперь расширим функционал получившихся часов, добавив к ним функцию будильника. А код, который будет выполняться при срабатывании будильника выведем в отдельную функцию "Func_alarm_action()", чтоб Вы смогли легко его найти и изменить. Например, при срабатывании будильника, открывать жалюзи, включать свет или музыку, включить через реле тостер или кофе-машину и т.д.
Нам понадобится:
- Arduino х 1шт.
- RTC модуль Trema на базе чипа DS1307 х 1шт.
- LCD дисплей LCD1602 IIC/I2C(синий) или LCD1602 IIC/I2C(зелёный) х 1шт.
- Trema Shield х 1шт.
- Trema-модуль i2C Hub х 1шт.
- Trema-модуль кнопка c проводами х 3шт.
- Шлейф «мама-мама»для шины I2С х 2шт.
- Trema-модуль зуммер х 1шт.
- Trema-модуль светодиод х 1шт. (белый, синий, красный, оранжевый или зелёный)
Для реализации проекта нам необходимо установить библиотеки:
- Библиотека iarduino_RTC (для подключения RTC часов реального времени DS1302, DS1307, DS3231)
- Библиотека LiquidCrystal_I2C_V112 (для подключения дисплеев LCD1602 по шине I2C)
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Видео:
Схема подключения:
Подключение модулей RTC и LCD, данного урока, осуществляется к аппаратным выводам SDA, и SCL.
| RTC модуль Trema на базе чипа DS1307 / LCD дисплей на базе чипа LCD1602 | Arduino Uno |
|---|---|
| GND | GND |
| Vcc | +5V |
| SDA (Serial DAta) | A4 |
| SCL (Serial CLock) | A5 |
Подключение кнопок: кнопка «SET» к выводу 2, кнопка «UP» к выводу 3 и копка «DOWN» к выводу 4.
Зуммер подключаем к выводу 5, а светодиод к выводу 13 (дублируя встроенный в arduino).
Алгоритм работы кнопок следующий:
- В режиме вывода даты/времени/будильника (обычный режим): Кратковременное нажатие на кнопку SET переключает режимы вывода: даты/времени/будильника Удержание кнопки SET переводит часы в режим установки даты/времени/будильника (зависит от того, каким был режим вывода) Кнопки UP и DOWN, в режиме вывода будильника, активируют/деактивируют будильник. Если будильник активен, то в правом верхнем углу экрана появляется значок будильника.
- В режиме установки даты/времени/будильника: Кратковременное нажатие на кнопку SET - переход между устанавливаемыми параметрами (сек, мин, час, дни, мес, год, д.н.) Удержание кнопки SET выводит часы из режима установки Каждое нажатие на кнопку UP увеличивает значение устанавливаемого параметра даты или времени Каждое нажатие на кнопку DOWN уменьшает значение устанавливаемого параметра даты или времени
- Во время работы сигнализации будильника: Удержание любой кнопки в течении 1 секунды, отключает сигнализацию (без выполнения их действий, в любом режиме)
Код программы:
Работа кнопок, вывод и установка времени, описывались в уроке 18, в этом уроке рассмотрим работу будильника:
В начале кода добавляем две константы: PIN_alarm_TONE и PIN_alarm_LED, указывающие номера выводов зуммера и светодиода. А также добавляем четыре переменные: VAR_alarm_MIN, VAR_alarm_HOUR, VAR_alarm_FLAG1 и VAR_alarm_FLAG2.
- VAR_alarm_MIN - переменная в которой хранится значение минут, при котором сработает будильник (по умолчанию 0 минут)
- VAR_alarm_HOUR - переменная в которой хранится значение часов, при котором сработает будильник (по умолчанию 0 часов)
- VAR_alarm_FLAG1 - флаг разрешения работы будильника, false - не активен, true - активен (по умолчанию true - активен)
- VAR_alarm_FLAG2 - флаг указывающий на то, что будильник сработал "сигнализация" (по умолчанию false - не сработал)
Последняя переменная которую мы добавили - MAS_alarm_SYM, она содержит изображение символа будильника для вывода на дисплей.
В функции loop, после вывода информации на дисплей, добавляем проверку: не пора ли включить будильник?
void loop(){
if(millis()%1000==0){ // если прошла 1 секунда
...
...
// проверка будильника
if(VAR_alarm_FLAG1){ // если будильник включён
if(time.seconds==00){ // если в текущем времени 0 секунд
if(time.minutes==VAR_alarm_MIN){ // если совпали минуты
if(time.Hours==VAR_alarm_HOUR){ // если совпали часы
VAR_alarm_FLAG2=true; // устанавливаем флаг разрешающий совершение действий будильника (сигнализация)
}
}
}
}else{VAR_alarm_FLAG2=false;} // если будильник выключен, то сбрасываем флаг разрешающий совершение действий будильника (сигнализация)
if(VAR_alarm_FLAG2){Func_alarm_action();}// запускаем действия будильника
}
Func_buttons_control(); // передаём управление кнопкам
}
- если будильник включён (установлен флаг VAR_alarm_FLAG1)
- если в текущем времени 0 секунд (time.seconds==00)
- если количество минут текущего времени (time.minutes) равно количеству минут установленных в будильнике (VAR_alarm_MIN)
- если количество часов текущего времени (time.Hours) равно количеству часов установленных в будильнике (VAR_alarm_HOUR) то устанавливаем флаг VAR_alarm_FLAG2 (указывающий на то, что будильник сработал)
- если установлен флаг VAR_alarm_FLAG2, то запускаем действия будильника (действия описаны в функции Func_alarm_action) Так как проверка будильника и запуск функции Func_alarm_action() находится внутри условия if(millis()%1000==0){...}, то действия будильника будут выполняться один раз в секунду.
Теперь всё готово для создания полного кода:
// Подключаем библиотеки:
#include <Wire.h> // подключаем библиотеку для работы с шиной I2C
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для работы с LCD дисплеем
#include <iarduino_RTC.h> // подключаем библиотеку для работы с RTC модулем
LiquidCrystal_I2C lcd(0x27,16,2); // объявляем переменную для работы с LCD дисплеем, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2)
iarduino_RTC time(RTC_DS1307); // объявляем переменную для работы с RTC модулем, указывая название модуля
// Объявляем переменные и константы:
const uint8_t PIN_button_SET = 2; // указываем номер вывода arduino, к которому подключена кнопка SET
const uint8_t PIN_button_UP = 3; // указываем номер вывода arduino, к которому подключена кнопка UP
const uint8_t PIN_button_DOWN = 4; // указываем номер вывода arduino, к которому подключена кнопка DOWN
const uint8_t PIN_alarm_TONE = 5; // указываем номер вывода arduino, к которому подключён зуммер будильника
const uint8_t PIN_alarm_LED = 13; // указываем номер вывода arduino, к которому подключён светодиод
uint8_t VAR_mode_SHOW = 1; // режим вывода: 1-время 2-дата 3-время_будильника
uint8_t VAR_mode_SET = 0; // режим установки времени: 0-нет 1-сек 2-мин 3-час 4-день 5-мес 6-год 7-день_недели 8-мин_будильника 9-час_будильника
uint8_t VAR_alarm_MIN = 0; // будильник минуты
uint8_t VAR_alarm_HOUR = 0; // будильник часы
bool VAR_alarm_FLAG1 = true; // будильник разрешение работы
bool VAR_alarm_FLAG2 = false; // будильник совершение действий (сигнализация)
byte MAS_alarm_SYM[8]={B00000,B01110,B10101,B10111,B10001,B01110,B00000,B00000}; // символ будильника для отображения на дисплее
void setup() {
pinMode(PIN_button_SET, INPUT); // устанавливаем режим работы вывода PIN_button_SET, как "вход"
pinMode(PIN_button_UP, INPUT); // устанавливаем режим работы вывода PIN_button_UP, как "вход"
pinMode(PIN_button_DOWN, INPUT); // устанавливаем режим работы вывода PIN_button_DOWN, как "вход"
pinMode(PIN_alarm_TONE, OUTPUT); // устанавливаем режим работы вывода PIN_alarm_TONE, как "выход"
pinMode(PIN_alarm_LED, OUTPUT); // устанавливаем режим работы вывода PIN_alarm_LED, как "выход"
digitalWrite(PIN_alarm_TONE, LOW); // устанавливаем уровень логического «0» на выводе PIN_alarm_TONE
digitalWrite(PIN_alarm_LED, LOW); // устанавливаем уровень логического «0» на выводе PIN_alarm_LED
delay(300); // ждем 300мс
time.begin(); // инициируем RTC модуль
lcd.init(); // инициируем LCD дисплей
lcd.backlight(); // включаем подсветку LCD дисплея
lcd.createChar(1, MAS_alarm_SYM); // загружаем символ будильника под номером 1
}
void loop(){
if(millis()%1000==0){ // если прошла 1 секунда
if(VAR_mode_SET==0){ // если дата/время/будильник выводятся, а не устанавливаются
lcd.setCursor(0, 0); // устанавливаем курсор в позицию: столбец 0, строка 0
lcd.print("iArduino.ru"); // выводим текст "iArduino.ru"
lcd.setCursor(15, 0); // устанавливаем курсор в позицию: столбец 15, строка 0
lcd.print(VAR_alarm_FLAG1?"\1":" "); // выводим значёк будильника
}else{ // если дата/время/будильник устанавливаются, а не выводятся
lcd.setCursor(0, 0); // устанавливаем курсор в позицию: столбец 0, строка 0
if(VAR_mode_SHOW==1){lcd.print("Set time:" );}
if(VAR_mode_SHOW==2){lcd.print("Set date:" );}
if(VAR_mode_SHOW==3){lcd.print("Set alarm:");}
}
if(VAR_mode_SHOW==1){ // если установлен режим вывода времени
lcd.setCursor(0, 1); // устанавливаем курсор в позицию: столбец 0, строка 1
lcd.print(time.gettime("H:i:s")); // выводим время
}
if(VAR_mode_SHOW==2){ // если установлен режим вывода даты
lcd.setCursor(0, 1); // устанавливаем курсор в позицию: столбец 0, строка 1
lcd.print(time.gettime("d-m-Y D")); // выводим дату
}
if(VAR_mode_SHOW==3){ // если установлен режим вывода будильника
lcd.setCursor(0, 1); // устанавливаем курсор в позицию: столбец 0, строка 1
if(VAR_mode_SET==0){lcd.print("Alarm ");}
time.gettime(); // обновляем значение переменной time.seconds, для "мигания" устанавливаемым параметром будильника
if(VAR_mode_SET==9&&time.seconds%2){lcd.print(" ");}else{if(VAR_alarm_HOUR<10){lcd.print("0");} lcd.print(VAR_alarm_HOUR);}
lcd.print(":");
if(VAR_mode_SET==8&&time.seconds%2){lcd.print(" ");}else{if(VAR_alarm_MIN<10){ lcd.print("0");} lcd.print(VAR_alarm_MIN);}
}
delay(1); // приостанавливаем на 1 мс, чтоб не выводить время несколько раз за 1мс
// проверка будильника
if(VAR_alarm_FLAG1){ // если будильник включён
if(time.seconds==00){ // если в текущем времени 0 секунд
if(time.minutes==VAR_alarm_MIN){ // если совпали минуты
if(time.Hours==VAR_alarm_HOUR){ // если совпали часы
VAR_alarm_FLAG2=true; // устанавливаем флаг разрешающий совершение действий будильника (сигнализация)
}
}
}
}else{VAR_alarm_FLAG2=false;} // если будильник выключен, то сбрасываем флаг разрешающий совершение действий будильника (сигнализация)
if(VAR_alarm_FLAG2){Func_alarm_action();}// запускаем действия будильника
}
Func_buttons_control(); // передаём управление кнопкам
}
// Функция управления кнопками:
void Func_buttons_control(){
uint8_t i=0;
time.blinktime(VAR_mode_SET); // мигаем устанавливаемым параметром (если VAR_mode_SET больше 0)
//Если часы находятся в режиме установки даты/времени
if(VAR_mode_SET){
// Если нажата кнопка UP
if(digitalRead(PIN_button_UP )){
while(digitalRead(PIN_button_UP)){delay(50);} // ждём пока мы не отпустим кнопку UP
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
switch (VAR_mode_SET){ // инкремент (увеличение) устанавливаемого значения
/* сек */ case 1: time.settime(0, -1, -1, -1, -1, -1, -1); break;
/* мин */ case 2: time.settime(-1, (time.minutes==59?0:time.minutes+1), -1, -1, -1, -1, -1); break;
/* час */ case 3: time.settime(-1, -1, (time.Hours==23?0:time.Hours+1), -1, -1, -1, -1); break;
/* дни */ case 4: time.settime(-1, -1, -1, (time.day==31?1:time.day+1), -1, -1, -1); break;
/* мес */ case 5: time.settime(-1, -1, -1, -1, (time.month==12?1:time.month+1), -1, -1); break;
/* год */ case 6: time.settime(-1, -1, -1, -1, -1, (time.year==99?0:time.year+1), -1); break;
/* д.н.*/ case 7: time.settime(-1, -1, -1, -1, -1, -1, (time.weekday==6?0:time.weekday+1) ); break;
/* м.б.*/ case 8: VAR_alarm_MIN =VAR_alarm_MIN ==59?0:VAR_alarm_MIN +1; break;
/* ч.б.*/ case 9: VAR_alarm_HOUR=VAR_alarm_HOUR==23?0:VAR_alarm_HOUR+1; break;
}
}
}
// Если нажата кнопка DOWN
if(digitalRead(PIN_button_DOWN)){
while(digitalRead(PIN_button_DOWN)){delay(50);} // ждём пока мы её не отпустим
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
switch (VAR_mode_SET){ // декремент (уменьшение) устанавливаемого значения
/* сек */ case 1: time.settime(0, -1, -1, -1, -1, -1, -1); break;
/* мин */ case 2: time.settime(-1, (time.minutes==0?59:time.minutes-1), -1, -1, -1, -1, -1); break;
/* час */ case 3: time.settime(-1, -1, (time.Hours==0?23:time.Hours-1), -1, -1, -1, -1); break;
/* дни */ case 4: time.settime(-1, -1, -1, (time.day==1?31:time.day-1), -1, -1, -1); break;
/* мес */ case 5: time.settime(-1, -1, -1, -1, (time.month==1?12:time.month-1), -1, -1); break;
/* год */ case 6: time.settime(-1, -1, -1, -1, -1, (time.year==0?99:time.year-1), -1); break;
/* д.н.*/ case 7: time.settime(-1, -1, -1, -1, -1, -1, (time.weekday==0?6:time.weekday-1) ); break;
/* м.б.*/ case 8: VAR_alarm_MIN =VAR_alarm_MIN ==0?59:VAR_alarm_MIN -1; break;
/* ч.б.*/ case 9: VAR_alarm_HOUR=VAR_alarm_HOUR==0?23:VAR_alarm_HOUR-1; break;
}
}
}
// Если нажата кнопка SET
if(digitalRead(PIN_button_SET)){
while(digitalRead(PIN_button_SET)){ // ждём пока мы её не отпустим
delay(10);
if(i<200){i++;}else{lcd.clear();} // фиксируем, как долго удерживается кнопка SET, если дольше 2 секунд, то стираем экран
}
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
if(i<200){ // если кнопка SET удерживалась меньше 2 секунд
VAR_mode_SET++; // переходим к следующему устанавливаемому параметру
if(VAR_mode_SHOW==1 && VAR_mode_SET>3){VAR_mode_SET=1;} // возвращаемся к первому устанавливаемому параметру
if(VAR_mode_SHOW==2 && VAR_mode_SET>7){VAR_mode_SET=4;} // возвращаемся к первому устанавливаемому параметру
if(VAR_mode_SHOW==3 && VAR_mode_SET>9){VAR_mode_SET=8;} // возвращаемся к первому устанавливаемому параметру
}else{ // если кнопка SET удерживалась дольше 2 секунд, то требуется выйти из режима установки даты/времени
VAR_mode_SET=0; // выходим из режима установки даты/времени
}
}
}
//Если часы находятся в режиме вывода даты/времени
}else{
// Если нажата кнопка UP
if(digitalRead(PIN_button_UP )){
while(digitalRead(PIN_button_UP)){delay(50);} // ждём пока мы её не отпустим
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
if(VAR_mode_SHOW==3){VAR_alarm_FLAG1=VAR_alarm_FLAG1?0:1;} // если установлен режим вывода будильника, то включаем/выключаем будильник
}
}
// Если нажата кнопка DOWN
if(digitalRead(PIN_button_DOWN)){
while(digitalRead(PIN_button_DOWN)){delay(50);} // ждём пока мы её не отпустим
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
if(VAR_mode_SHOW==3){VAR_alarm_FLAG1=VAR_alarm_FLAG1?0:1;} // если установлен режим вывода будильника, то включаем/выключаем будильник
}
}
// Если нажата кнопка SET
if(digitalRead(PIN_button_SET)){
while(digitalRead(PIN_button_SET)){delay(10); // ждём пока мы её не отпустим
if(i<200){i++;}else{lcd.clear();} // фиксируем, как долго удерживается кнопка SET, если дольше 2 секунд, то стираем экран
}
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
if(i<200){ // если кнопка SET удерживалась меньше 2 секунд
lcd.clear(); // стираем экран
VAR_mode_SHOW++; if(VAR_mode_SHOW>3){VAR_mode_SHOW=1;} // меняем режим вывода: дата/время/будильник
}else{ // если кнопка SET удерживалась дольше 2 секунд, то требуется перейти в режим установки даты/времени
if(VAR_mode_SHOW==1){VAR_mode_SET=1;} // если установлен режим вывода времени, то устанавливаемый параметр - секунды
if(VAR_mode_SHOW==2){VAR_mode_SET=4;} // если установлен режим вывода даты, то устанавливаемый параметр - день
if(VAR_mode_SHOW==3){VAR_mode_SET=8;} // если установлен режим вывода будильника, то устанавливаемый параметр - минуты_будильника
}
}
}
}
}
// Функция выполняющая действия будильника:
void Func_alarm_action(){
digitalWrite(PIN_alarm_LED, HIGH);
tone(PIN_alarm_TONE, 2000); delay(100); noTone(PIN_alarm_TONE); delay(100);
tone(PIN_alarm_TONE, 2000); delay(100); noTone(PIN_alarm_TONE); delay(100);
tone(PIN_alarm_TONE, 2000); delay(100); noTone(PIN_alarm_TONE);
digitalWrite(PIN_alarm_LED, LOW);
}
Разберемся в коде действий будильника:
Действия будильника описаны в функции Func_alarm_action().
В этой функции мы включаем светодиод, далее подаём три коротких звуковых сигнала (с частотой 2000Гц, длительностью и паузой 100мс), после чего выключаем светодиод.
Если Вам необходимо выполнить действие будильника однократно, а не каждую секунду после его срабатывания, то начните выполнение действий со сброса флага VAR_alarm_FLAG2, присвоив ему значение false.
Ссылки:
Комплект для повторения проекта
Что понадобится
Это быстрый ориентир по основным модулям и деталям. Полный список для повторения проекта смотрите в самой статье.
14 позиций
Часы реального времени RTC DS1307Z (Trema-модуль)
Электронный энергонезависимый хронометр на чипе DS1307Z
Открыть в iArduino
Кнопка, красная (Trema-модуль)
Тактовая кнопка, которая может служить источником сигналов (команд) для Ваших проектов
Открыть в iArduino
Символьный дисплей LCD1602 I²C (Зелёная подсветка)
Текстовый экран с управлением по I²C на 2 строки по 16 символов с чёрным текстом на зелёной подсветке
Открыть в iArduino
Arduino Uno R3 (USB ATmega16U2)
Платформа c микроконтроллером ATmega328P на ядре AVR с чипом USB ATmega16U2 для разработки электронных устройств на языке C++
Открыть в iArduino
Символьный дисплей LCD1602 I²C (Синяя подсветка)
Текстовый экран с управлением по I²C на 2 строки по 16 символов с белым текстом на синей подсветке
Открыть в iArduino
Trema Shield
Плата расширения для удобного подключения периферийных устройств
Открыть в iArduino
i2C Hub
Будет полезен в проектах с большим количеством устройств с интерфейсом I2C
Открыть в iArduino
Шлейф Dupont «Мама – Мама» (4 pin, 20 см)
Шлейф из четырёх проводов длиной 20 см с коннекторами Dupont Female
Открыть в iArduino
Зуммер (Trema-модуль)
Позволяет излучать звук определённой тональности (частоты).
Открыть в iArduino
Светодиод - белый (Trema-модуль)
Удобно использовать в качестве светового индикатора
Открыть в iArduino
Светодиод - синий (Trema-модуль)
синий
Открыть в iArduino
Светодиод - красный (Trema-модуль)
красный
Открыть в iArduino
Светодиод - оранжевый (Trema-модуль)
оранжевый
Открыть в iArduino
Светодиод - зеленый (Trema-модуль)
зелёный
Открыть в iArduino
