Часы/Таймер на кухне

Ralgxi
Offline
Зарегистрирован: 16.08.2021

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

Итак данное устройство умеет:

1. Отображать текущее время (часы, минуты, секунды)

2. Имеет вшитые временные задания (2 мин, 5 мин, 10 мин, 20 мин, 30 мин,

    50 мин, 1час, 1ч 20 мин, 1ч 50 мин, 2 часа, 2ч 50 мин)

3. Можно выставить произвольное время таймера в диапазоне (1 мин — 99 час)

4. Ручную корректировку часов реального времени.

5. Пауза в режиме отсчета таймера и прерывание счета.

Прошу по коду сильно не пинать, я все еще учусь.

Файл DS3231.h разместить в одной папке с скетчем.

/*****************************************************************

              Copyright (C) 2020 Александр

*****************************************************************/

#include <LedControl.h>
#include <Wire.h>
#include "GyverEncoder.h"

#include "DS3231.h"

/*
  Now we need a LedControl to work with.
 ***** These pin numbers will probably not work with your hardware *****
  pin 12 is connected to the DIn
  pin 11 is connected to the CLK
  pin 10 is connected to CS
  We have only a single MAX72XX.
*/
LedControl lc = LedControl(12, 11, 10, 1);

#define pin_CLK 3 // Энкодер пин A
#define pin_DT  4 // Энкодер пин B
#define pin_Btn 5 // Кнопка

Encoder enc1(pin_CLK, pin_DT, pin_Btn);

#define BUZZER  8               // сюда подключена пищалка

volatile boolean Start_timer;   // переключатель дисплея
boolean screenChange = false;   // enum
int currentScreen = 0;

volatile boolean flag;          // флаг секунд                      
volatile boolean flag_null = false;  // Флаг для гашения незначащего ноля на часах
uint8_t pause;                  // флаг паузы
uint8_t working;                // флаг работы

long newPosition = 0;           // значение энкодера
int _sec, _min, _hour;
int brightness = 12;            // Яркость  15
int DispFlag = 0;

int p_ress = 0;

enum ScreenID
{
  min2 = 1,
  min5,
  min10,
  min20,
  min30,
  min50,
  h1_00min,
  h1_20min,
  h1_50min,
  h2_00min,
  h2_50min,
  COUNT_ITEMS
};

//===================== прерывание от sqw ===============

/* Для мигания дисплея и отсчета */
void  blink()
{
  flag = !flag;
}

//********************* энкодер кнопка ****************//

void isrButton() {

  if (Start_timer) {
    if ( !working ) {
      working = 1;
      pause = !pause;
    }
    else pause = !pause;
  }
}

// ============= мигаем экраном =====================

void shimmer ()
{
  if (flag) brightness = 2;
  else brightness = 15;

  lc.setIntensity(0, brightness);
}

//============ отображение на дисплее ==============

void displey ()
{

// забиваем массив значениями для отпарвки на экран

  int8_t TimeDisp[6];

  TimeDisp[7] = hour / 10;
  TimeDisp[6] = hour % 10;
  TimeDisp[4] = minute / 10;
  TimeDisp[3] = minute % 10;
  TimeDisp[1] = second / 10;
  TimeDisp[0] = second % 10;

  int8_t TimeTime[6];

  TimeTime[7] = _hour / 10;     // Десятки часов  
  TimeTime[6] = _hour % 10;     // Единицы часов
  TimeTime[4] = _min / 10;      // Десятки минут
  TimeTime[3] = _min % 10;      // Единицы минут
  TimeTime[1] = _sec / 10;      // Десятки минут
  TimeTime[0] = _sec % 10;      // Единицы минут

  // выводим на экран
  //================= часы =====================

  if (!Start_timer) {

    brightness = 8;
    lc.setIntensity(0, brightness);

    if (TimeDisp[7] != 0)
    { // Если первое значение не 0, то выводим
      if (flag_null)flag_null = false;     // Сбросим флаг нуля
      lc.setDigit(0, 7, TimeDisp[7], false); // Вывод первой цифры
    }
    else
    { // Иначе гашение незначащего нуля
      // Гасим один первый раз при смене на 0
      if (!flag_null)
      {
        flag_null = true;               // Выставим флаг нуля
        lc.clearDisplay(0);             // Гашение экрана
      }
    }
    lc.setDigit(0, 6, TimeDisp[6], false);
    lc.setChar(0, 5, '-', false);
    lc.setDigit(0, 4, TimeDisp[4], false);
    lc.setDigit(0, 3, TimeDisp[3], false);
    lc.setChar(0, 2, '-', false);
    lc.setDigit(0, 1, TimeDisp[1], false);
    lc.setDigit(0, 0, TimeDisp[0], false);
  }

  //================ таймер ======================

  else {

    if ( _hour != 0 ) {

      if (TimeTime[7] != 0)
      { // Если первое значение не 0, то выводим
        if (flag_null)flag_null = false;
        lc.setDigit(0, 7, TimeTime[7], false);
      }
      else
      { // Иначе гашение незначащего нуля
        // Гасим один первый раз при смене на 0
        if (!flag_null)
        {
          flag_null = true;
          lc.clearDisplay(0);
        }
      }
      lc.setDigit(0, 6, TimeTime[6], false);
      lc.setChar(0, 5, '-', false);
      lc.setDigit(0, 4, TimeTime[4], false);
      lc.setDigit(0, 3, TimeTime[3], false);
      lc.setChar(0, 2, '-', false);
      lc.setDigit(0, 1, TimeTime[1], false);
      lc.setDigit(0, 0, TimeTime[0], false);
    }
    else {

      if (TimeTime[4] != 0)
      { // Если первое значение не 0, то выводим
        if (flag_null)flag_null = false;
        lc.setDigit(0, 4, TimeTime[4], false);
      }
      else
      { // Иначе гашение незначащего нуля
        // Гасим один первый раз при смене на 0
        if (!flag_null)
        {
          flag_null = true;
          lc.clearDisplay(0);
        }
      }
      lc.setDigit(0, 3, TimeTime[3], false);
      lc.setChar(0, 2, '-', false);
      lc.setDigit(0, 1, TimeTime[1], false);
      lc.setDigit(0, 0, TimeTime[0], false);
    }
    shimmer ();         // мигаем экраном
  }
}
//========== старт таймера ========================

void St_Timer ()
{

  if (_hour == 0 && _min == 0 && _sec == 0) stopOut();// если отсчитывать нечего, тогда и не запускаемся

  if ( pause == 1) {                        // начинаем отсчет
    if ( _sec > 0) _sec--;
    else
    {
      _sec = 59;
      if (_min > 0) _min--;
      else
      {
        _min = 59;
        if (_hour > 0) _hour--;
        else _hour = 0;
        lc.clearDisplay(0);
      }
    }
    if (_hour == 0 && _min == 0 && _sec == 0) displey (), Stop();
  }
  if (enc1.isHolded()) stopOut();                          // если была удержана и энк не поворачивался
}

//---------------------- стоп таймера -----------------------

void Stop () {

  stopOut();

  int i;
  int y;

  for (y = 0; y < 5; y++) {
    for (i = 0; i < 1000; i++)
    {
      digitalWrite(BUZZER, HIGH);
      delayMicroseconds(500);
      digitalWrite(BUZZER, LOW);
      delayMicroseconds(500);
    }
    delay(500);
  }
}

//-------------------------------------------------
void stopOut() {

  enc1.resetStates();
  // screenChange = false;
  currentScreen = 0;
  working = 0;
  Start_timer = false;
  pause = 0;
  _hour = _min = _sec = 0;
}

//=========== настройка времени таймера =========================

void setpoint () {

  do {

    enc1.tick();

    if (enc1.isRight()) newPosition++;    // если был поворот
    if (enc1.isLeft()) newPosition--;

    if (enc1.isFastR()) newPosition += 10;   // если был быстрый поворот направо, увеличиваем на 10
    if (enc1.isFastL()) newPosition -= 10;   // если был быстрый поворот налево, уменьшаем на 10

    _min = _min + newPosition;
    newPosition = 0;

    if (  _min > 59 )
    {
      _min = 0;
      _hour ++;
    }
    else if ( _min < 0 )
    {
      _min = 59;
      _hour --;
      lc.clearDisplay(0);
    }
    if ( _hour > 99 || _hour <= 0 ) _hour = 0;
    //   }
    displey ();
    p_ress = enc1.isHold();            // состояние кнопки
  } while (!p_ress);
}

//++++++++++++++++++ Настройка времени часов ++++++++++++++++++

void setupTimer() {

            process_DS3231();

  while (!p_ress) {

    enc1.tick();

    if (enc1.isLeft()) {            // если влево - минуты
      newPosition++;

      if (enc1.isFastL()) newPosition += 5;

      minute = minute + newPosition;
      newPosition = 0;

      if (minute > 59) minute = 0;
    }

    if (enc1.isRight()) {           // если вправо - часы
      newPosition++;

      if (enc1.isFastR()) newPosition += 5;

      hour = hour + newPosition;
      newPosition = 0;

      if (hour > 23) hour = 0;
    }
    
    if (enc1.isClick()) p_ress = 1;

    displey ();

  }
  setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year);     
}

//=================================================================

void setup()
{
  Serial.begin(115200);
  Serial.println("");

  Wire.begin();

  enc1.setType(TYPE2);        // тип энкодера

  setup_DS3231();

  pinMode(BUZZER, OUTPUT);
  delay (50);
  tone(BUZZER, 1000);          // диагностика звука
  delay(250);
  noTone(BUZZER);

  /*
    The MAX72XX is in power-saving mode on startup,
    we have to do a wakeup call
  */
  lc.shutdown(0, false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0, brightness);   // яркость 15
  /* and clear the display */
  lc.clearDisplay(0);            // очистка дисплея

  noInterrupts();
  attachInterrupt(0, blink, CHANGE); //  прерывание от смены секунд
  interrupts();

// зажимаем кнопку энкодера, включаем питание - 
//переходим к настройке часов. Кнопкой запись и выход

  if (!digitalRead(5)) setupTimer();                       

}

//===============================================================

void loop ()
{

  enc1.tick();

  if (enc1.isClick()) isrButton();// пуск\пауза счета    


  process_DS3231();

  displey ();

  if ( !working ) {

    if (enc1.isRight()) {   // если вправо - настройка времени таймера

      Start_timer = true;

      lc.clearDisplay(0);
      p_ress = 0;

      _hour = 0;
      _min = 0;
      _sec = 0;

      setpoint ();
    }

    if (enc1.isLeft()) {   // если влево - выбор предустановленных параметров

      Start_timer = true;

      screenChange = true;    // флаг, что экран надо перерисовать
      currentScreen++;        // переходим на следующий экран
      if (currentScreen == COUNT_ITEMS) {
        currentScreen = min2;
      }
      /////// обработчик экранов дисплея
      if (screenChange)
      {
        lc.clearDisplay(0);
        screenChange = false;
        switch (currentScreen)
        {
          case min2:
            _hour = 0;
            _min = 2;
            _sec = 0;
            break;

          case min5:
            _hour = 0;
            _min = 5;
            _sec = 0;
            break;

          case min10:
            _hour = 0;
            _min = 10;
            _sec = 0;
            break;

          case min20:
            _hour = 0;
            _min = 20;
            _sec = 0;
            break;

          case min30:
            _hour = 0;
            _min = 30;
            _sec = 0;
            break;

          case min50:
            _hour = 0;
            _min = 50;
            _sec = 0;
            break;

          case h1_00min:
            _hour = 1;
            _min = 0;
            _sec = 0;
            break;

          case h1_20min:
            _hour = 1;
            _min = 20;
            _sec = 0;
            break;

          case h1_50min:
            _hour = 1;
            _min = 50;
            _sec = 0;
            break;

          case h2_00min:
            _hour = 2;
            _min = 0;
            _sec = 0;
            break;

          case h2_50min:
            _hour = 2;
            _min = 50;
            _sec = 0;
            break;
        }
      }
    }
  }

  if (Start_timer) {
    if ( flag && DispFlag == 0) { // 1 раз в сек обновляем дисплей в режиме таймера
      DispFlag ++;

      St_Timer();

    }
    if ( !flag && DispFlag == 1) {
      DispFlag = 0;
    }
  }

  // delay(500);

}

 

DS3231.h


#ifndef DS3231_h
#define DS3231_h

#define DS3231_I2C_ADDRESS 0x68

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;

/**********************
 **** Подпрограммы ****
 **********************/
/* часы .. */
byte decToBcd(byte val)
{
  return ((val / 10 * 16) + (val % 10));
}

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

/* Установка данных в модуль RTC3231 */
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 setup_DS3231()
{
  setINT();                           // Включаем выход SQW на RTC3231
}

void process_DS3231()
{

  // читаем время из модуля

  getDateDs3231(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

}

#endif

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

А с чем связана такая странная шкала?

Например, между 1 ч и 1 ч 20 мин - 20 минут,

между 1 ч 30 мин и 1 ч 50 мин - 30 минут,

между 1 ч 50 мин и 2 ч - только 10 минут.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Супруга так захотела. Но в прошивке все легко изменить.

Pyotr
Offline
Зарегистрирован: 12.03.2014

У Вас dayOfWeek, dayOfMonth, month, year на табло не выводятся и в скетче не используются. Поэтому достаточно читать и писать в RTC только часы, минуты, сек.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

я еще в EEPROM запоминаю последние 16 выдержек с сортировкой по длительности и перезаписью, и по LongPress энкодера перебираю их.  За последние 2 года новых выдержек не появлялось, оказалось достаточно тех, что уже записаны. :)  

Pyotr
Offline
Зарегистрирован: 12.03.2014

А еще мне нравится библиотека   I2C.h    https://github.com/DSSCircuits/I2C-Master-Library

Пример

//==========================  Функция получения времени
void updateTime() {
  I2c.read(0x68, 0x00, 3);
  currSec = bcd2dec(I2c.receive() & 0x7f);// читаем секунды
  currMin = bcd2dec(I2c.receive());     // читаем минуты
  currHour = bcd2dec(I2c.receive());       // читаем часы
}
//Функция получения даты
void updateDate(void){
  I2c.read(0x68, 0x04, 2); 
  currDay = bcd2dec(I2c.receive());    // читаем день
  currMon = bcd2dec(I2c.receive());  // читаем месяц
}
//==========  Функция записи даты и времени в ds
void setDate_Time(byte mon, byte d, byte h, byte mint){
  byte arr[6] = {0x00, mint, h, 0x00, d, mon};//сек, мин, час, день недели, день, месяц
  I2c.write(0x68, 0x00, arr, 0x06);
}

 

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Согласен. Хотел TFT дисплей прилепить с выводом день недели, месяц. Что бы по русски. Но осталось как есть.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

/*****************************************************************

              Copyright (C) 2020 Александр

*****************************************************************/

#include <LedControl.h>
#include <Wire.h>
#include "GyverEncoder.h"

#include "DS3231.h"

/*
  Now we need a LedControl to work with.
 ***** These pin numbers will probably not work with your hardware *****
  pin 12 is connected to the DIn
  pin 11 is connected to the CLK
  pin 10 is connected to CS
  We have only a single MAX72XX.
*/
LedControl lc = LedControl(12, 11, 10, 1);

#define pin_CLK 3 // Энкодер пин A
#define pin_DT  4 // Энкодер пин B
#define pin_Btn 5 // Кнопка

Encoder enc1(pin_CLK, pin_DT, pin_Btn);

#define BUZZER  8               // сюда подключена пищалка

volatile boolean Start_timer;   // переключатель дисплея
boolean screenChange = false;   // enum
int currentScreen = 0;

volatile boolean flag;          // флаг секунд                      
volatile boolean flag_null = false;  // Флаг для гашения незначащего ноля на часах
uint8_t pause;                  // флаг паузы
uint8_t working;                // флаг работы

long newPosition = 0;           // значение энкодера
int _sec, _min, _hour;
int brightness = 12;            // Яркость  15
int DispFlag = 0;

int p_ress = 0;

enum ScreenID
{
  min2 = 1,
  min5,
  min10,
  min20,
  min30,
  min50,
  h1_00min,
  h1_20min,
  h1_50min,
  h2_00min,
  h2_50min,
  COUNT_ITEMS
};

//===================== прерывание от sqw ===============

/* Для мигания дисплея и отсчета */
void  blink()
{
  flag = !flag;
}

//********************* энкодер кнопка ****************//

void isrButton() {

  if (Start_timer) {
    if ( !working ) {
      working = 1;
      pause = !pause;
    }
    else pause = !pause;
  }
}

// ============= мигаем экраном =====================

void shimmer ()
{
  if (flag) brightness = 2;
  else brightness = 15;

  lc.setIntensity(0, brightness);
}

//============ отображение на дисплее ==============

void displey ()
{

// забиваем массив значениями для отпарвки на экран

  int8_t TimeDisp[6];

  TimeDisp[7] = hour / 10;
  TimeDisp[6] = hour % 10;
  TimeDisp[4] = minute / 10;
  TimeDisp[3] = minute % 10;
  TimeDisp[1] = second / 10;
  TimeDisp[0] = second % 10;

  int8_t TimeTime[6];

  TimeTime[7] = _hour / 10;     // Десятки часов  
  TimeTime[6] = _hour % 10;     // Единицы часов
  TimeTime[4] = _min / 10;      // Десятки минут
  TimeTime[3] = _min % 10;      // Единицы минут
  TimeTime[1] = _sec / 10;      // Десятки минут
  TimeTime[0] = _sec % 10;      // Единицы минут

  // выводим на экран
  //================= часы =====================

  if (!Start_timer) {

    brightness = 8;
    lc.setIntensity(0, brightness);

    if (TimeDisp[7] != 0)
    { // Если первое значение не 0, то выводим
      if (flag_null)flag_null = false;     // Сбросим флаг нуля
      lc.setDigit(0, 7, TimeDisp[7], false); // Вывод первой цифры
    }
    else
    { // Иначе гашение незначащего нуля
      // Гасим один первый раз при смене на 0
      if (!flag_null)
      {
        flag_null = true;               // Выставим флаг нуля
        lc.clearDisplay(0);             // Гашение экрана
      }
    }
    lc.setDigit(0, 6, TimeDisp[6], false);
    lc.setChar(0, 5, '-', false);
    lc.setDigit(0, 4, TimeDisp[4], false);
    lc.setDigit(0, 3, TimeDisp[3], false);
    lc.setChar(0, 2, '-', false);
    lc.setDigit(0, 1, TimeDisp[1], false);
    lc.setDigit(0, 0, TimeDisp[0], false);
  }

  //================ таймер ======================

  else {

    if ( _hour != 0 ) {

      if (TimeTime[7] != 0)
      { // Если первое значение не 0, то выводим
        if (flag_null)flag_null = false;
        lc.setDigit(0, 7, TimeTime[7], false);
      }
      else
      { // Иначе гашение незначащего нуля
        // Гасим один первый раз при смене на 0
        if (!flag_null)
        {
          flag_null = true;
          lc.clearDisplay(0);
        }
      }
      lc.setDigit(0, 6, TimeTime[6], false);
      lc.setChar(0, 5, '-', false);
      lc.setDigit(0, 4, TimeTime[4], false);
      lc.setDigit(0, 3, TimeTime[3], false);
      lc.setChar(0, 2, '-', false);
      lc.setDigit(0, 1, TimeTime[1], false);
      lc.setDigit(0, 0, TimeTime[0], false);
    }
    else {

      if (TimeTime[4] != 0)
      { // Если первое значение не 0, то выводим
        if (flag_null)flag_null = false;
        lc.setDigit(0, 4, TimeTime[4], false);
      }
      else
      { // Иначе гашение незначащего нуля
        // Гасим один первый раз при смене на 0
        if (!flag_null)
        {
          flag_null = true;
          lc.clearDisplay(0);
        }
      }
      lc.setDigit(0, 3, TimeTime[3], false);
      lc.setChar(0, 2, '-', false);
      lc.setDigit(0, 1, TimeTime[1], false);
      lc.setDigit(0, 0, TimeTime[0], false);
    }
    shimmer ();         // мигаем экраном
  }
}
//========== старт таймера ========================

void St_Timer ()
{

  if (_hour == 0 && _min == 0 && _sec == 0) stopOut();// если отсчитывать нечего, тогда и не запускаемся

  if ( pause == 1) {                        // начинаем отсчет
    if ( _sec > 0) _sec--;
    else
    {
      _sec = 59;
      if (_min > 0) _min--;
      else
      {
        _min = 59;
        if (_hour > 0) _hour--;
        else _hour = 0;
        lc.clearDisplay(0);
      }
    }
    if (_hour == 0 && _min == 0 && _sec == 0) displey (), Stop();
  }
  if (enc1.isHolded()) stopOut();                          // если была удержана и энк не поворачивался
}

//---------------------- стоп таймера -----------------------

void Stop () {

  stopOut();

  int i;
  int y;

  for (y = 0; y < 5; y++) {
    for (i = 0; i < 1000; i++)
    {
      digitalWrite(BUZZER, HIGH);
      delayMicroseconds(500);
      digitalWrite(BUZZER, LOW);
      delayMicroseconds(500);
    }
    delay(500);
  }
}

//-------------------------------------------------
void stopOut() {

  enc1.resetStates();
  // screenChange = false;
  currentScreen = 0;
  working = 0;
  Start_timer = false;
  pause = 0;
  _hour = _min = _sec = 0;
}

//=========== настройка времени таймера =========================

void setpoint () {

  do {

    enc1.tick();

    if (enc1.isRight()) newPosition++;    // если был поворот
    if (enc1.isLeft()) newPosition--;

    if (enc1.isFastR()) newPosition += 10;   // если был быстрый поворот направо, увеличиваем на 10
    if (enc1.isFastL()) newPosition -= 10;   // если был быстрый поворот налево, уменьшаем на 10

    _min = _min + newPosition;
    newPosition = 0;

    if (  _min > 59 )
    {
      _min = 0;
      _hour ++;
    }
    else if ( _min < 0 )
    {
      _min = 59;
      _hour --;
      lc.clearDisplay(0);
    }
    if ( _hour > 99 || _hour <= 0 ) _hour = 0;
    //   }
    displey ();
    p_ress = enc1.isHold();            // состояние кнопки
  } while (!p_ress);
}

//++++++++++++++++++ Настройка времени часов ++++++++++++++++++

void setupTimer() {

            process_DS3231();

  while (!p_ress) {

    enc1.tick();

    if (enc1.isLeft()) {            // если влево - минуты
      newPosition++;

      if (enc1.isFastL()) newPosition += 5;

      minute = minute + newPosition;
      newPosition = 0;

      if (minute > 59) minute = 0;
    }

    if (enc1.isRight()) {           // если вправо - часы
      newPosition++;

      if (enc1.isFastR()) newPosition += 5;

      hour = hour + newPosition;
      newPosition = 0;

      if (hour > 23) hour = 0;
    }
    
    if (enc1.isClick()) p_ress = 1;

    displey ();

  }
  setDateDs3231(second, minute, hour);     
}

//=================================================================

void setup()
{
  Serial.begin(115200);
  Serial.println("");

  Wire.begin();

  enc1.setType(TYPE2);        // тип энкодера

  setup_DS3231();

  pinMode(BUZZER, OUTPUT);
  delay (50);
  tone(BUZZER, 1000);          // диагностика звука
  delay(250);
  noTone(BUZZER);

  /*
    The MAX72XX is in power-saving mode on startup,
    we have to do a wakeup call
  */
  lc.shutdown(0, false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0, brightness);   // яркость 15
  /* and clear the display */
  lc.clearDisplay(0);            // очистка дисплея

  noInterrupts();
  attachInterrupt(0, blink, CHANGE); //  прерывание от смены секунд
  interrupts();

// зажимаем кнопку энкодера, включаем питание - 
//переходим к настройке часов. Кнопкой запись и выход

  if (!digitalRead(5)) setupTimer();                       

}

//===============================================================

void loop ()
{

  enc1.tick();

  if (enc1.isClick()) isrButton();// пуск\пауза счета    


  process_DS3231();

  displey ();

  if ( !working ) {

    if (enc1.isRight()) {   // если вправо - настройка времени таймера

      Start_timer = true;

      lc.clearDisplay(0);
      p_ress = 0;

      _hour = 0;
      _min = 0;
      _sec = 0;

      setpoint ();
    }

    if (enc1.isLeft()) {   // если влево - выбор предустановленных параметров

      Start_timer = true;

      screenChange = true;    // флаг, что экран надо перерисовать
      currentScreen++;        // переходим на следующий экран
      if (currentScreen == COUNT_ITEMS) {
        currentScreen = min2;
      }
      /////// обработчик экранов дисплея
      if (screenChange)
      {
        lc.clearDisplay(0);
        screenChange = false;
        switch (currentScreen)
        {
          case min2:
            _hour = 0;
            _min = 2;
            _sec = 0;
            break;

          case min5:
            _hour = 0;
            _min = 5;
            _sec = 0;
            break;

          case min10:
            _hour = 0;
            _min = 10;
            _sec = 0;
            break;

          case min20:
            _hour = 0;
            _min = 20;
            _sec = 0;
            break;

          case min30:
            _hour = 0;
            _min = 30;
            _sec = 0;
            break;

          case min50:
            _hour = 0;
            _min = 50;
            _sec = 0;
            break;

          case h1_00min:
            _hour = 1;
            _min = 0;
            _sec = 0;
            break;

          case h1_20min:
            _hour = 1;
            _min = 20;
            _sec = 0;
            break;

          case h1_50min:
            _hour = 1;
            _min = 50;
            _sec = 0;
            break;

          case h2_00min:
            _hour = 2;
            _min = 0;
            _sec = 0;
            break;

          case h2_50min:
            _hour = 2;
            _min = 50;
            _sec = 0;
            break;
        }
      }
    }
  }

  if (Start_timer) {
    if ( flag && DispFlag == 0) { // 1 раз в сек обновляем дисплей в режиме таймера
      DispFlag ++;

      St_Timer();

    }
    if ( !flag && DispFlag == 1) {
      DispFlag = 0;
    }
  }

  // delay(500);

}

Внес исправления по замечаниям Pyotr пост 3

Ralgxi
Offline
Зарегистрирован: 16.08.2021
DS3231.h


#ifndef DS3231_h
#define DS3231_h

#define DS3231_I2C_ADDRESS 0x68

byte second, minute, hour;

/**********************
 **** Подпрограммы ****
 **********************/
/* часы .. */
byte decToBcd(byte val)
{
  return ((val / 10 * 16) + (val % 10));
}
byte bcdToDec(byte val)
{
  return ((val / 16 * 10) + (val % 16));
}

/* Установка данных в модуль RTC3231 */
void setDateDs3231(byte second,        // 0-59
                   byte minute,        // 0-59
                   byte hour)           // 1-23
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.endTransmission();
}

/* Получение данных с модуля RTC DS3231 */
void getDateDs3231
(
  byte *second,
  byte *minute,
  byte *hour
)
{
  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);
}

//==============================================================

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

//===============================================================

void setup_DS3231()
{
  setINT();                           // Включаем выход SQW на RTC3231
}

void process_DS3231()
{

  // читаем время из модуля

  getDateDs3231(&second, &minute, &hour);

}

#endif