#include<SPI.h> 
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd (0x27, 16,2); // Создание объекта lcd для работы с ЖК-дисплеем.
#define FSYNC 4 // Определение пина FSYNC.

#define WAVE_SINE     0x2000 // Определение типов волн: синусоидальная, прямоугольная, треугольная.
#define WAVE_SQUARE   0x2028
#define WAVE_TRIANGLE 0x2002
// Определение пинов кнопок для управления частотой и функцией генератора.
#define b_UP    5 
#define b_DOWN  17
#define b_MULTI 15
#define b_FUNC  1

long int counter = 0;  // Установка начальной частоты.
long int counter_ant = 0; // Переменная для хранения предыдущей частоты.
long int function = 0; // Переменная для хранения типа волны (синусоидальная, прямоугольная, треугольная).
long int function_ant = 0; // Переменная для хранения предыдущего типа волны.
int multi = 0; // Переменная для хранения текущей степени десяти.
int func = 0; // Переменная для хранения текущей функции.
int func_ant = 0; // Переменная для хранения предыдущей функции.
const byte pwm_pin = 25; // Установка пина для ШИМ мигнала.
const byte pot_pin = 12; // Установка пина потенциометра.
int potValue = analogRead(pot_pin); // Считываем показания с потенциометра.
int duty = map(potValue, 0, 4095, 0, 255); // Определяем скважность ШИМ.



void AD9833setup(){ // Функция настройки генератора.
   pinMode(FSYNC, OUTPUT); // Установка пина FSYNC на выход.
   digitalWrite(FSYNC, HIGH); 
   SPI.begin(); 
   delay(50); 
   AD9833reset(); 
}

void AD9833reset(){ // Функция сброса генератора.
   WriteRegister(0x100); // Отправка сигнала сброса.
   delay(10); // Задержка 10 миллисекунд.
}

void AD9833setFrequency(long frequency, int Waveform){ // Функция установки частоты и типа волны.
   long FreqWord = (frequency * pow(2, 28)) / 25.0E6; // Расчет значения частоты.
   int MSB = (int)((FreqWord & 0xFFFC000) >> 14); 
   int LSB = (int)(FreqWord & 0x3FFF); 
   LSB |= 0x4000;
   MSB |= 0x4000; 
   WriteRegister(0x2100);   
   WriteRegister(LSB);
   WriteRegister(MSB);
   WriteRegister(0xC000);
   WriteRegister(Waveform);
}
//записываем данные в AD9833
void WriteRegister(int dat){ 
   SPI.setDataMode(SPI_MODE2);        
   digitalWrite(FSYNC, LOW);
   delayMicroseconds(10); 
   SPI.transfer(dat>>8);
   SPI.transfer(dat&0xFF);
   digitalWrite(FSYNC, HIGH);
   SPI.setDataMode(SPI_MODE0);
}

void setup(){
   ledcAttachPin (pwm_pin,0); // Определения канала ШИМ.
   ledcSetup(0,10000,8); // Настройки ШИМ сигнала (10 кГц, 8 бит).
   Serial.begin(9600);
   AD9833setup();
   pinMode(b_UP, INPUT_PULLUP);
   pinMode(b_DOWN,INPUT_PULLUP);
   pinMode(b_MULTI,INPUT_PULLUP);
   pinMode(b_FUNC,INPUT_PULLUP);
   //инциализация дисплея
   lcd.init ();
   lcd.setCursor(0, 0);
   lcd.print("Wafeform Generat");
   lcd.backlight ();
   lcd.setCursor(1, 3);
   lcd.print("ChepurkoM 2023");
   delay(5000);
   lcd.clear();

}
//обновление информации 
void actualiza_func(){
   if(!digitalRead(b_FUNC)){
      delay(50);
      if(!digitalRead(b_FUNC)){ 
         if(func_ant == 0)
            func = 1;
         if(func_ant == 1)
            func = 2;
         if(func_ant == 2)
            func = 0;
         func_ant = func;
         if(func_ant == 3)
            func = 3;
         func_ant = func;
      }
   }
   if(func == 0){
      lcd.setCursor(6, 1);
      lcd.print("      SINE");
      function = WAVE_SINE;
   }
   if(func == 1){
      lcd.setCursor(6, 1);
      lcd.print("  TRIANGLE");
      function = WAVE_TRIANGLE;
   }
   if(func == 2){
      lcd.setCursor(6, 1);
      lcd.print("  SQUARE");
      function = WAVE_SQUARE;
   }
   if(func == 3){
      lcd.setCursor(6, 1);
      lcd.print("     PWM");
      function = WAVE_SQUARE;
   }
   if(counter_ant != counter || function_ant != function){
      AD9833setFrequency(counter, function);
   }
   counter_ant = counter;
   function_ant = function;
}

void limpiaDigitos(){
   if(counter < 100){
      lcd.setCursor(2, 0);
      lcd.print("      ");  
   }else{
      if(counter < 1000){
         lcd.setCursor(3, 0);
         lcd.print("     "); 
      }else{
         if(counter < 10000){
            lcd.setCursor(4, 0);
            lcd.print("    "); 
         }else{
            if(counter < 100000){
               lcd.setCursor(5, 0);
               lcd.print("   "); 
            }else{
               if(counter < 1000000){
                  lcd.setCursor(6, 0);
                  lcd.print("  "); 
               }else{
                  if(counter < 1999000){
                     lcd.setCursor(7, 0);
                     lcd.print(" "); 
                  }
               }
            }
         }
      }                
   }
}
void PWM(){
    int potValue = analogRead(pot_pin); // Считываем показания с потенциометра.
    int duty = map(potValue, 0, 4095, 0, 255); // Определяем скважность ШИМ.
    ledcWrite(0,duty);
}
void loop(){ 
   PWM();
   switch(multi){
   case 0:
      if(!digitalRead(b_MULTI)){ 
         delay(50);
         if(!digitalRead(b_MULTI)){ 
            multi = 1;
         }
      }
      if(!digitalRead(b_UP)){ 
         delay(50);
         if(!digitalRead(b_UP)){ 
            counter++;
         }
      }
      if(!digitalRead(b_DOWN)){ 
         delay(50);
         if(!digitalRead(b_DOWN)){ 
            if(counter>0)
               counter--;
         }
      }
      lcd.setCursor(0, 1);
      lcd.print("10^0");
      lcd.setCursor(14, 0);
      lcd.print("Hz");
      lcd.setCursor(0, 0);
      lcd.print(counter);
      limpiaDigitos();
      actualiza_func();
      break;
   case 1:
      if(!digitalRead(b_MULTI)){ 
         delay(50);
         if(!digitalRead(b_MULTI)){ 
            multi = 2;
         }
      }
      if(!digitalRead(b_UP)){ 
         delay(50);
         if(!digitalRead(b_UP)){ 
            counter = counter + 1000;
         }
      }
      if(!digitalRead(b_DOWN)){ 
         delay(50);
         if(!digitalRead(b_DOWN)){ 
            if(counter>1000)
               counter = counter - 1000;
         }
      }
      lcd.setCursor(0, 1);
      lcd.print("10^3");
      lcd.setCursor(14, 0);
      lcd.print("Hz");
      lcd.setCursor(0, 0);
      lcd.print(counter);
      limpiaDigitos();
      actualiza_func();
      break;
   case 2:
      if(!digitalRead(b_MULTI)){ 
         delay(50);
         if(!digitalRead(b_MULTI)){ 
            multi = 0;
         }
      }
      if(!digitalRead(b_UP)){ 
         delay(50);
         if(!digitalRead(b_UP)){ 
            if(counter<1000000)
               counter = counter + 1000000;
         }
      }
      if(!digitalRead(b_DOWN)){ 
         delay(50);
         if(!digitalRead(b_DOWN)){ 
            if(counter>1000000)
               counter = counter - 1000000;
         }
      }
      lcd.setCursor(0, 1);
      lcd.print("10^6");
      lcd.setCursor(14, 0);
      lcd.print("Hz");
      lcd.setCursor(0, 0);
      lcd.print(counter);
      limpiaDigitos();
      actualiza_func();
      break;
   }
}