На днях я решил создать часы на arduino с отображением времени, текущей даты, дня недели и температуры воздуха на OLED дисплее. Что из этого получилось смотрите на видео.




Список необходимых компонентов:


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


Далее подключаем все по схеме

image

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

Скетч
#include <OLED_I2C.h>         // Подключение библиотеки для дисплея
OLED  myOLED(SDA, SCL, 8);    
extern uint8_t MegaNumbers[]; // Подключение больших шрифтов
extern uint8_t SmallFont[];   // Подключение маленьких шрифтов
#include <DS1307.h>           // Подключение библиотеки для часового модуля
DS1307 rtc(A0, A1);
 
void setup() {
  myOLED.begin();
  rtc.halt(false); 
  rtc.setDOW(SUNDAY);         // Настройка дня недели  
  rtc.setTime(12, 0, 0);      // Настройка времени 
  rtc.setDate(10, 05, 2015);  // Настройка даты
}
 
void loop(){
  myOLED.setFont(SmallFont);
  myOLED.print(rtc.getDOWStr(), CENTER, 0);   // Отображение дня недели
  String stringOne = rtc.getTimeStr();
  myOLED.setFont(MegaNumbers);
  myOLED.print(stringOne.substring(0,2), 4, 12);   // Отображение часов
  myOLED.print("/", 51, 12);                       // Отображение двоеточия
  myOLED.print(stringOne.substring(3,5), 75, 12);  // Отображение минут
  myOLED.setFont(SmallFont);
  myOLED.print(rtc.getDateStr(), CENTER, 57);      // Отображение даты
  myOLED.update();
  delay(500);
  myOLED.setFont(MegaNumbers);                     // Скрытие двоеточия
  myOLED.print("-", 51, 12);
  myOLED.update();
  delay(500);
}


после загрузки скетча у нас на дисплее отобразятся часы как на фото

image

Как видим все отображается нормально, но что бы добавить русские названия дней недели нам потребуется инициализировать русские шрифты добавив строку в скетч

extern uint8_t RusFont[];

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

switch (t.dow)
  {
    case 1:     myOLED.print("GJYTLTKMYBR", CENTER, 0);    break;
    case 2:     myOLED.print("DNJHYBR", CENTER, 0);        break;
    case 3:     myOLED.print("CHTLF", CENTER, 0);          break;
    case 4:     myOLED.print("XTNDTHU", CENTER, 0);        break;
    case 5:     myOLED.print("GZNYBWF", CENTER, 0);        break;
    case 6:     myOLED.print("CE<<JNF", CENTER, 0);        break;
    case 7:     myOLED.print("DJCRHTCTYMT", CENTER, 0);    break;
  }

и еще закомментируем строки

//  rtc.setDOW(MONDAY);        
//  rtc.setTime(13, 25, 0);     
//  rtc.setDate(27, 04, 2015);

что бы при повторной загрузке скетча не устанавливать заново время. После этого день недели на нашем дисплее отобразится на русском языке.

image

теперь изменим отображения месяца, добавив в скетч строки

switch (t.mon)
  {
    case 1:
      myOLED.print(String(t.date), 30, 57);
      myOLED.print("ZYDFHZ", CENTER, 57);
      myOLED.print(String(t.year), 88, 57);
      break;
    case 2:
      myOLED.print(String(t.date), 26, 57);
      myOLED.print("ATDHFKZ", CENTER, 57);
      myOLED.print(String(t.year), 92, 57);
      break;
    case 3:
      myOLED.print(String(t.date), 30, 57);
      myOLED.print("VFHNF", CENTER, 57);
      myOLED.print(String(t.year), 88, 57);
      break;
    case 4:
      myOLED.print(String(t.date), 30, 57);
      myOLED.print("FGHTKZ", CENTER, 57);
      myOLED.print(String(t.year), 88, 57);
      break;
    case 5:
      myOLED.print(String(t.date), 36, 57);
      myOLED.print("VFZ", CENTER, 57);
      myOLED.print(String(t.year), 82, 57);
      break;
    case 6:
      myOLED.print(String(t.date), 35, 57);
      myOLED.print("B>YZ", CENTER, 57);
      myOLED.print(String(t.year), 81, 57);
      break;
    case 7:
      myOLED.print(String(t.date), 35, 57);
      myOLED.print("B>KZ", CENTER, 57);
      myOLED.print(String(t.year), 81, 57);
      break;
    case 8:
      myOLED.print(String(t.date), 28, 57);
      myOLED.print("FDUECNF", CENTER, 57);
      myOLED.print(String(t.year), 90, 57);
      break;
    case 9:
      myOLED.print(String(t.date), 24, 57);
      myOLED.print("CTYNZ<HZ", CENTER, 57);
      myOLED.print(String(t.year), 94, 57);
      break;
    case 10:
      myOLED.print(String(t.date), 26, 57);
      myOLED.print("JRNZ<HZ", CENTER, 57);
      myOLED.print(String(t.year), 92, 57);
      break;
    case 11:
      myOLED.print(String(t.date), 28, 57);
      myOLED.print("YJZ<HZ", CENTER, 57);
      myOLED.print(String(t.year), 90, 57);
      break;
    case 12:
      myOLED.print(String(t.date), 26, 57);
      myOLED.print("LTRF<HZ", CENTER, 57);
      myOLED.print(String(t.year), 92, 57);
      break;
  }

Почему надписи в скетче отображаются непонятным набором символов читайте в этой статье Русские и украинские шрифты для OLED I2C дисплея


Теперь наши часики будут выглядеть как на фото.

image

Для тех, кому было лень править скетч, ниже есть готовый скетч.

Скетч
#include <OLED_I2C.h> 
OLED  myOLED(SDA, SCL, 8); 
extern uint8_t MegaNumbers[];
extern uint8_t RusFont[];
extern uint8_t SmallFont[];

#include <DS1307.h>
DS1307 rtc(A0, A1);
Time t;

void setup() {
  myOLED.begin();
  rtc.halt(false);
//  rtc.setDOW(WEDNESDAY);
//  rtc.setTime(10, 02, 0);
//  rtc.setDate(29, 4, 2015);
}

void loop() {
  myOLED.setFont(RusFont);
  t = rtc.getTime();
  switch (t.dow)
  {
    case 1:     myOLED.print("GJYTLTKMYBR", CENTER, 0);    break;
    case 2:     myOLED.print("DNJHYBR", CENTER, 0);        break;
    case 3:     myOLED.print("CHTLF", CENTER, 0);          break;
    case 4:     myOLED.print("XTNDTHU", CENTER, 0);        break;
    case 5:     myOLED.print("GZNYBWF", CENTER, 0);        break;
    case 6:     myOLED.print("CE<<JNF", CENTER, 0);        break;
    case 7:     myOLED.print("DJCRHTCTYMT", CENTER, 0);    break;
  }
  String stringOne = rtc.getTimeStr();
  myOLED.setFont(MegaNumbers);
  myOLED.print(stringOne.substring(0, 2), 4, 12);
  myOLED.print("/", 51, 12);
  myOLED.print(stringOne.substring(3, 5), 75, 12);
  myOLED.setFont(RusFont);
  switch (t.mon)
  {
    case 1:
      myOLED.print(String(t.date), 30, 57);
      myOLED.print("ZYDFHZ", CENTER, 57);
      myOLED.print(String(t.year), 88, 57);
      break;
    case 2:
      myOLED.print(String(t.date), 26, 57);
      myOLED.print("ATDHFKZ", CENTER, 57);
      myOLED.print(String(t.year), 92, 57);
      break;
    case 3:
      myOLED.print(String(t.date), 30, 57);
      myOLED.print("VFHNF", CENTER, 57);
      myOLED.print(String(t.year), 88, 57);
      break;
    case 4:
      myOLED.print(String(t.date), 30, 57);
      myOLED.print("FGHTKZ", CENTER, 57);
      myOLED.print(String(t.year), 88, 57);
      break;
    case 5:
      myOLED.print(String(t.date), 36, 57);
      myOLED.print("VFZ", CENTER, 57);
      myOLED.print(String(t.year), 82, 57);
      break;
    case 6:
      myOLED.print(String(t.date), 35, 57);
      myOLED.print("B>YZ", CENTER, 57);
      myOLED.print(String(t.year), 81, 57);
      break;
    case 7:
      myOLED.print(String(t.date), 35, 57);
      myOLED.print("B>KZ", CENTER, 57);
      myOLED.print(String(t.year), 81, 57);
      break;
    case 8:
      myOLED.print(String(t.date), 28, 57);
      myOLED.print("FDUECNF", CENTER, 57);
      myOLED.print(String(t.year), 90, 57);
      break;
    case 9:
      myOLED.print(String(t.date), 24, 57);
      myOLED.print("CTYNZ<HZ", CENTER, 57);
      myOLED.print(String(t.year), 94, 57);
      break;
    case 10:
      myOLED.print(String(t.date), 26, 57);
      myOLED.print("JRNZ<HZ", CENTER, 57);
      myOLED.print(String(t.year), 92, 57);
      break;
    case 11:
      myOLED.print(String(t.date), 28, 57);
      myOLED.print("YJZ<HZ", CENTER, 57);
      myOLED.print(String(t.year), 90, 57);
      break;
    case 12:
      myOLED.print(String(t.date), 26, 57);
      myOLED.print("LTRF<HZ", CENTER, 57);
      myOLED.print(String(t.year), 92, 57);
      break;
  }
  myOLED.update();
  delay(500);
  myOLED.setFont(MegaNumbers);
  myOLED.print("-", 51, 12);
  myOLED.update();
  delay(500);
}


Ну а теперь, еще более усовершенствуем наши OLED часы и добавим к ним отображение температуры, которую мы будем считывать с датчика температуры DS18B20.

Для отображения рисунка с градусником на OLED дисплее и значка градуса выберем картинку с рисунком градусника и с помощью графического редактора сохраним ее в формате GIF с именем term.gif, и тоже самое проделаем с картинкой с значком градуса — сохраним ее как grad.gif.

картинки должны быть двухцветными (белый и черный), доступные форматы картинок png, jpg, gif

У меня картинка term.bmp имеет размеры 19?40 пикселей, а картинка grad.bmp 13?12 пикселей. Потом нам потребуется конвертировать две картинки с помощью онлайн-сервиса www.rinkydinkelectronics.com

image

выбираем наш файл изображения и жмем Make File

image

Жмем на Click here to download your file и сохраняем файл grad.c в папку с нашим скетчем, тоже самое проделываем с другим изображением. Сохраняем и закрываем скетч. При повторном открытии он будет иметь еще две вкладки с файлами изображений.

image

После этого добавим две строки в скетч, которые инициализируют наши файлы изображений

	
extern uint8_t term[];
extern uint8_t grad[];


а потом отобразим наши изображения на экране OLED дисплея, добавив строки

  myOLED.drawBitmap(4, 12, term, 19, 40);
  myOLED.drawBitmap(92, 12, grad, 13, 12);


Добавим в наш скетч на два цикла. В первом цикле у нас будет отображаться время – назовем его void watch(); Второй цикл будет считывать и отображать температуру void temp();

А в основном цикле void loop(); пропишем для ротации циклов несколько строчек кода

 if (x >= 10) {
    temp();
    x=0;
  }
  else
  {
    watch();
  }
  x++;


В цикле void temp(); пропишем кусочек кода для считывания и отображения температуры

for(int x = 0; x < 10; x++){
  byte data[2];
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44);
  delay(150);
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE);
  data[0] = ds.read();
  data[1] = ds.read();
  int Temp = (data[1] << 8) + data[0];
  Temp = Temp >> 4;
  
  String stringOne = rtc.getTimeStr();
  
  myOLED.clrScr();
  myOLED.setFont(SmallFont);
  myOLED.print(stringOne.substring(0, 5), 98, 0);
  myOLED.print(rtc.getDateStr(), 0, 0);
  myOLED.setFont(RusFont);
  myOLED.print("NTVGTHFNEHF", CENTER, 57);
  myOLED.drawBitmap(4, 12, term, 19, 40);
  myOLED.setFont(MegaNumbers);
  myOLED.print(String(Temp), CENTER, 12);
  myOLED.drawBitmap(92, 12, grad, 13, 12); 
  myOLED.update();
  myOLED.clrScr();
  }

В цикле void watch(); пропишем наш код, который отвечает за отображение времени

После заливки скетча, наши OLED часы сначала должны отображать время, а потом температуру как на видео в начале статьи.

image

Полный скетч можно загрузить по ссылке OLED_watch_temp.rar

Обсуждение статьи доступно в нашей группе vk.com

Комментарии (32)


  1. BOOTor
    11.05.2015 14:29
    +3

    Неплохо бы при подключении DS резистор использовать…


    1. inhelp Автор
      11.05.2015 14:53

      извините, в схеме ошибка — у меня DS18B20 распаян на модуле DS1307…


      1. makaroff
        11.05.2015 20:27

        Тогда стоит подправить схему.


  1. CAJAX
    11.05.2015 15:07
    +2

    Кстати, некоторые продавцы пишут с обратной стороны этого экрана адрес 0x78, но на деле там 0x3C как в доках на adafruit.


    1. Karlson_rwa
      11.05.2015 21:04
      +1

      0x78 — это адрес, сдвинутый на 1 влево. Т.е. с точки зрения указания адреса это не совсем правильно (в i2c ведь адрес семибитный). Зато это адрес, в котором нужно менять лишь нулевой бит для чтения-записи.
      Хотя, на мой взгляд, правильнее прописывать адрес устройства как 0x3C, а потом уже сдвигать его и выставлять бит чтения\записи.


  1. Speccyfan
    11.05.2015 15:32
    +2

    Не плохо бы добавить пару кнопок для установки времени, свободные пины то есть.


    1. Stridemann
      11.05.2015 18:06
      -3

      А зачем? Там RTC стоит.
      В прошивке один раз пишут код установки времени, шьют, запускают, потом код удаляют. По крайней мере я так делал…


      1. Speccyfan
        11.05.2015 19:45

        Чтобы устройство было более автономным, вот сядет батарейка и придется опять подключать ее к ПК, заливать скетч с установкой времени, потом комментировать этот код и опять заливать счетч для нормальной работы, это как-то неправильно.


        1. makaroff
          11.05.2015 20:30
          +3

          А ещё потому что модули на DS1307 не гарантируют точность хода атомных часов.


        1. Stridemann
          11.05.2015 21:09

          В данном случае согласен.
          Правда производитель RTC обещает 10 лет работы от батарейки… типа скорее батарейка накроется чем модуль ее разрядит…


          1. r00tGER
            12.05.2015 08:19
            -2

            А ещё через месяц работы (что от «батарейки», что от внешнего питания) время на пару часов убежит.


            1. Arezus
              12.05.2015 12:02
              +1

              У меня на ардуине собраны часы на жестком диске, когда-то давно понадобился БП от них и они больше года пролежали в пыли, сейчас запустил — отклонение 7 минут. Если даже дважды в год переводить часы или подправлять ход, то впоне терпимо.


              1. r00tGER
                12.05.2015 12:11

                Скорее, исключение. Ибо, уже не раз упоминалось о стабильности модулей «Tiny RTC».
                У меня, в среднем +2 часа убегают за месяц. Когда начал искать причину, увидел, что проблема глобальная для подобных модулей.

                Совершенно, не пойму, что «минусящим» не понравилось.


                1. inhelp Автор
                  12.05.2015 12:35


                  1. r00tGER
                    12.05.2015 12:42

                    Ну, а я о чем…


                    1. inhelp Автор
                      12.05.2015 13:11

                      Так после лечения и замены батарейки модуль спешит на 1-2 сек в месяц… Что меня больше чем устраивает )))


                      1. r00tGER
                        12.05.2015 13:28
                        +1

                        Поэтому и добавил тему со стабильностью, там где предлагали «кнопочную коррекцию».


      1. revector
        12.05.2015 14:20

        У моего камня RTC за полгода время на 44 минуты вперед убежало. Для коррекции поставил GPS модуль дешевенький.


    1. Stridemann
      11.05.2015 18:10

      Запускал я этот DS1307 на ардуино… Как-то глючно работает, то выдает восьмерки… то вообще не понятные даты.
      Долго разбирался в чем дело. В результате пришел к выводу, что DS1307 нужно подключать к питанию 3.3v, а не к 5v. Тогда заработало всё отлично.


  1. gnomeby
    11.05.2015 17:12
    +7

    Всё-таки правильнее паковать в zip, он нативно открывается большим количеством ОС.


  1. eta4ever
    11.05.2015 20:53

    Позанудствую немножко. Корпус и кнопки планируются, или на хлебной доске все остановится?
    Ну и, если уж делитесь кодом — почему не Гитхаб?


    1. inhelp Автор
      11.05.2015 21:19

      планирую и кнопки и еще добавить отображение давления и влажности, и отображение графиков температуры, давления, влыжности — но времени никак не хватает все доделать… Про графики я рассказал в этой статье Отображение графика на OLED дисплее


  1. evtomax
    12.05.2015 01:35
    +2

    Не советую держать этот дисплей включенным круглосуточно. За год яркость постоянно светящихся пикселей очень сильно упадёт.


  1. Strange
    12.05.2015 13:41

    Сколько потребляет вся конструкция?


  1. g1t5
    12.05.2015 15:28
    +1

    Ссылки

    http://s.click.aliexpress.com/*
    реферальные чтоли?


    1. yjurfdw
      12.05.2015 15:34

      У Вас тоже не открываются?
      Или это adBlock меня не пускает? :)


      1. g1t5
        12.05.2015 15:46

        Да вроде открываются, но просто правила говорят что:

        Плохая публикация:
        Содержит реферальные ссылки на что угодно;


      1. REZ1DENT3
        12.05.2015 19:13
        +1

        Скорее всего реф. ссылки.
        Я перешел по ним по прямому клику, скопировал названия и купил все на eBay. Вышло 7.88$, чуть дешевле чем тут


    1. inhelp Автор
      12.05.2015 21:51
      -3

      Да, а в чем-то проблема ??? Я лично в этом проблемы не вижу!!! Статью копировал со своего сайта, ссылки там уже были прописаны… На сайте и баннеры реферальные ))) Ссылка на статью http://arduino-project.net/oled-chasy-na-arduino/


      1. g1t5
        12.05.2015 23:24
        +2

        Проблема в том что вы не знаете правил.

        Хабрахабр — не ЖЖ и не центр мирового кросспостинга.
        Хабрахабр— не магазин.


        1. inhelp Автор
          13.05.2015 09:44
          +1

          Уже знаю ))) СПС


  1. Alexeyslav
    13.05.2015 08:47

    Ужас-ужас… просто море магических цифр и никак не обоснованной магии.
    Потому у вас и не хватает времени чтобы развить проект дальше, он стал слишком сложным и не гибким чтобы его легко расширить.