В этом уроке мы научимся не только выводить, но и устанавливать время RTC модуля при помощи трёх кнопок.
Нам понадобится:
- 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шт.
Для реализации проекта нам необходимо установить библиотеки:
- Библиотека 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.
Код программы:
При подключении библиотеки «iarduino_RTC» нужно указать, с каким модулем ей работать, в данном случае это модуль Trema на базе чипа DS1307:
#include <iarduino_RTC.h> // подключаем библиотеку для работы с RTC модулем iarduino_RTC time(RTC_DS1307); // объявляем переменную time для работы с библиотекой, указывая название модуля RTC_DS1307 void setup() { time.begin(); // инициируем RTC модуль }
Аналогичный алгоритм действий при подключении библиотеки «LiquidCrystal_I2C» для работы с LCD дисплеем LCD1602 IIC/I2C(синий) или LCD1602 IIC/I2C(зелёный):
#include <Wire.h> // подключаем библиотеку для работы с шиной I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для работы с LCD дисплеем LiquidCrystal_I2C lcd(0x27,16,2); // объявляем переменную lcd для работы с LCD дисплеем, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2) void setup() { lcd.init(); // инициируем LCD дисплей lcd.backlight(); // включаем подсветку LCD дисплея }
Осталось подключить 3 кнопки: «SET», «UP» и «DOWN». Для этого им нужно назначить номера выводов и указать, что эти выводы работают как вход:
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 void setup() { pinMode(PIN_button_SET, INPUT); // устанавливаем режим работы вывода кнопки, как "вход" pinMode(PIN_button_UP, INPUT); // устанавливаем режим работы вывода кнопки, как "вход" pinMode(PIN_button_DOWN, INPUT); // устанавливаем режим работы вывода кнопки, как "вход" }
В библиотеке «iarduino_RTC», для работы с датой и временем реализованы две функции: settime() - установка и gettime() - получение времени.
Установка времени:
time.settime(0,1,2,3,4,5,6); // установить время: 00 сек, 01 мин, 02 часа, 03 день, 04 месяц, 05 год, 06 день недели - суббота // Если указать отрицательное значение, то соответствующий параметр останется без изменений. // Например: time.settime(10,20,-1,-1,-1,-1,-1); приведёт к изменению секунд и минут, а часы и дата останутся без изменений
Получение времени:
time.gettime("d-m-Y, H:i:s, D"); // получить время в виде строки. Получим: "03-04-2005, 02:01:00, Sat" // Функция получает строку с символами, заменяет символы на дату и время, и возвращает строку // Какие символы на что заменяются можно посмотреть в файле iarduino_RTC.h
В библиотеке «iarduino_RTC» доступны 9 числовых переменных: seconds, minutes, hours, Hours, midday, day, weekday, month и year, значения которых обновляются после каждого вызова функции gettime(). Эти переменные мы будим использовать для изменения даты и времени.
int i = time.month; // если в часах установлен месяц май, то i будет равно 5 (пятый месяц)
Еще одна функция библиотеки «iarduino_RTC», которая нам понадобится, это blinktime(), она заставляет функцию gettime(), мигать одним из параметров времени (0 - не мигать, 1 - мигать секундами, 2 - мигать минутами, 3 - мигать часами, 4 - мигать днями и т.д.).
time.blinktime(4); // функция gettime() будет выводить строки с "мигающими" днями
И последнее, о чем надо позаботиться перед созданием кода программы - это алгоритм работы кнопок и определение переменных
Алгоритм работы кнопок следующий:
- В режиме вывода даты или времени (обычный режим):
- Кратковременное нажатие на кнопку SET переключает вывод даты и вывод времени
- Удержание кнопки SET переводит часы в режим установки даты или времени (зависит от того, что было на дисплее, дата или время)
- Кнопки UP и DOWN неактивны.
- В режиме установки даты или времени:
- Кратковременное нажатие на кнопку SET - переход между устанавливаемыми параметрами (сек, мин, час, дни, мес, год, д.н.)
- Удержание кнопки SET выводит часы из режима установки
- Каждое нажатие на кнопку UP увеличивает значение устанавливаемого параметра даты или времени
- Каждое нажатие на кнопку DOWN уменьшает значение устанавливаемого параметра даты или времени
Исходя из алгоритма, нам понадобятся две переменные, назовем их: VAR_mode_SHOW и VAR_mode_SET. Первая будет указывать режим вывода (1-выводим_время, 2-выводим_дату). Вторая, будет указывать режим установки времени (0-нет, 1-сек, 2-мин, 3-час, 4-день, 5-мес, 6-год, 7-д.н.).
Теперь всё готово для создания полного кода:
// Подключаем библиотеки: #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 uint8_t VAR_mode_SHOW = 1; // режим вывода: 1-время 2-дата uint8_t VAR_mode_SET = 0; // режим установки времени: 0-нет 1-сек 2-мин 3-час 4-день 5-мес 6-год 7-день_недели void setup() { pinMode(PIN_button_SET, INPUT); // устанавливаем режим работы вывода кнопки, как "вход" pinMode(PIN_button_UP, INPUT); // устанавливаем режим работы вывода кнопки, как "вход" pinMode(PIN_button_DOWN, INPUT); // устанавливаем режим работы вывода кнопки, как "вход" delay(300); // ждем 300мс time.begin(); // инициируем RTC модуль lcd.init(); // инициируем LCD дисплей lcd.backlight(); // включаем подсветку LCD дисплея } void loop(){ if(millis()%1000==0){ // если прошла 1 секунда lcd.setCursor(0, 0); // устанавливаем курсор в позицию: столбец 0, строка 0 lcd.print("iArduino.ru"); // выводим текст "iArduino.ru" lcd.setCursor(0, 1); // устанавливаем курсор в позицию: столбец 0, строка 1 if(VAR_mode_SHOW==1){ // если установлен режим вывода времени lcd.print(time.gettime("H:i:s")); // выводим время } if(VAR_mode_SHOW==2){ // если установлен режим вывода даты lcd.print(time.gettime("d-m-Y D")); // выводим дату } delay(1); // приостанавливаем на 1 мс, чтоб не выводить время несколько раз за 1мс } 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 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; } } // Если нажата кнопка DOWN if(digitalRead(PIN_button_DOWN)){ while(digitalRead(PIN_button_DOWN)){delay(50);} // ждём пока мы её не отпустим 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; } } // Если нажата кнопка SET if(digitalRead(PIN_button_SET)){ while(digitalRead(PIN_button_SET)){ // ждём пока мы её не отпустим delay(10); if(i<200){i++;}else{lcd.clear();} // фиксируем, как долго удерживается кнопка SET, если дольше 2 секунд, то стираем экран } 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;} // возвращаемся к первому устанавливаемому параметру }else{ // если кнопка SET удерживалась дольше 2 секунд, то требуется выйти из режима установки даты/времени VAR_mode_SET=0; // выходим из режима установки даты/времени } } //Если часы находятся в режиме вывода даты/времени }else{ // Если нажата кнопка SET if(digitalRead(PIN_button_SET)){ while(digitalRead(PIN_button_SET)){delay(10); // ждём пока мы её не отпустим if(i<200){i++;}else{lcd.clear();} // фиксируем, как долго удерживается кнопка SET, если дольше 2 секунд, то стираем экран } if(i<200){ // если кнопка SET удерживалась меньше 2 секунд lcd.clear(); // стираем экран VAR_mode_SHOW=VAR_mode_SHOW==1?2:1; // меняем режим вывода: дата/время }else{ // если if(VAR_mode_SHOW==1){VAR_mode_SET=1;} // если установлен режим вывода времени, то устанавливаемый параметр - секунды if(VAR_mode_SHOW==2){VAR_mode_SET=4;} // если установлен режим вывода даты, то устанавливаемый параметр - день } } } }
Разберемся в данном коде:
- сначала мы подключили библиотеки Wire.h, LiquidCrystal_I2C.h и iarduino_RTC.h
- далее объявили константы: PIN_button_SET=2, PIN_button_UP=3, PIN_button_DOWN=4, указав им номера выводов с кнопками
- объявили две переменные: VAR_mode_SHOW=1 (режим вывода времени) и VAR_mode_SET=0 (без установки времени)
- в функции setup(): указали выводам с кнопками работать как вход, инициировали модули LCD и RTC, включили подсветку дисплея
- в функции loop(): циклически выполняем следующую последовательность:
- каждую секунду выводим текст "iArduino"
- каждую секунду, если переменная VAR_mode_SHOW равна 1, то выводим время: lcd.print(time.gettime("H:i:s"));
- каждую секунду, если переменная VAR_mode_SHOW равна 2, то выводим дату: lcd.print(time.gettime("d-m-Y D"));
- каждую секунду, приостанавливаем выполнение на 1мс
- при каждом цикле вызываем функцию Func_buttons_control(); которая следит за нажатием кнопок
- в функции Func_buttons_control(): выполняем следующую последовательность:
- если VAR_mode_SET больше 0, то мигаем устанавливаемым параметром time.blinktime(VAR_mode_SET);
- проверяем не находимся ли мы в режиме установки даты/времени
- в любом случае проверяем не нажаты ли кнопки: if(digitalRead(PIN_button_???)){...}
- если кнопки нажаты, то ждем пока они не будут отпущены: while(digitalRead(PIN_button_???)){...}
- после того как кнопка была отпущена, выполняем действия связанные с её предназначением в текущем режиме
Обсуждение