Часы на ардуино

Часики с 7-сигментным индикатором на TM1637 и часами реального времени DS3231, с возможностью установки времени кнопками.

Ниже несколько версий.

Версия на плате фабричного производства.

Видео:

https://youtu.be/iYdqlH0mh_4

Код:

Код
/// Код на 24.04.21

#include <Wire.h>
#include "TM1637.h"  // http://arduinolab.pw/wp-content/uploads/2016/06/DigitalTube.zip
/*
 * В файле TM1637.h нужно подправить табличку и добавить туда "0x63, 0x00" как ниже.
   static int8_t TubeTab[] = {0x3f,0x06,0x5b,0x4f,
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f,0x77,0x7c,
                           0x39,0x5e,0x79,0x71, 0x63, 0x00};//0~9,A,b,C,d,E,F              
*/   
#define keyP 4                        // кнопки
#define keySET 3 
#define keyM  2
  
TM1637 tm1637(6, 7);                  // CLK, DIO 
 
///// ... часы ..
#define DS3231_I2C_ADDRESS 0x68

int8_t decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}

int8_t bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
}

void setDateDs3231(int8_t second,        // 0-59
                   int8_t minute,        // 0-59
                   int8_t hour,          // 1-23
                   int8_t dayOfWeek,     // 1-7
                   int8_t dayOfMonth,    // 1-28/29/30/31
                   int8_t month,         // 1-12
                   int8_t 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();
}

void getDateDs3231(byte *second,
          int8_t *minute,
          int8_t *hour,
          int8_t *dayOfWeek,
          int8_t *dayOfMonth,
          int8_t *month,
          int8_t *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());
}

////// 

void setup() {
//   Serial.begin(9600);
  Wire.begin(); 
  pinMode(keyP, INPUT_PULLUP);
  pinMode(keySET, INPUT_PULLUP);
  pinMode(keyM, INPUT_PULLUP);

  tm1637.init();
  tm1637.set(0);  
  tm1637.point(1); 

  analogReference(INTERNAL);         
    
}

void loop(){
    // читаем время из модуля
  int8_t 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;

// обработка кнопок  
  /// Установка времени
  if (!digitalRead(keySET)){               // Если надавили сет
     delay(200);                           // антидребезг
     second = 0;                           // сбрасываем секунды
     tm1637.point(1);                      // включаем ":"
      do{                                    /// Крутим цикл! /// часы
        if (!digitalRead(keyP)){           // если в цикле надавили на "+"
           hour++;                               // пребавляем единицу к часу
           if (hour > 23) hour = 0;              // если вылезли за границы присваеваем 0
           setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); // пишим в модуль
           delay(200);          
        }
        if (!digitalRead(keyM)){            // если на "-"
           hour--;                               // убавляем единицу
           if (hour < 0) hour = 23;              // если вылезли за границы 
           setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); // пишим в модуль
           delay(200);          
        }
       TimeDisp[0] = hour / 10;             // в цикле также показываем что получилось
       TimeDisp[1] = hour % 10;
       TimeDisp[2] = 17;                    // 17 это 0xff, выключение
       TimeDisp[3] = 17;                     
        tm1637.display(TimeDisp);          // отправляем массив на экран      
     }while(digitalRead(keySET));          // крутимся пока не надавили сет     
     delay(500);                           // антидребез  
     
     do{                                   // снова крутимся, но уже для минут. 
        if (!digitalRead(keyP)){           // также смотрим не нажато ли "+" 
           minute++;                       // прибавляем минуту
           if (minute > 59) minute = 0;    // проверяем
           setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
           delay(200);      
        }
        if (!digitalRead(keyM)){           // также смотрим на "-"
           minute--;
           if (minute < 0) minute = 59;
           setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
           delay(200);       
        }
        TimeDisp[0] = 17;
        TimeDisp[1] = 17;
        TimeDisp[2] = minute / 10;
        TimeDisp[3] = minute % 10;              
        tm1637.display(TimeDisp);          // отправляем массив на экран  
        
     }while(digitalRead(keySET));          // крутимся пока не надавили сет     
      delay(200);                          // задумываемся перед выходом
  }
  
// таймер на RTC )    
    static byte oldSec;
   if (oldSec != second){                  // true каждую секунду. 
      oldSec = second;                     // сохраняем прошедную 
         // мигание точкой
      static bool point;                   
      point = !point;
      tm1637.point(point); 

         // Устанавливаем яркость LED
      byte brightness = map(analogRead(A1), 0, 1023, 0, 7);   // Читаем вход и мапим, приделы подкорректировать !!!
      tm1637.set(brightness);                                 // Пишем в дисплей

   } ///
     
// Отображение температуры
//      if (second == 15 || second == 16 || second == 17 || !digitalRead(keyP)){   // Отображаем каждые 3 секунды или кнопкой
      if (!digitalRead(keyP)){                                // Отображаем при нажатой кнопки "+"
        tm1637.point(0);                                      // Выключаем двоеточие
        
/// Получение температуры !!!
//        int8_t tempC = (analogRead(A0) / 9.31;                                // Для LM35 и атмеги328 (опорное 1,1)  
        int8_t tempC = (((analogRead(A0) * 2.54) / 1024.0) - 0.5) * 100;      // для TMP36 и атмеги8 (опорное 2,56)
//        int8_t tempC = (((analogRead(A0) * 1.1) / 1024.0) - 0.5) * 100;       // для TMP36 и атмеги328 (опорное 1,1)   
//        int8_t tempC = (analogRead(A0)/1024.0)*5.0*1000/10;    // для 5 вольт LM35.          
       
        TimeDisp[0] = tempC / 10;                            // Заполняем массив
        TimeDisp[1] = tempC % 10;
        TimeDisp[2] = 16;                                     // градус (нужно добавить "0x63" в "TubeTab[]" в "TM1637.h")
        TimeDisp[3] = 12;                                     // C
       delay(200);
      }
      
     // отправляем массив на экран
  tm1637.display(TimeDisp); 
  
}

Ссылки и файлы:

Проект easyeda: Тут.

Подправленная библиотека: Тут.


Старые, прошлые, версии!!!

позже приведу в порядок и их.

ниже код из видео

update: 04.08.20 \ код и то что написано ниже, основанно на том видео, но не является истенно верным.

Как все подключено:

Было решено отказаться от мигалки двоеточием при помощи аппаратного прерывания, ибо для многих это оказалось слишком сложным техническим решением. Подключать ногу SQW на модуле к ардуино, не нужно. Кнопки и остальная логика работы не изменилась.


Железки на али:

Индикатор на TM1637
Часы DS3231
клон Arduino UNO


Код:

Чтобы всё заработало как нужно, чтобы при компиляции не вываливались ошибоки, необходимо установить библиотеку для работы с индикатором TM1637:

Существуют и другие библиотеки для TM1637, но код написан с использованием DigitalTube от seeedstudio. Работа проверена на версии IDE 1.6.5-r5.

То как оно было изначально.
#include <Wire.h>
#include "TM1637.h"  // http://www.seeedstudio.com/wiki/File:DigitalTube.zip

    // 7сигментный индикатор
#define CLK 6         
#define DIO 7 
#define brightness 6  // яркость, от 0 до 7

    // кнопки
#define keyHor 5
#define keyMin 4 
#define keyPL  3

TM1637 tm1637(CLK,DIO);  
#define DS3231_I2C_ADDRESS 0x68
  
volatile boolean flag;

///// часы ..
byte decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
}

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();
}

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());
}

void setINT(){    //включает выход SQW, который вроде выключен по умолчанию
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x0E);
  Wire.write(0x0);
  Wire.endTransmission();
}

void blink() {
  digitalWrite(13, !digitalRead(13));
  flag = !flag;
  tm1637.point(flag); 
}

void setup() {
//  Serial.begin(9600);
  Wire.begin();
  pinMode(13, OUTPUT);
  pinMode(keyHor, INPUT_PULLUP);
  pinMode(keyMin, INPUT_PULLUP);
  pinMode(keyPL, INPUT_PULLUP);

  tm1637.init();
  tm1637.set(brightness);  
  
  setINT(); 
  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;

    // обработка кнопок
  if (!digitalRead(keyHor) && !digitalRead(keyPL)){   // часы
      second = 0;                           // сбрасываем секунды
      hour++;                               // пребавляем единицу к часам
      if (hour > 23) hour = 0;              // если вылезли за границы присваеваем 0
      setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); // пишим в модуль
      delay(200);
  }
  if (!digitalRead(keyMin) && !digitalRead(keyPL)){   // минуты
      second = 0;
      minute++;
      if (minute > 59) minute = 0;
      setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
      delay(200);
  }
     // отправляем массив на экран
  tm1637.display(TimeDisp);
 
  
}

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

Возможно с ней будут проблемы в новых версиях IDE, но на версии 1.6.5-r5 оно работает.

Версия с таймером
#include <Wire.h>
#include "TM1637.h"  // https://arduinolab.pw/wp-content/uploads/2016/06/DigitalTube.zip
#include <MsTimer2.h> // https://arduinolab.pw/wp-content/uploads/2016/06/MsTimer2.zip

////// подключение:
    // 7сигментный индикатор
#define CLK 6         
#define DIO 7 
#define brightness 6  // яркость, от 0 до 7

    // кнопки
#define keyHor 5
#define keyMin 4 
#define keyPL  3

//////

TM1637 tm1637(CLK,DIO);  
#define DS3231_I2C_ADDRESS 0x68

boolean val;
   
/////... часы ..
byte decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
}

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();
}

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());
}

////// 
 
  
void flash() {
  static boolean output = HIGH;
  tm1637.point(output); 
  digitalWrite(13, output);
  output = !output;
}


void setup() {
//  Serial.begin(9600);
  Wire.begin();
  pinMode(13, OUTPUT);
  pinMode(keyHor, INPUT_PULLUP);
  pinMode(keyMin, INPUT_PULLUP);
  pinMode(keyPL, INPUT_PULLUP);

  tm1637.init();
  tm1637.set(brightness);  

  MsTimer2::set(500, flash); // 500ms period
  MsTimer2::start();
   
}

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;

    // обработка кнопок
  if (!digitalRead(keyHor) && !digitalRead(keyPL)){   // часы
      second = 0;                           // сбрасываем секунды
      hour++;                               // пребавляем единицу к часам
      if (hour > 23) hour = 0;              // если вылезли за границы присваеваем 0
      setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); // пишим в модуль
      delay(200);
  }
  if (!digitalRead(keyMin) && !digitalRead(keyPL)){   // минуты
      second = 0;
      minute++;
      if (minute > 59) minute = 0;
      setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
      delay(200);
  }
     // отправляем массив на экран
  tm1637.display(TimeDisp);
 
  
}


Версия без мигания двоеточием:


Если совсем ничего не получается
#include <Wire.h>
#include "TM1637.h"  // https://arduinolab.pw/wp-content/uploads/2016/06/DigitalTube.zip
 

////// подключение:
    // 7сигментный индикатор
#define CLK 6         
#define DIO 7 
#define brightness 6  // яркость, от 0 до 7

    // кнопки
#define keyHor 5
#define keyMin 4 
#define keyPL  3

//////

TM1637 tm1637(CLK,DIO);  
#define DS3231_I2C_ADDRESS 0x68

   
/////... часы ..
byte decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
}

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();
}

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());
}

////// 
 
  
 


void setup() {
//  Serial.begin(9600);
  Wire.begin();
  pinMode(13, OUTPUT);
  pinMode(keyHor, INPUT_PULLUP);
  pinMode(keyMin, INPUT_PULLUP);
  pinMode(keyPL, INPUT_PULLUP);

  tm1637.init();
  tm1637.set(brightness);  
  tm1637.point(1); 
    
}

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;

    // обработка кнопок
  if (!digitalRead(keyHor) && !digitalRead(keyPL)){   // часы
      second = 0;                           // сбрасываем секунды
      hour++;                               // пребавляем единицу к часам
      if (hour > 23) hour = 0;              // если вылезли за границы присваеваем 0
      setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); // пишим в модуль
      delay(200);
  }
  if (!digitalRead(keyMin) && !digitalRead(keyPL)){   // минуты
      second = 0;
      minute++;
      if (minute > 59) minute = 0;
      setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
      delay(200);
  }
     // отправляем массив на экран
  tm1637.display(TimeDisp);
 
  
}


пока всё.