#12 Эксперимент “Будильник”
На этом занятии мы будем работать с очень полезным модулем – часами реального времени DS1302. Этот модуль позволит нашим устройствам ориентироваться в текущем времени, а значит у нас появится возможность писать скрипты, выполняющиеся по расписанию. В качестве примера мы соберём простейшее устройство, которое будет выполнять роль будильника.
Перед выполнением эксперимента прочтите:
СБОРКА УСТРОЙСТВА НА МАКЕТНОЙ ПЛАТЕ
Нам понадобятся следующие компоненты:
- Arduino Uno;
- USB-кабель для подключения к компьютеру;
- Беспаечная макетная плата;
- Модуль часов реального времени DS1302;
- 1 светодиод любого цвета;
- 1 резистор номиналом 220 Ом;
- 1 резистор номиналом 10 кОм;
- 5 соединительных проводов типа “папа-мама” различных цветов;
- 3 соединительных провода типа папа-папа различных цветов.
Соберите устройство по следующей схеме:
Соберите устройство по следующей схеме |
Обратите внимание:
- Пин GND модуля часов подключаем к земле через резистор на 10 кОм;
- Светодиод подключаем через резистор на 220 Ом;
- Важно! Если в вашем модуле отсутствует батарейка, установите её. Для модуля необходим элемент питания CR2032, это позволит модулю работать независимо от подключённого внешнего питания.
Для начала работы с модулем часов установим библиотеку <Iarduino_RTC>. На предыдущих занятия мы уже устанавливали библиотеки из .ZIP архивов. Для этого нужно:
- Скачать библиотеку по ссылке;
- Запустить Arduino IDE и выбрать [Скетч] → [Подключить библиотеку] → [Добавить .ZIP библиотеку], далее выбрать архив с названием Iarduino_RTC.zip и нажать [Открыть].
После установки библиотеки, мы можем приступить к настройке нашего модуля.
ПРОГРАММИРОВАНИЕ
Для начала, давайте настроим подключение нашего модуля, задав нужные параметры в функциях библиотеки:
#include <iarduino_RTC.h> // подключаем библиотеку // далее указываем тип модуля и пины Arduino к которым подключён модуль // модуль|RTS|CLK|DAT iarduino_RTC time(RTC_DS1302, 8, 6, 7); void setup() { } void loop(){ }
Если вы решите подключить модуль к другим пинам Arduino, не забудьте изменить их значения в коде программы.
Теперь нужно сообщить модулю текущее время, чтобы он получил “точку”, от которой он будет начинать отсчёт времени. Для этого загрузим в Arduino следующий скетч:
#include <iarduino_RTC.h> // подключаем библиотеку // далее указываем тип модуля и пины Arduino к которым подключён модуль // модуль|RTS|CLK|DAT iarduino_RTC time(RTC_DS1302, 8, 6, 7); void setup() { delay(300); // небольшая задержка перед началом работы Serial.begin(9600); // инициализируем последовательный порт time.begin(); // инициализируем работу модуля time.settime(0,5,22,11,1,19,5); // задаём время, дату и текущий день недели // В нашем случае 0 сек, 5 мин, 22 часа, 11, января, 2019 года, пятница } void loop(){ if(millis()%1000==0){ // если прошла 1 секунда Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время в порт delay(1); // приостанавливаем на 1 мс, чтоб не выводить время несколько раз за 1 мс } }
Внимание! В качестве текущего времени, даты и дня недели, сообщите модулю актуальные время, дату и день недели, т.е. ваши время, дату и день недели.
Обратите внимание: мы не только сообщили модулю текущее время, но и сразу же инициализировали последовательный порт, чтобы убедиться в том, что модуль “принял” наши данные и “запомнил” их. Откройте монитор последовательного порта и убедитесь в том, что модуль исправно отсчитывает текущее время, корректно отображает дату и день недели. Для вывода информации будем использовать плагин SerialProjector:
Всё, модуль настроен и работает, далее, можно удалить из раздела [void setup] команду:
time.settime();
Это необходимо для того, чтобы при каждом запуске Arduino, модуль не сбрасывал время до начального, заданного нами ранее значения. На этом первоначальную настройку модуля можно считать оконченной. Теперь осталось разобраться с деталями:
- Необходимо заставить Arduino отображать день недели на русском;
- Добавить в код функцию будильника.
Русификация отображения дня недели:
С помощью команды:
time.gettime();
с нужными параметрами в скобках, мы можем получать только нужные нам значения текущего времени, например только значение минут, секнд, текущее число или день недели. Полный список возможных параметров приведён ниже:
// Функция gettime("строка с параметрами"): // функция получает и выводит строку заменяя описанные ниже символы на текущее время // пример: gettime("d-m-Y, H:i:s, D"); ответит строкой "01-10-2015, 14:00:05, Thu" // пример: gettime("s"); ответит строкой "05" // указанные символы идентичны символам для функции date() в PHP // s секунды от 00 до 59 (два знака) // i минуты от 00 до 59 (два знака) // h часы в 12-часовом формате от 01 до 12 (два знака) // H часы в 24-часовом формате от 00 до 23 (два знака) // d день месяца от 01 до 31 (два знака) // w день недели от 0 до 6 (один знак: 0-воскресенье, 6-суббота) // D день недели наименование от Mon до Sun (три знака: Mon Tue Wed Thu Fri Sat Sun) // m месяц от 01 до 12 (два знака) // M месяц наименование от Jan до Dec (три знака: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) // Y год от 2000 до 2099 (четыре знака) // y год от 00 до 99 (два знака) // a полдень am или pm (два знака, в нижнем регистре) // A полдень AM или PM (два знака, в верхнем регистре) // строка не должна превышать 50 символов // // если требуется получить время в виде цифр, то можно вызвать функцию gettime() без параметра, после чего получить время из переменных // seconds секунды 0-59 // minutes минуты 0-59 // hours часы 1-12 // Hours часы 0-23 // midday полдень 0-1 (0-am, 1-pm) // day день месяца 1-31 // weekday день недели 0-6 (0-воскресенье, 6-суббота) // month месяц 1-12 // year год 0-99
Для того, чтобы “русифицировать” название дня недели, мы должны получить его отдельно, заменить на русское обозначение и дописать в строку с общим временем. Это мы можем сделать следующим образом:
#include <iarduino_RTC.h> // подключаем библиотеку // далее указываем тип модуля и пины Arduino к которым подключён модуль // модуль|RTS|CLK|DAT iarduino_RTC time(RTC_DS1302, 8, 6, 7); void setup() { delay(300); // небольшая задержка перед началом работы Serial.begin(9600); // инициализируем последовательный порт time.begin(); // инициализируем работу модуля } void loop(){ if(millis()%1000==0){ // если прошла 1 секунда Serial.print(time.gettime("d-m-Y, H:i:s, ")); // выводим время и дату без дня недели в порт String daynumb=time.gettime("D"); String curday; if (daynumb=="Sun"){curday="Воскресение";} // русифицируем дни недели if (daynumb=="Mon"){curday="Понедельник";} if (daynumb=="Tue"){curday="Вторник";} if (daynumb=="Wed"){curday="Среда";} if (daynumb=="Thu"){curday="Четверг";} if (daynumb=="Fri"){curday="Пятница";} if (daynumb=="Sat"){curday="Суббота";} Serial.println(curday); // дописываем текущий день недели delay(1); // приостанавливаем на 1 мс, чтоб не выводить время несколько раз за 1 мс } }
Пример работы программы:
Делаем простейший будильник:
Наша задача: дополнить скетч таким образом, чтобы по наступлению определённого времени, светодиод, подключенный к Arduino начал мигать. Светодиод должен мигать 1 раз в секунду в течение 1 минуты. Это можно реализовать двумя способами. Способ первый – лёгкий, но не совсем корректный:
#include <iarduino_RTC.h> // подключаем библиотеку // далее указываем тип модуля и пины Arduino к которым подключён модуль // модуль|RTS|CLK|DAT iarduino_RTC time(RTC_DS1302, 8, 6, 7); int WakeUpHour = 23; // задаём значение часов для будильника int WakeUpMin = 37; // задаём значение минут для будильника void setup() { delay(300); // небольшая задержка перед началом работы Serial.begin(9600); // инициализируем последовательный порт time.begin(); // инициализируем работу модуля pinMode(9, OUTPUT); } void loop(){ if(millis()%1000==0){ // если прошла 1 секунда String daynumb=time.gettime("D"); String curday; if (daynumb=="Sun"){curday="Воскресение";} // русифицируем дни недели if (daynumb=="Mon"){curday="Понедельник";} if (daynumb=="Tue"){curday="Вторник";} if (daynumb=="Wed"){curday="Среда";} if (daynumb=="Thu"){curday="Четверг";} if (daynumb=="Fri"){curday="Пятница";} if (daynumb=="Sat"){curday="Суббота";} Serial.print(time.gettime("d-m-Y, H:i:s, "));// выводим время и дату в порт Serial.println(curday); // выводим день недели на русском в порт delay(1); // приостанавливаем на 1 мс, чтоб не выводить время несколько раз за 1 мс if ((time.Hours==WakeUpHour) && (time.minutes==WakeUpMin)){ // проверям - совпали ли значения часов и минут с нашими digitalWrite(9, HIGH); // мигаем светодиодом delay(500); digitalWrite(9, LOW); delay(500); } } }
Выставьте значения будильника на 2 минуты вперёд текущего времени и протестируйте его работу.
Вы заметили, что при срабатывании будильника, отображение времени в порте начало “притормаживать”? Это происходит из-за использования функции [delay();]. Она тормозит работу наших часов, т.к. пока действует пауза, программа как-бы замирает. Перепишем код нашего будильника так, чтобы он не влиял на работу самих часов. Для этого будем использовать значения времени взятые из часов реального времени:
#include <iarduino_RTC.h> // подключаем библиотеку // далее указываем тип модуля и пины Arduino к которым подключён модуль // модуль|RTS|CLK|DAT iarduino_RTC time(RTC_DS1302, 8, 6, 7); int WakeUpHour = 23; // задаём значение часов для будильника int WakeUpMin = 44; // задаём значение минут для будильника void setup() { delay(300); // небольшая задержка перед началом работы Serial.begin(9600); // инициализируем последовательный порт time.begin(); // инициализируем работу модуля pinMode(9, OUTPUT); } void loop(){ if(millis()%1000==0){ // если прошла 1 секунда String daynumb=time.gettime("D"); String curday; if (daynumb=="Sun"){curday="Воскресение";} // русифицируем дни недели if (daynumb=="Mon"){curday="Понедельник";} if (daynumb=="Tue"){curday="Вторник";} if (daynumb=="Wed"){curday="Среда";} if (daynumb=="Thu"){curday="Четверг";} if (daynumb=="Fri"){curday="Пятница";} if (daynumb=="Sat"){curday="Суббота";} Serial.print(time.gettime("d-m-Y, H:i:s, "));// выводим время и дату в порт Serial.println(curday); // выводим день недели на русском в порт delay(1); // приостанавливаем на 1 мс, чтоб не выводить время несколько раз за 1 мс if ((time.Hours==WakeUpHour) && (time.minutes==WakeUpMin)){ // проверям - совпали ли значения часов и минут с нашими if (time.seconds%2==1) {digitalWrite(9, HIGH);} // и мигаем светодиодом else {digitalWrite(9, LOW); } } digitalWrite(9, LOW); // окончательно отключаем светодиод } }
Пояснение к участку кода:
if (time.seconds%2==1) {digitalWrite(9, HIGH);} else {digitalWrite(9, LOW); }
В первой строчке мы проверяем чему равняется остаток от деления нацело на 2 текущего значения секунды. Если он равен одному (например для значений 1, 3, 5 и остальных нечётных значений), то светодиод зажигается. В противном случае, если остаток от деления нацело равен нулю (например для значений 2, 4, 6 и остальных чётных), то светодиод гаснет.
Наш будильник готов!
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОГО ВЫПОЛНЕНИЯ
Задание 1:
Сделайте наш будильник действительно полезным! Замените светодиод на пьезодинамик и заставьте его издавать прерывистые сигналы в момент срабатывания будильника.
Задание 2:
Наш будильник не совсем автономен, т.к. мы не можем видеть текущее время без наличия компьютера. Добавьте в схему LCD-дисплей и выводите время на него. Кроме этого, в момент срабатывания будильника, на экран дисплея выведите сообщение “Wake Up!”.
Задание 3:
Добавьте в схему устройства кнопку и отключайте будильник при нажатии на неё.
Задание 4:
Заставьте ваш будильник проигрывать какую-либо мелодию при пробуждении! Кнопка отключения должна работать.
Задание 5*:
Продумайте способ, который позволит задавать время срабатывания будильника не внутри программы. Для этого можно использовать матричную клавиатуру, а вначале исполнения программы (в разделе void setup() вы можете запрашивать у пользователя значения часов и минут для срабатывания будильника);