// kod pro ovladani motorku - zapnuti, vypnuti, rychlost, zobrazeni rychlosti v ot./min = RPM, zobrazeni stavu baterie
// Natálie Rexová
 
#include <LiquidCrystal.h>                          // nacteni knihovny pro praci s displejem
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);              // specifikace pinu pouzitych pro displej

const float referenceVolts = 5.0;                   // vychozi reference pro 5V desku
const int bateriePin = 0;                           // pripojeni baterie k pinu A0

int motorSpeed = 200;                               // hdonota urcujici rychlost motorku 0-255
int motorPin = 9;                                   // pripojeni tranzistoru k pinu D9
int spinacPin = 3;                                  // pripojeni spinace k pinu D3
int spinacState = 0;                                // vychozi stav spinace
int potenciometr = 5;                               // pripojeni potenciometru k pinu A5

const int pocet_prumer = 10;                        // zprumerovani deseti hodnot
int detekce[pocet_prumer];
unsigned long prumer = 0;                           // promenna pro zapis zprumerovanych hodnot
int index = 0;
unsigned long celkem; 
volatile int pocet_detekci = 0;                     // promenna pro zapis poctu detekci  
unsigned long rpm = 0;
unsigned long posledni_detekce = 0;                 // posledni cas detekce

void setup(){
  
 Serial.begin(9600);                                // seriovy port s prenosovou rychlosti 9600bps
  
 pinMode(motorPin, OUTPUT);                         // vystup pro motorek
 pinMode(spinacPin, INPUT);                         // vstup pro spinac
 pinMode(5,INPUT); //vsup pro potenciometr
 attachInterrupt(0, rpm_mot, RISING);               // interruptnumber 0 = pin number 2; rpm_mot je funkce, která se zavolá vždy při změně napětí na pinu 2; 
                                                    // RISING je mód, který určuje, že je fce rpm_mot zavolána při změně napěí z nuly 

 lcd.begin(16, 2);                                  // specifikace typu displeje 16x2
 lcd.print("Nahravam");                             // vypsani zpravy pri prvni inicializaci kodu
 delay(1000);                                       // cekani jednu sekundu
 lcd.clear();                                       // vymazani zpravy
}

void loop(){
  
int val = analogRead(bateriePin);                   // precteni hodnoty z pinu pro baterii 
float volts = (val / 1023.0) * referenceVolts;      // vypocet realne hodnoty 
Serial.println(volts);                              // zobrazeni hodnoty ve voltech v seriovém monitoru
delay(500);                                         // cekani pul sekundy

int value = analogRead(potenciometr);               // precteni hodnoty z pinu pro potenciometr, v rozsahu 0-1023
int motorSpeed = value/4;                           // prepocet, PWM zobrazuje 255 ruznych hodnot

spinacState = digitalRead(spinacPin);               // precteni hodnoty z pinu pro spinac
  if(spinacState == HIGH){
    analogWrite(motorPin, motorSpeed);              // pokud je spinac sepnuty, motor bezi dle hodnoty motorSpeed
  }else{
    analogWrite(motorPin, 0);                       // pokud spinac sepnuty neni motor je vypnuty
   }
   
  if (millis() - posledni_detekce >= 1000){         // aktualizace proměnné pocet_otacek každou sekundu, to je rovno frekvenci otáček
 
 detachInterrupt(0);                                // zakaz interrupts pri vypoctu
 celkem = 0;  
 detekce[index] = pocet_detekci * 60;               // přepočet frekvence na ot./min  
 for (int x=0; x<=9; x++){
   celkem = celkem + detekce[x];
 }
 
 prumer = celkem / pocet_prumer;                    // výpočet průměru z každých deseti detekcí.
 rpm = prumer; 
 pocet_detekci = 0;                                 // restartování proměnné pocet_otacek
 index++;
 if(index >= pocet_prumer){
  index=0; 
 }  
 
if (millis() > 11000){                              // cekani na ustaleni zprumerovani

 Serial.print(" RPM = ");                           // vypsani vyslednych hodnot do serioveho monitoru
 Serial.println(rpm);

 // Zobrazeni hodnot na displeji
 lcd.clear();
 lcd.setCursor(0, 1);                               // prvni sloupec, druhy radek
 lcd.print("Baterie:");                             // zobrazeni slova Baterie
 lcd.print(volts);                                  // zobrazeni stavu baterie ve voltech
 lcd.setCursor(0, 0);                               // (column,row) //prvni sloupec, prvni radek
 lcd.print("Rychlost:");                            // zobrazeni slova Rychlost
 
//Prevod hodnoty rpm do ASCII retezce
  char  rpm_string[4];                              // uchovani retezce o ctyrech znacich
  sprintf(rpm_string, "%4d", rpm);   
  lcd.print(rpm_string); 
  }
 
 posledni_detekce = millis();                       // aktualizace promenne posledni_detekce
  attachInterrupt(0, rpm_mot, FALLING);             // opetovane umozneni interrupts
  }
}

void rpm_mot(){                                     // kod se provede pokazde kdyz je detekovana zmena napeti na pinu 2
  pocet_detekci++;
}


