#define buzzer 3 //вывод для работы будльника 
#define DS 8 //линия для передачи данных
#define SH 7 //сдвиг разряда на единицу
#define ST 4 //установка режима ввода или вывода данных

//создадим "библиотеку" кодов 
//коды чисел на индикаторе
byte digitsArr[10]={
  0b11000000, //число 0
  0b11111001, //число 1
  0b10100100, //число 2
  0b10110000, //число 3
  0b10011001, //число 4
  0b10010010, //число 5
  0b10000010, //число 6
  0b11111000, //число 7
  0b10000000, //число 8
  0b10010000, //число 9
};

//коды числе с точкой на индикаторе
byte digitsDotArr[10]={
  0b01000000, //число 0
  0b01111001, //число 1
  0b00100100, //число 2
  0b00110000, //число 3
  0b00011001, //число 4
  0b00010010, //число 5
  0b00000010, //число 6
  0b01111000, //число 7
  0b00000000, //число 8
  0b00010000, //число 9
};

//коды выбора разряда числа
byte regArr[4]={
  0b11111000, //разряд 0
  0b11110100, //разряд 1
  0b11110010, //разряд 2
  0b11110001, //разряд 3
};

// массив для удобного вывода
byte chArr[4]={0,0,0,0}; //Массив для вывода значений таймера времени и предустановки времени
byte chArrB[4]={0,0,0,0}; //Массив для вывода значений предустановки будильника

//Переменные для задания работы счетчика
int number = 0;
int MIN = 0;
int HOUR = 0;

//Переменные для задания времени срабатывания будильника
int numberB = 0;
int MINB = 0;
int HOURB = 0;

//Переменные для независимого выполнения функций программы
unsigned long timer;
unsigned long timer2;
unsigned long timer3;
unsigned long timer4;


int LED_D1 = 10;                // Указываем вывод светодиода
int LED_D2 = 11;                // Указываем вывод светодиода
int LED_D3 = 12;                // Указываем вывод светодиода
int butt_1 = A1;                // Указываем вывод кнопки
int butt_2 = A2;                // Указываем вывод кнопки
int butt_3 = A3;                // Указываем вывод кнопки

//Переменные для записи значений с кнопок
int VAL; 
int VAL1; 
int VAL2; 
int VAL3; 

//Флаги для расстановки 
//приоритетов выполнения программы
int START = 0;
int START1 = 0;
int START2 = 0;
int START3 = 0;
int START4 = 0;

void setup (){
  
  pinMode(DS,OUTPUT); // Устанавливаем вывод как выход
  pinMode(SH,OUTPUT); // Устанавливаем вывод как выход
  pinMode(ST,OUTPUT); // Устанавливаем вывод как выход

  pinMode(LED_D1, OUTPUT);       // Устанавливаем вывод как выход
  pinMode(LED_D2, OUTPUT);       // Устанавливаем вывод как выход
  pinMode(LED_D3, OUTPUT);       // Устанавливаем вывод как выход
  pinMode(butt_1, INPUT);        // Устанавливаем вывод как вход
  pinMode(butt_2, INPUT);        // Устанавливаем вывод как вход
  pinMode(butt_3, INPUT);        // Устанавливаем вывод как вход

  pinMode(buzzer ,  OUTPUT);     // Устанавливаем вывод как выход
  digitalWrite(buzzer, HIGH);    // Выключаем звук зуммера
}

void loop(){ 

    // индикация работы кнопок 
  VAL=digitalRead(butt_1);       // Считываем данные порта в переменную VAL
  if (VAL == LOW){digitalWrite(LED_D1, LOW);}
  else           {digitalWrite(LED_D1,HIGH);}
   
   VAL=digitalRead(butt_2);       // Считываем данные порта в переменную VAL
  if (VAL == LOW){digitalWrite(LED_D2, LOW);}
  else           {digitalWrite(LED_D2,HIGH);}
   
  VAL=digitalRead(butt_3);       // Считываем данные порта в переменную VAL
  if (VAL == LOW){digitalWrite(LED_D3, LOW);}
  else           {digitalWrite(LED_D3,HIGH);}

// переменные на каждую кнопку в отдельности
  VAL1=digitalRead(butt_1);    
  VAL2=digitalRead(butt_2); 
  VAL3=digitalRead(butt_3); 


// предустановка изначального времени
if (millis() - timer2 > 100) {
      timer2 = millis();
  while (VAL1==LOW && START1==0 && START3==0){ //запуск предустановки времени по умолчанию по флагам Старт и Старт3
      if (VAL2==LOW){
        //Формирование значений по нажатию кнопок
        MIN=MIN+1;
         if (MIN > 59) 
        MIN = 0;
      }
       if (VAL3==LOW){
        HOUR=HOUR+1;
      if (HOUR>23)
        HOUR=0;
      }

      number=100*HOUR+MIN; //Формирование значений для вывода на дисплей

      int thousands = number/1000%10; //выделяем десятки часов
      int hundreds = number/100%10;   //выделяем единицы часов
      int tens = number/10%10;        //выделяем десятки минут
      int unit = number%10;           //выделяем единицы минут
      
      //записываем в массив для удобного использования
      chArr[0]=unit;
      chArr[1]=tens;
      chArr[2]=hundreds;
      chArr[3]=thousands;

      //возвращение кнопок в положение по умолчанию
    VAL1=HIGH;
    VAL2=HIGH;
    VAL3=HIGH;
  }
if (VAL2==LOW && VAL1==HIGH && VAL3==HIGH){START1 = 1; START3=1; } // описание того, что мы завершили предустановку по нажатию кпонки 2. 
//Старт 1 - флаг для возможности запуска предустановки будильника
//Старт 3 отключает возможность повторной предустановки времени и освобождает кнопки
}


// предустановка будильника после установки времени по флагу Старт 1
if (millis() - timer3 > 100) {
      timer3 = millis();
      if (START1 == 1 && START4==0) { //Запуск функции только по Флагам Старт1 и Старт 4. Только после завершения предустановки времени
  while (VAL3==LOW){
      if (VAL2==LOW){
        //Формирование значений по нажатию кнопок
        MINB=MINB+1;
         if (MINB > 59) 
        MINB = 0;
      }
       if (VAL1==LOW){
        HOURB=HOURB+1;
      if (HOURB>23)
        HOURB=0;
      }

      numberB=100*HOURB+MINB; //Формирование значений для вывода на дисплей

      int thousandsB = numberB/1000%10; //выделяем десятки часов
      int hundredsB = numberB/100%10;   //выделяем единицы часов
      int tensB = numberB/10%10;        //выделяем десятки минут
      int unitB = numberB%10;           //выделяем единицы минут
      
      //записываем в массив для удобного использования
      chArrB[0]=unitB;
      chArrB[1]=tensB;
      chArrB[2]=hundredsB;
      chArrB[3]=thousandsB;
      
      //возвращение кнопок в положение по умолчанию
    VAL1=HIGH;
    VAL2=HIGH;
    VAL3=HIGH;
  }
if (VAL1==LOW && VAL2==HIGH && VAL3==HIGH){START2 = 1; START4=1; }// описание того, что мы завершили предустановку по нажатию кпонки 1
//Старт 2 - флаг для возможности запуска таймера времени
//Старт 4 отключает возможность повторной предустановки будильника 
}
}


  //таймер "реального времени"
  
  if (millis() - timer > 1005) {
      timer = millis();
if (START2 == 1) START=1;     // Запуск функции по фрагу Старт2, т.е после завершения всех предустановок. Флагом Старт1 разрешаем запуск основного таймера
while (START2 == 1 && START==1) {
  //Формирование значений по внутреннему таймеру
      MIN = MIN + 1;
      if (MIN > 59) { 
        MIN = 0;
        HOUR = HOUR + 1; 
      }
      if (HOUR>23){
        MIN=0;
        HOUR=0;
      }

       //формируем число для вывода на индикатор
      number=100*HOUR+MIN;

      int thousands = number/1000%10; //выделяем десятки часов
      int hundreds = number/100%10;   //выделяем единицы часов
      int tens = number/10%10;        //выделяем десятки минут
      int unit = number%10;           //выделяем единицы минут
      
      //записываем в массив для удобного использования
      chArr[0]=unit;
      chArr[1]=tens;
      chArr[2]=hundreds;
      chArr[3]=thousands;
      START = 0; // фозвращаем значение Флага Старт1 для корректной работы структкры Вайл
   }
 if (START2 == 1) START=1; // Проверка по значений Флага2 закончена ли предустановка и можно ли начинать выполнение. 
}


  // индикация установка времени
  if (START3==0) {//индикация предустановки включена по умолчанию и выключании при окончании по флагу Старт3 вместе с отключением функции предустановки времени
  for (int i = 0; i<4; i++){
    
    //вывод числа с точной во втором разряде и без точки в остальных
    if (i==2){
      digitalWrite(ST, LOW); //Устанавливаем на 12х выводах регистров режим ввода данных
      shiftOut(DS, SH, MSBFIRST, digitsDotArr[chArr[i]]); //Запись информации в правый регистр
      shiftOut(DS, SH, MSBFIRST, regArr[i]);    //Запись информации в левый регистр
      digitalWrite(ST, HIGH); //Устанавливаем на 12х выводах регистров режим вывода данных
    }
    
    else {
      digitalWrite(ST, LOW); //Устанавливаем на 12х выводах регистров режим ввода данных
      shiftOut(DS, SH, MSBFIRST, digitsArr[chArr[i]]); //Запись информации в правый регистр
      shiftOut(DS, SH, MSBFIRST, regArr[i]);    //Запись информации в левый регистр
      digitalWrite(ST, HIGH); //Устанавливаем на 12х выводах регистров режим вывода данных
    }
  }
  }


 if (START4==1){
  
  
   if (HOUR==HOURB && MIN==MINB){
      digitalWrite(buzzer, LOW);
     
   }
   else{
   
   digitalWrite(buzzer, HIGH);
   }
 }
   
   
 
 
  


   
  

// индикация предустановки будильника. Включается по флагам Старт1 и Старт4. После завершения предустановки времени и до момоента завершения предустановки будтльника.
      if (START1==1 && START4==0) {
  for (int i = 0; i<4; i++){
    
    //вывод числа с точной во втором разряде и без точки в остальных
    if (i==2){
      digitalWrite(ST, LOW); //Устанавливаем на 12х выводах регистров режим ввода данных
      shiftOut(DS, SH, MSBFIRST, digitsDotArr[chArrB[i]]); //Запись информации в правый регистр
      shiftOut(DS, SH, MSBFIRST, regArr[i]);    //Запись информации в левый регистр
      digitalWrite(ST, HIGH); //Устанавливаем на 12х выводах регистров режим вывода данных
    }
    
    else {
      digitalWrite(ST, LOW); //Устанавливаем на 12х выводах регистров режим ввода данных
      shiftOut(DS, SH, MSBFIRST, digitsArr[chArrB[i]]); //Запись информации в правый регистр
      shiftOut(DS, SH, MSBFIRST, regArr[i]);    //Запись информации в левый регистр
      digitalWrite(ST, HIGH); //Устанавливаем на 12х выводах регистров режим вывода данных
    }
  }
  }

 //Индикация счетчика времени. Включается по флагам Старт1, Старт2, Старт3, Старт4. После завершения всех предустановок.
  if (START2==1 && START4==1) { 
  for (int i = 0; i<4; i++){
    
    //вывод числа с точной во втором разряде и без точки в остальных
    if (i==2){
      digitalWrite(ST, LOW); //Устанавливаем на 12х выводах регистров режим ввода данных
      shiftOut(DS, SH, MSBFIRST, digitsDotArr[chArr[i]]); //Запись информации в правый регистр
      shiftOut(DS, SH, MSBFIRST, regArr[i]);    //Запись информации в левый регистр
      digitalWrite(ST, HIGH); //Устанавливаем на 12х выводах регистров режим вывода данных
    }
    
    else {
      digitalWrite(ST, LOW); //Устанавливаем на 12х выводах регистров режим ввода данных
      shiftOut(DS, SH, MSBFIRST, digitsArr[chArr[i]]); //Запись информации в правый регистр
      shiftOut(DS, SH, MSBFIRST, regArr[i]);    //Запись информации в левый регистр
      digitalWrite(ST, HIGH); //Устанавливаем на 12х выводах регистров режим вывода данных
    }
  }
  }
 }


  


