// Автономный DDS на базе Arduino Nano (ATMega328p) + HC-SR08 (DDS AD9850)
// Поддержка перестройки частоты по USB и двумя кнопками
// Разработчик: Бадло Сергей Григорьевич
// H-page: http://raxp.radioliga.com

#include <EEPROM.h>

// соответствие пинов подключений
#define W_CLK 8   // 8  - W_CLK AD9850
#define FQ_UD 9   // 9  - F_EN AD9850
#define DATA 10   // 10 - DATA AD9850
#define RESET 11  // 11 - Reset AD9850

#define upp 1   // 1 — KEY 1 UP FREQ
#define dwn 2  // 2 — KEY 2 DOWN FREQ
long prevms = 0; 

#define pulse(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
int_fast32_t timepassed = millis(); // задержка

int_fast32_t rx=1000000; // начальное значение частоты DDS, Гц
int_fast32_t rx2=1;      // temp при новой частоте
int incbutton = 0;

byte ones, tens, gekto, kilo, tenkilo, gektokilo, mega, tenmega;
String freq;            // значение частоты
int flag_eeprom = 1;    // флаг разрешения записи в EEPROM по "0"
int ForceFreq = 0;      // установить в "0" для активации EEPROM


void setup() {
  Serial.begin(19200);

  pinMode(upp, INPUT);   // кнопку вешаем на землю, 
  digitalWrite(upp, HIGH); // вход подтягиваем на питание
  pinMode(dwn, INPUT);   // кнопку вешаем на землю, 
  digitalWrite(dwn, HIGH); // вход подтягиваем на питание
  
  // настраиваем на выход
  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT); 
  
  pulse(RESET); // Reset
  pulse(W_CLK); // ТИ
  pulse(FQ_UD); // флаг разрешения выдачи

   // грузим из EEPROM сохраненное значение частоты  
  if (ForceFreq == 0) {
    freq = String(EEPROM.read(0))+String(EEPROM.read(1))+String(EEPROM.read(2))+String(EEPROM.read(3))+String(EEPROM.read(4))+String(EEPROM.read(5))+String(EEPROM.read(6))+String(EEPROM.read(7));
    rx = freq.toInt();  
  }
}


// бесконечный цикл проверки новой частоты, установки
// запись в EEPROM по флагу + чтение кнопки + чтение Serial
void loop() {
  
  // чтение пакета с преобразованием массива принятых в единое число в INT
  if (Serial.available() > 0) {
      rx = Serial.parseInt();
      Serial.write(rx); // контроль эха в ASCII
  }
      
  // читаем замыкание на землю
  // сложное условие на все кнопки
   if (digitalRead(upp)==LOW  || digitalRead(dwn)==LOW) { 
   
     // если > 100 мc 
     if (millis() - prevms > 100) { 
       prevms = millis(); 
     
       // первая комбинация
       if (digitalRead(upp)==LOW) {
        rx++;
       }
       // вторая комбинация
       if (digitalRead(dwn)==LOW) {
        rx--;
       }
     }
   };

  // если предыдущее значение частоты <> новому
  if (rx!= rx2){          
        showFreq();        // пересчет частоты по мантиссе и поднятие флага разрешения записи в EEPROM = 0
        sendFrequency(rx); // установка частоты по SPI
        rx2 = rx;          // запоминаем новое значение частоты для последующего сравнения
  }

  // если поднят флаг разрешения записи в EEPROM = 0
  if(flag_eeprom == 0){   
   if(timepassed+2000 < millis()){ // ждем 2 сек
    saveEEPROM(); // запись в EEPROM
   }
  }   
}


// установка частоты page 8 = 125 000 000 * Fnew/2^32
void sendFrequency(double frequency) {  
  int32_t freq = frequency * 4294967295/125000000; 
  for (int b=0; b<4; b++, freq>>=8) {
    tx_byte(freq & 0xFF);
  }
  tx_byte(0x000); // control byte for 9850 chip
  pulse(FQ_UD);   // разрешаем выдачу
}


// передача младшими битами вперед 32-х битного слова частоты на DATA (оставшиеся из 40-32 бит = 8, 3 бита под режимы)
void tx_byte(byte data) {
  for (int i=0; i<8; i++, data>>=1) {
    digitalWrite(DATA, data & 0x01);
    pulse(W_CLK); 
  }
}


// пересчет частоты
void showFreq() {
   tenmega = ((rx/10000000)%10);
   mega = ((rx/1000000)%10);
   gektokilo = ((rx/100000)%10);
   tenkilo = ((rx/10000)%10);
   kilo = ((rx/1000)%10);
   gekto = ((rx/100)%10);
   tens = ((rx/10)%10);
   ones = ((rx/1)%10);

   timepassed = millis();
   flag_eeprom = 0; // поднимаем флаг разрешения записи частоты в EEPROM
};


// запись в EEPROM
void saveEEPROM() {
   EEPROM.write(0, tenmega);   // 10 000 000
   EEPROM.write(1, mega);      // 1000 000
   EEPROM.write(2, gektokilo); // 100 000
   EEPROM.write(3, tenkilo);   // 10 000
   EEPROM.write(4, kilo);      // 1000
   EEPROM.write(5, gekto);     // 100     
   EEPROM.write(6, tens);      // 10
   EEPROM.write(7, ones);      // единицы 
   flag_eeprom = 1;
}; 