Часы на Ардуино с OLED и DHT11

Еще один проект часов на Ардуино с дисплеем OLED i2c 128×64 и датчиком температуры и влажности воздуха DHT11 (можно заменить на датчик давления BMP180). Мы разместили сразу два варианта — с модулем часов реального времени RTC (время можно установить только в самой программе) и без модуля RTC (время настроить можно в любой момент). Оба варианта с функцией будильника.

Часы на OLED дисплее

Ардуино часы на OLED i2c с датчиком DHT11

Если вы используете плату Arduino Mega, то на этой плате порты SDA и SCL для расположены на 20 и 21 пине. У платы Arduino Nano распиновка такая же, как на Uno и дисплей подключается к портам A4 (SDA) и A5 (SCL). Кнопки подключаются к цифровым портам Arduino, сконфигурированных в режиме INPUT_PULLUP — при таком способе подключения можно считывать количество нажатий на кнопку.

Для этого проекта потребуется:

  • Arduino Uno / Arduino Nano / Arduino Mega
  • дисплей oled 128×64
  • датчик DHT11 / модуль RTC
  • 2 тактовые кнопки и пьезодинамик
  • макетная плата
  • провода «папа-мама», «папа-папа»
Часы Ардуино на OLED i2c с термометром
Часы Ардуино на OLED i2c с термометром
OLED i2c 0,96 Arduino Uno Arduino Nano Arduino Mega
GND GND GND GND
VDD 5V 5V 5V
SDA A4 A4 20
SCL A5 A5 21

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

Скетч. Часы на OLED дисплее без модуля RTC

#include "DHT.h"
DHT dht(2, DHT11);

#include "OLED_I2C.h"
OLED  myOLED(SDA, SCL, 8);

extern uint8_t SmallFont[];
extern uint8_t BigNumbers[];

// переменные для отсчета времени и будильника
byte SEC = 0;
byte MIN = 59;
byte HOUR = 7;
byte MIN_A = 0;
byte HOUR_A = 8;
unsigned long timer;

// переменные для считывания нажатия на кнопки
boolean button1WasUp = true;
boolean button2WasUp = true;
boolean button1IsUp;
boolean button2IsUp;

boolean alarm = true;
byte w, i;

void setup() {
  pinMode(9, INPUT_PULLUP);   // подключаем тактовые кнопки
  pinMode(8, INPUT_PULLUP);
  pinMode(5, OUTPUT);               // подключаем пьезодинамик
  dht.begin();
  myOLED.begin();
  timer = millis();
}

void loop() {
   int h = dht.readHumidity();
   int t = dht.readTemperature();
  
  // узнаем текущее состояние кнопки
  button1IsUp = digitalRead(9);
  button2IsUp = digitalRead(8);
 
  // если кнопка 1 нажата, заходим в настройки (цикл while)
  if (button1WasUp && !button1IsUp) {
    delay(10); button1IsUp = digitalRead(9);
    if (!button1IsUp) { SEC = 0; w = 1; } }
  button1WasUp = button1IsUp;
 
  // если кнопка 2 была нажата выключаем будильник
  if (button2WasUp && !button2IsUp) {
    delay(10); button2IsUp = digitalRead(8);
    if (!button2IsUp) { alarm = !alarm; } }
  button2WasUp = button2IsUp;

  // если прошло 1000 мс - прибавляем одну секунду
  if (millis() - timer > 1000) {
    timer = millis(); SEC++;
    // если прошло 59 секунд, прибавляем 1 минуту
    if (SEC > 59) { SEC = 0; MIN++; }
    // если прошло 59 минут, прибавляем 1 час
    if (MIN > 59) { MIN = 0; HOUR++; }
    if (HOUR > 23) { HOUR = 0; }
    // включение будильника в течении 1 минуты
    if (alarm == true && HOUR == HOUR_A && MIN == MIN_A && i < 60) { tone(5, 50); i++; }
    if (i >= 60) { noTone(5); alarm == false; i = 0; }

    myOLED.clrScr(); // очищаем дисплей
    myOLED.setFont(BigNumbers); // подключаем шрифт для цифр
    
    // выводим текущее время
    if (HOUR < 10) { myOLED.print("0" + String(HOUR) + "-", 8, 20); }
    if (HOUR >= 10) { myOLED.print(String(HOUR) + "-", 8, 20); }
    if (MIN < 10) { myOLED.print("0" + String(MIN) + "-", 50, 20); }
    if (MIN >= 10) { myOLED.print(String(MIN) + "-", 50, 20); }
    if (SEC < 10) { myOLED.print("0" + String(SEC), 92, 20); }
    if (SEC >= 10) { myOLED.print(String(SEC), 92, 20); }
  
    myOLED.setFont(SmallFont); // подключаем шрифт для текста
    
    // выводим состояние будильника 
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    
    // выводим температуру и влажность
    myOLED.print(String(t) + "' / " + String(h) + "% ", RIGHT, 55);
    myOLED.update();
    noTone(5);
  }

  while (w == 1) {
    myOLED.clrScr();
 
    myOLED.setFont(BigNumbers);
    if (HOUR > 23) { HOUR = 0; }
    if (HOUR < 10) { myOLED.print("0" + String(HOUR) + "-", 8, 20); }
    if (HOUR >= 10) { myOLED.print(String(HOUR) + "-", 8, 20); }
    if (MIN < 10) { myOLED.print("0" + String(MIN) + "-", 50, 20); }
    if (MIN >= 10) { myOLED.print(String(MIN) + "-", 50, 20); }
    myOLED.print("00", 92, 20);
    
    myOLED.setFont(SmallFont);
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    myOLED.print("HOUR SETTING", CENTER, 55);
    myOLED.update();

    button1IsUp = digitalRead(9);
    button2IsUp = digitalRead(8);
    // если кнопка 1 была нажата, переходим во 2 цикл while
    if (button1WasUp && !button1IsUp) {
      delay(10); button1IsUp = digitalRead(9);
      if (!button1IsUp) { w = 2; } }
    button1WasUp = button1IsUp;
    // если кнопка 2 была нажата, прибавляем 1 час
    if (button2WasUp && !button2IsUp) {
      delay(10); button2IsUp = digitalRead(8);
      if (!button2IsUp) { HOUR++; } }
    button2WasUp = button2IsUp;
  }

  while (w == 2) {
    myOLED.clrScr();
 
    myOLED.setFont(BigNumbers);
    if (MIN > 59) { MIN = 0;}
    if (HOUR < 10) { myOLED.print("0" + String(HOUR) + "-", 8, 20); }
    if (HOUR >= 10) { myOLED.print(String(HOUR) + "-", 8, 20); }
    if (MIN < 10) { myOLED.print("0" + String(MIN) + "-", 50, 20); }
    if (MIN >= 10) { myOLED.print(String(MIN) + "-", 50, 20); }
    myOLED.print("00", 92, 20);

    myOLED.setFont(SmallFont);
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    myOLED.print("MINUTE SETTING", CENTER, 55);
    myOLED.update();

    button1IsUp = digitalRead(9);
    button2IsUp = digitalRead(8);
    // если кнопка 1 была нажата, переходим в 3 цикл while
    if (button1WasUp && !button1IsUp) {
      delay(10); button1IsUp = digitalRead(9);
      if (!button1IsUp) { w = 3; } }
    button1WasUp = button1IsUp;
    // если кнопка 2 была нажата, прибавляем 1 минуту
    if (button2WasUp && !button2IsUp) {
      delay(10); button2IsUp = digitalRead(8);
      if (!button2IsUp) { MIN++; } }
    button2WasUp = button2IsUp;
  }

  while (w == 3) {
    myOLED.clrScr();
 
    myOLED.setFont(BigNumbers);
    if (MIN_A > 59) { MIN_A = 0; HOUR_A++; }
    if (HOUR_A > 23) { HOUR_A = 0; }
    if (HOUR_A < 10) { myOLED.print("0" + String(HOUR_A) + "-", 8, 20); }
    if (HOUR_A >= 10) { myOLED.print(String(HOUR_A) + "-", 8, 20); }
    if (MIN_A < 10) { myOLED.print("0" + String(MIN_A) + "-", 50, 20); }
    if (MIN_A >= 10) { myOLED.print(String(MIN_A) + "-", 50, 20); }
    myOLED.print("00", 92, 20);

    myOLED.setFont(SmallFont);
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    myOLED.print("ALARM SET HOUR", CENTER, 55);
    myOLED.update();
 
    button1IsUp = digitalRead(9);
    button2IsUp = digitalRead(8);
     // если кнопка 1 была нажата, переходим в 4 цикл while
    if (button1WasUp && !button1IsUp) {
      delay(10); button1IsUp = digitalRead(9);
      if (!button1IsUp) { w = 4; } }
    button1WasUp = button1IsUp;
    // если кнопка 2 была нажата, прибавляем 1 час
    if (button2WasUp && !button2IsUp) {
      delay(10); button2IsUp = digitalRead(8);
      if (!button2IsUp) { HOUR_A++; } }
    button2WasUp = button2IsUp;
  }

  while (w == 4) {
    myOLED.clrScr();
 
    myOLED.setFont(BigNumbers);
    if (MIN_A > 59) { MIN_A = 0; HOUR_A++; }
    if (HOUR_A > 23) { HOUR_A = 0; }
    if (HOUR_A < 10) { myOLED.print("0" + String(HOUR_A) + "-", 8, 20); }
    if (HOUR_A >= 10) { myOLED.print(String(HOUR_A) + "-", 8, 20); }
    if (MIN_A < 10) { myOLED.print("0" + String(MIN_A) + "-", 50, 20); }
    if (MIN_A >= 10) { myOLED.print(String(MIN_A) + "-", 50, 20); }
    myOLED.print("00", 92, 20);
 
    myOLED.setFont(SmallFont); 
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    myOLED.print("ALARM SET MINUTE", CENTER, 55);
    myOLED.update();
 
    button1IsUp = digitalRead(9);
    button2IsUp = digitalRead(8);
     // если кнопка 1 была нажата, выходим из цикла
    if (button1WasUp && !button1IsUp) {
      delay(10); button1IsUp = digitalRead(9);
      if (!button1IsUp) { w = 0; } }
    button1WasUp = button1IsUp;
    // если кнопка 2 была нажата, прибавляем 1 минуту
    if (button2WasUp && !button2IsUp) {
      delay(10); button2IsUp = digitalRead(8);
      if (!button2IsUp) { MIN_A++; } }
    button2WasUp = button2IsUp;
  }

}

Пояснения к коду:

  1. в скетче предусмотрена возможность настройки времени и будильника;
  2. значения времени и будильника можно изменить в начале программы.



Часы Ардуино на OLED i2c с модулем RTC
Часы Ардуино на OLED i2c с модулем RTC и будильником

Второй вариант часов предусматривает использование модуля часов реального времени RTC на базе чипа DS1302/DS1307 с использованием библиотеки iarduino_RTC.h. Схема подключения модуля и дисплея к Ардуино изображена на картинке выше. Настройки даты и времени в программе устанавливаются функцией watch.settime();, с помощью кнопок можно будет настроить только будильник.

Скетч. Часы на OLED дисплее с модулем RTC

#include "DHT.h"
DHT dht(2, DHT11);

#include "OLED_I2C.h"
OLED  myOLED(SDA, SCL, 8);

#include "Wire.h"
#include "iarduino_RTC.h"
iarduino_RTC watch(RTC_DS1302, 5, 6, 7); // RTC на базе чипа DS1302, RST, CLK, DAT.
//  iarduino_RTC watch(RTC_DS1307);      // RTC на базе чипа DS1307, I2C.
//  iarduino_RTC watch(RTC_DS3231);      // RTC на базе чипа DS3231, I2C.

extern uint8_t SmallFont[];
extern uint8_t BigNumbers[];

// переменные для отсчета времени и будильника
byte MIN_A = 0;
byte HOUR_A = 8;
unsigned long timer;

// переменные для считывания нажатия на кнопки
boolean button1WasUp = true;
boolean button2WasUp = true;
boolean button1IsUp;
boolean button2IsUp;

boolean alarm = true;
byte w, i;

void setup() {
  pinMode(9, INPUT_PULLUP);   // подключаем тактовые кнопки
  pinMode(8, INPUT_PULLUP);
  pinMode(3, OUTPUT);               // подключаем пьезодинамик
  dht.begin();
  myOLED.begin();
  timer = millis();
  watch.begin();
  // записываем время - 0 сек, 59 мин, 7 час, 16, февраля, 2022 года, среда
  watch.settime(0, 59, 7, 16, 02, 22, 3);
}

void loop() {
   int h = dht.readHumidity();
   int t = dht.readTemperature();
  
  // узнаем текущее состояние кнопки
  button1IsUp = digitalRead(9);
  button2IsUp = digitalRead(8);
  // если кнопка 1 нажата, заходим в настройки (цикл while)
  if (button1WasUp && !button1IsUp) {
    delay(10); button1IsUp = digitalRead(9);
    if (!button1IsUp) { w = 1; } }
  button1WasUp = button1IsUp;
  // если кнопка 2 была нажата выключаем будильник
  if (button2WasUp && !button2IsUp) {
    delay(10); button2IsUp = digitalRead(8);
    if (!button2IsUp) { alarm = !alarm; } }
  button2WasUp = button2IsUp;

  // если прошло 1000 мс - прибавляем одну секунду
  if (millis() - timer > 1000) {
    timer = millis();
    // включение будильника в течении 1 минуты
    if (alarm == true && watch.Hours == HOUR_A && watch.minutes == MIN_A && i < 60) { tone(3, 50); i++; }
    if (i >= 60) { noTone(3); alarm == false; i = 0; }

    myOLED.clrScr(); // очищаем дисплей
    
    myOLED.setFont(BigNumbers); // подключаем шрифт для цифр
    // выводим текущее время
    myOLED.print(watch.gettime("H-i-s"), CENTER, 20);
  
    myOLED.setFont(SmallFont); // подключаем шрифт для текста
    // выводим температуру, влажность и состояние будильника 
    if (alarm == true) { myOLED.print(String(t) + "' / " + String(h) + "% / on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print(String(t) + "' / " + String(h) + "% / off", RIGHT, 3); }
    // выводим дату
    myOLED.print(watch.gettime("d.m.Y, D"), CENTER, 55);
    myOLED.update();
    noTone(3);
  }

   while (w == 1) {
    myOLED.clrScr();
 
    myOLED.setFont(BigNumbers);
    if (MIN_A > 59) { MIN_A = 0; HOUR_A++; }
    if (HOUR_A > 23) { HOUR_A = 0; }
    if (HOUR_A < 10) { myOLED.print("0" + String(HOUR_A) + "-", 8, 20); }
    if (HOUR_A >= 10) { myOLED.print(String(HOUR_A) + "-", 8, 20); }
    if (MIN_A < 10) { myOLED.print("0" + String(MIN_A) + "-", 50, 20); }
    if (MIN_A >= 10) { myOLED.print(String(MIN_A) + "-", 50, 20); }
    myOLED.print("00", 92, 20);

    myOLED.setFont(SmallFont);
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    myOLED.print("ALARM SET HOUR", CENTER, 55);
    myOLED.update();
 
    button1IsUp = digitalRead(9);
    button2IsUp = digitalRead(8);
    // если кнопка 1 была нажата, переходим во 2 цикл while
    if (button1WasUp && !button1IsUp) {
      delay(10); button1IsUp = digitalRead(9);
      if (!button1IsUp) { w = 2; } }
    button1WasUp = button1IsUp;
    // если кнопка 2 была нажата, прибавляем 1 час
    if (button2WasUp && !button2IsUp) {
      delay(10); button2IsUp = digitalRead(8);
      if (!button2IsUp) { HOUR_A++; } }
    button2WasUp = button2IsUp;
  }

  while (w == 2) {
    myOLED.clrScr();
 
    myOLED.setFont(BigNumbers);
    if (MIN_A > 59) { MIN_A = 0; HOUR_A++; }
    if (HOUR_A > 23) { HOUR_A = 0; }
    if (HOUR_A < 10) { myOLED.print("0" + String(HOUR_A) + "-", 8, 20); }
    if (HOUR_A >= 10) { myOLED.print(String(HOUR_A) + "-", 8, 20); }
    if (MIN_A < 10) { myOLED.print("0" + String(MIN_A) + "-", 50, 20); }
    if (MIN_A >= 10) { myOLED.print(String(MIN_A) + "-", 50, 20); }
    myOLED.print("00", 92, 20);
 
    myOLED.setFont(SmallFont); 
    if (alarm == true) { myOLED.print("on ", RIGHT, 3); }
    if (alarm == false) { myOLED.print("off", RIGHT, 3); }
    myOLED.print("ALARM SET MINUTE", CENTER, 55);
    myOLED.update();
 
    button1IsUp = digitalRead(9);
    button2IsUp = digitalRead(8);
    // если кнопка 1 была нажата, выходим из цикла
    if (button1WasUp && !button1IsUp) {
      delay(10); button1IsUp = digitalRead(9);
      if (!button1IsUp) { w = 0; } }
    button1WasUp = button1IsUp;
    // если кнопка 2 была нажата, прибавляем 1 минуту
    if (button2WasUp && !button2IsUp) {
      delay(10); button2IsUp = digitalRead(8);
      if (!button2IsUp) { MIN_A++; } }
    button2WasUp = button2IsUp;
  }

}

Пояснения к коду:

  1. после прошивки модуля RTC и установки нужной даты с временем, закомментируйте или удалите строчку watch.settime(0, 59, 7, 16, 02, 22, 3); в программе и снова загрузите код в Ардуино;
  2. в этом варианте прошивки часов нет возможности настраивать время с помощью кнопок, можно установить только будильник.

Заключение. Мы представили сразу два варианта часов на OLED дисплее — с модулем реального времени RTC и без него. Также на нашем сайте есть пример программы со схемой сборки часов на LCD дисплее. Все вопросы или полезные замечания по этому проекту вы можете оставлять в комментариях к этой записи.



9 Replies to “Часы на Ардуино с OLED i2c и датчиком DHT11”

  1. Здравствуйте! К чему подходит pin5 на схеме часов без модуля RTC? В списке того, что потребуется для данного проекта, я не нашла, что это?

  2. Два бесполезных проекта. Одни часы с точностью пару минут в сутки, вторые — без возможности установки времени. Ну и зачем это надо? Для «наполнения сайта»?
    Видимо так.

  3. Уважаемые юзеры, Не будьте занудами, лучше выкладывайте свои — полезные и безошибочные проекты. Люди м.б. учатся, постигают программирование, а вы их сразу… фейсом об тэйбл! Нельзя так! Лучше сказать спасибо и внести дополнения, улучшающие проект!

  4. Собрал вторые часы,все работает,спасибо автору за полезные проекты,написано выше что нет возможности установить время,как же нельзя?в в скетче есть настройка времени

  5. Спасибо! Только начал в этом разбираться, очень помогла статья, все понятно, даже мне)))

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.