Блок с датойБлок с временемБлок с возрастом сайта
Mr.ALB

    Анатолий Беляев (aka Mr.ALB). Персональный сайт

    Да пребудут с вами Силы СВЕТА!

     

    Ардуино (Arduino). #8

    Часы на RTC DS3231 и TM1637

    Продолжаю использовать недорогие и миниатюрные платы Arduino Pro Mini. На этой странице представляю проект часов. Обычные такие часы улыбка.

    Подразделы

     


    Прежде чем делать свой скетч, посмотрел в Интернете, что делают другие. И вот мне попался интересный проект http://arduinolab.pw/index.php/2016/06/23/chasy-na-arduino/, решил взять его за основу.

    Повторив проект, обнаружил, что он имеет ряд недостатков. Существенные недостатки, на мой взгляд, это:

    1. Отсутствие регулировки яркости индикатора.
    2. Отсутствие гашения незначащего нуля.

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

    Кто-то делает автоматическую регулировку яркости с помощью фоторезистора. Так вполне можно сделать, но я не стал, нет необходимости в такой опции, хотя проект и можно расширить, или модернизировать на такой вариант.

    Ещё хотел реализовать будильник, но потом что-то передумал и выведенная кнопка на переднюю панель для установки будильника так и осталась не подключенной. Может быть при необходимости и доработаю часы под будильник.

     


    Схема часов

    Схема часов не сложная. Благодаря тому, что индикатор управляется по протоколу IIC (I2C), соединений совсем немного. Блок питания используется импульсный, обратноходовый, от какой-то зарядки для телефона. Выдаёт он +6,5 В. Это напряжение подаётся на стабилизатор Arduino Pro Mini – на контакт RAW.

    Схема электрическая принципиальная для скетча #8
    Pic 1. Схема электрическая принципиальная для скетча #8

    Монтажную схему см. ниже.

    Схема монтажная для скетча #8
    Pic 2. Схема монтажная для скетча #8

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

     


    Конструкция часов

    Корпус традиционно склеен из пластика ABS. Габариты 80 х 60 х 54 мм (Ш х Г х В). Сама конструкция представляет собой блок из модулей: индикатора, реального времени, платы с Ардуино, модуля питания и планки с кнопками. Arduino Pro Mini вставлено в панельку DIP24, которая распаяна на монтажной плате. К этой плате и идут соединения от модулей. Конструктивно модули соединены между собой стойками из нейлона и винтами М3. К этим же стойкам прикручивается и задняя крышка. Блок из модулей вставлен в корпус и фиксируется снизу так же винтом М3.

    Обращу внимание на то, что сверху установлена клавиша выключения внешнего питания. Нет смысла жечь индикатор пока целый день на работе. Так как в модуле реального времени имеется своя литивая батарейка на 3 В, то время продолжает отсчитываться независимо от питания Ардуино и индикатора. Очень удобная функция.

    Кнопки управления вынес на переднюю панель и немного утопил вглубь. Сейчас объясню зачем так. Есть у меня часы ASSISTANT ah-1066, габариты у них чуть-чуть больше, а индикатор такой же, зелёненький. Так у них кнопки управления вынесены на верхнюю крышку, что с моей точки зрения и опыта эксплуатации такой конструкции не совсем удобно, да и пыль на них оседает. Батарейки в тех часах мизинчиковые (ААА) 3 шт. – недолговечно. Нет регулировки яркости индикатора. Поэтому, создавав свою конструкцию старался устранить эти недостатки. К примеру, когда кнопки впереди, то легко подстраивать или устанавливать время, так как одновременно видишь и индикатор, и кнопки.

    Ниже небольшой фотоотчёт по конструкции часов.

    Часы. Внешний вид, разные ракурсы
    Pic 3. Часы. Внешний вид, разные ракурсы
    Часы. Внешний вид, разные ракурсы
    Pic 4. Часы. Внешний вид, разные ракурсы
    Часы. Внешний вид, вид снизу
    Pic 5. Часы. Внешний вид, вид снизу
    Часы. Внешний вид, снята задняя крышка
    Pic 6. Часы. Внешний вид, снята задняя крышка
    Часы. Вынут блок часов из корпуса
    Pic 7. Часы. Вынут блок часов из корпуса
    Часы. Вынут блок-модуль часов из корпуса
    Pic 8. Часы. Вынут блок-модуль часов из корпуса
    Часы. Блок-модуль часов разъединён. Отделена плата RTC DS3231
    Pic 9. Часы. Блок-модуль часов разъединён. Отделена плата RTC DS3231
    Часы. Блок-модуль часов разъединён. Отделена плата RTC DS3231
    Pic 10. Часы. Блок-модуль часов разъединён. Отделена плата RTC DS3231
    Часы. Блок-модуль часов разъединён. Отделена плата индикатора TM1637 и панель кнопок
    Pic 11. Часы. Блок-модуль часов разъединён. Отделена плата индикатора TM1637 и панель кнопок

     


    Скетч часов

    Далее представлен скетч. Рассмотрю некоторые его особенности. Так, у автора для мигания точек используется сигнал с модуля реального времени с контакта SQW, который подаётся на контакт 2 Ардуино. На этом контакте установлено внешнее прерывание 0 на изменение (CHANGE). Можно реализовать и по-другому, к примеру, через Таймер1. Оставил так, как у автора, может быть в другом проекте сделаю через Таймер1, для разнообразия.

    Весь код подробно закомментирован, с его пониманием, надеюсь, проблем не будет. Хочу лишь обратить внимание, что когда происходит запись значения в EEPROM, то индикатор гашу на пол секунды, чтобы видеть, что команда записи отработала. В некотором роде – индикация записи.

    /*****************************************************************
     * 2018-05-25 Mr.ALB
     * Основа взята с сайта http://arduinolab.pw/index.php/2016/06/23/chasy-na-arduino/
     * Часы на 7 сегментном индикаторе TM1637 и модуле реального времени RTC DS3231
     * 
     * Модуль RTC DS3231:
     * SCL - A5
     * SDA - A4
     * SQW - 2 // Для мигания разделительных точек
     * VCC - 5V
     * GND - GND
     * 
     * Подключить кнопки управления на пины и на GND
     * 
     * 2018-11-20 Запись значения яркости в EEPROM
     * 2018-11-22 Гашение незначащего нуля
     *****************************************************************/
    
    #include <EEPROM.h>    // для EEPROM
    #include <Wire.h>
    #include "TM1637.h"
      
    // 7 сигментный индикатор TM1637
    #define CLK 6         
    #define DIO 7
    TM1637 tm1637(CLK,DIO); // Создание объекта индикатора
    
    // Кнопки установки времени
    #define buttonHour 5  // Часы
    #define buttonMin  4  // Минуты
    #define buttonSet  3  // Установка
    #define buttonBR   8  // Кнопка яркости
    
    #define DS3231_I2C_ADDRESS 0x68 // Адрес часов реального времени
    
    int brightness = 1;     // Яркость, от 0 до 7
    int addrBR = 6;         // Адрес в EEPROM для записи яркости
    boolean flag_br = false;// Флаг для записи яркости
    boolean flag_null=false;// Флаг для гашения незначащего нуля
    volatile boolean flag;  // Переменная для прерывания
    
    /**********************
     **** Подпрограммы ****
     **********************/
    /* часы .. */
    byte decToBcd(byte val)
    {
      return ((val/10*16) + (val%10));
    }
    
    byte bcdToDec(byte val)
    {
      return ((val/16*10) + (val%16));
    }
    
    /* Установка данных в модуль RTC DS3231 */
    void setDateDs3231(byte second,        // 0-59
                       byte minute,        // 0-59
                       byte hour,          // 1-23
                       byte dayOfWeek,     // 1-7
                       byte dayOfMonth,    // 1-28/29/30/31
                       byte month,         // 1-12
                       byte year)          // 0-99
    {
       Wire.beginTransmission(DS3231_I2C_ADDRESS);
       Wire.write(0);
       Wire.write(decToBcd(second));    
       Wire.write(decToBcd(minute));
       Wire.write(decToBcd(hour));     
       Wire.write(decToBcd(dayOfWeek));
       Wire.write(decToBcd(dayOfMonth));
       Wire.write(decToBcd(month));
       Wire.write(decToBcd(year));
       Wire.endTransmission();
    }
    
    /* Получение данных с модуля RTC DS3231 */
    void getDateDs3231
      (
        byte *second,
        byte *minute,
        byte *hour,
        byte *dayOfWeek,
        byte *dayOfMonth,
        byte *month,
        byte *year
      )
    {
      Wire.beginTransmission(DS3231_I2C_ADDRESS);
      Wire.write(0);
      Wire.endTransmission();
    
      Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
    
      *second     = bcdToDec(Wire.read() & 0x7f);
      *minute     = bcdToDec(Wire.read());
      *hour       = bcdToDec(Wire.read() & 0x3f); 
      *dayOfWeek  = bcdToDec(Wire.read());
      *dayOfMonth = bcdToDec(Wire.read());
      *month      = bcdToDec(Wire.read());
      *year       = bcdToDec(Wire.read());
    }
    
    /* Включаем выход SQW, который вроде выключен по умолчанию */
    void setINT()
    {    
      Wire.beginTransmission(DS3231_I2C_ADDRESS);
      Wire.write(0x0E);
      Wire.write(0x0);
      Wire.endTransmission();
    }
    
    /* Для мигания точек */
    void blink()
    {
      digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
      flag = !flag;
      tm1637.point(flag); 
    }
    
    void setup() 
    {
      Wire.begin();
      pinMode(LED_BUILTIN, OUTPUT);       // Для мигания точек
      pinMode(buttonHour, INPUT_PULLUP);  // Кнопка изменения часов
      pinMode(buttonMin, INPUT_PULLUP);   // Кнопка изменения минут
      pinMode(buttonSet, INPUT_PULLUP);   // Кнопка разрешения установок
      pinMode(buttonBR, INPUT_PULLUP);    // Кнопка изменения яркости 
       
      tm1637.init();                      // Инициализация индикатора
      
      setINT();                           // Включаем выход SQW на RTC3231
    
      tm1637.set(brightness);             // Установка начальной яркости 
      // Установка значений из EEPROM   
      if(EEPROM.read(addrBR) >= 0 && EEPROM.read(addrBR) < 8)
        tm1637.set(EEPROM.read(addrBR));// Считывание из EEPROM яркости
    
      attachInterrupt(0, blink, CHANGE);// Подключаем прерывание
    }
    
    void loop()
    {
      byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; 
      
      // Читаем время из модуля
      getDateDs3231(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); 
      
      // Заполняем массив значениями для отпарвки на индикатор
      int8_t TimeDisp[4]; 
      
      TimeDisp[0] = hour / 10;  // Десятки часов
      TimeDisp[1] = hour % 10;  // Единицы часов
      TimeDisp[2] = minute / 10;// Десятки минут
      TimeDisp[3] = minute % 10;// Единицы минут
    
      /* Обработка кнопок
       * Изменения при одновременном совместном нажитии на кнопку buttonSet
      */
      if (!digitalRead(buttonHour) && !digitalRead(buttonSet))
      { // Часы
        second = 0;                           // сбрасываем секунды
        hour++;                               // прибавляем единицу к часам
        if (hour > 23) hour = 0;              // если вылезли за границы присваеваем 0
        // записываем в модуль
        setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
        delay(200);
      }
      
      if (!digitalRead(buttonMin) && !digitalRead(buttonSet))
      { // Минуты
        second = 0;
        minute++;
        if (minute > 59) minute = 0;
        setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
        delay(200);
      }
      
      if (!digitalRead(buttonBR) && !digitalRead(buttonSet))
      { // Яркость индикатора
        brightness++; 
        if (brightness > 7) brightness = 0; 
        tm1637.set(brightness);
        flag_br = true;
        delay(200); 
      }
      
      if(flag_br==true && digitalRead(buttonSet)==HIGH)
      { // Запись значения в EEPROM при отжатой кнопке buttonSet
        flag_br=false;
        EEPROM.write(addrBR, brightness);
        tm1637.clearDisplay();// Гашение экрана как индикация записи
        delay(500); 
      }
      
      // Отправляем массив на индикатор
      if(TimeDisp[0]!=0)
      { // Если первое значение не 0, то выводим
        if(flag_null)flag_null=false; // Сбросим флаг нуля
        tm1637.display(0,TimeDisp[0]);// Вывод первой цифры
      }
      else
      { // Иначе гашение незначащего нуля
        // Гасим один первый раз при смене на 0 
        if(!flag_null)
        {
          flag_null=true;       // Выставим флаг нуля
          tm1637.clearDisplay();// Гашение экрана
        }
      }
      tm1637.display(1,TimeDisp[1]);  // Вывод второй цифры
      tm1637.display(2,TimeDisp[2]);  // Вывод третьей цифры
      tm1637.display(3,TimeDisp[3]);  // Вывод четвёртой цифры
    }
    
    

    Этими часами уже пользуюсь длительное время, до этого использовал сам блок-модулей, а теперь уже сделан полноценный корпус.

    На данный момент получилось то, что получилось улыбка. Конструкция полностью товарная готовая к использованию в обиходе. Довольно удобно. Рекомендую к повторению.

    Скетч можно скачать тут: Clock_tm1637_RTC_DS3231.zip

    Используемые библиотеки:

    EEPROM.zip
    TM1637.zip
    Wire.zip


    . Mr.ALB
    Предыдущая страница Страница 9