Главная chevron_right Наши уроки chevron_right Arduino chevron_right Урок 18. Подключение RTC часы реального времени с кнопками

Урок 18. Подключение RTC часы реального времени с кнопками

Учимся устанавливать время на RTC-модуле DS1307 с помощью трёх кнопок и выводить дату и время на LCD1602 через I2C. Подключаем всё к Arduino с библиотеками iarduino_RTC и Liquid...

Видео-обложка запускается при наведении

В этом уроке мы научимся не только выводить, но и устанавливать время RTC модуля при помощи трёх кнопок.

Нам понадобится:

Для реализации проекта нам необходимо установить библиотеки:

  • Библиотека iarduino_RTC (для подключения RTC часов реального времени DS1302, DS1307, DS3231)
  • Библиотека LiquidCrystal_I2C_V112 (для подключения дисплеев LCD1602 по шине I2C)

О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.

Видео

Схема подключения:

Подключение модулей RTC и LCD, данного урока, осуществляется к аппаратным выводам SDA, и SCL.

RTC модуль Trema на базе чипа DS1307 / LCD дисплей на базе чипа LCD1602Arduino Uno
GNDGND
Vcc+5V
SDA (Serial DAta)A4
SCL (Serial CLock)A5

подключение кнопок: кнопка «SET» к выводу 2, кнопка «UP» к выводу 3 и кнопка «DOWN» к выводу 4.

Схема подключения RTC к Arduino Uno

Код программы:

При подключении библиотеки «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_???)){...} после того как кнопка была отпущена, выполняем действия связанные с её предназначением в текущем режиме

Ссылки:

Комплект для повторения проекта

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

Это быстрый ориентир по основным модулям и деталям. Полный список для повторения проекта смотрите в самой статье.

7 позиций
Часы реального времени RTC DS1307Z (Trema-модуль) Электронный энергонезависимый хронометр на чипе DS1307Z Открыть в iArduino Символьный дисплей LCD1602 I²C (Синяя подсветка) Текстовый экран с управлением по I²C на 2 строки по 16 символов с белым текстом на синей подсветке Открыть в iArduino Символьный дисплей LCD1602 I²C (Зелёная подсветка) Текстовый экран с управлением по I²C на 2 строки по 16 символов с чёрным текстом на зелёной подсветке Открыть в iArduino Trema Shield Плата расширения для удобного подключения периферийных устройств Открыть в iArduino i2C Hub Будет полезен в проектах с большим количеством устройств с интерфейсом I2C Открыть в iArduino Кнопка, красная (Trema-модуль) Тактовая кнопка, которая может служить источником сигналов (команд) для Ваших проектов Открыть в iArduino Шлейф Dupont «Мама – Мама» (4 pin, 20 см) Шлейф из четырёх проводов длиной 20 см с коннекторами Dupont Female Открыть в iArduino
Все уроки Arduino