/*
 * Attiny13A Odpojovac
 * Created: 24.08.2024 10:15:50
 * Author : mdudk
 */ 

// Clock 9.6MHz/8 = 1.2MHz
// PB3 ADC input (divider from battery 2M2 + 1M || 100n)
// PB4 MOSFET output 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

#define TURN_OFF_THR 695 // 11.0V
#define TURN_ON_THR 755 // 12.0V
#define DISABLE_LOAD PORTB &=~(1<<4) // vypnout MOSFET (zátěž)
#define ENABLE_LOAD PORTB |= (1<<4) // zapnout MOSFET (zátěž)

uint16_t get_volt(void);
uint16_t volt; // změřené napětí
uint8_t counter=0; // jednoduchý filtr

// Rutina přerušení od "watchdog timeru"
ISR(WDT_vect) {
 asm("nop"); // není co dělat, jde jen o to se probudit
}

int main(void){
 PRR = (1<<PRTIM0) | (1<<PRADC); // vypnout clock periferiím
 ACSR = (1<<ACD); // vypnout komparátor
 DDRB = 1<<4; // nastavit PB4 jako výstup (MOSFET)
 PORTB = 0b100111; // zapnout pullup rezistory na nevyužitých pinech
 ADMUX = 0b11; // Zvolit VCC jako refrenci pro ADC a jako vstup pin PB3 (ADC3)
 DIDR0 = 0b111111; // Vypnout vstupní buffery na všech pinech 
 WDTCR |= (1<<WDP3); // Perioda pro watchdog přibližně 4s
 WDTCR |= (1<<WDTIE); // spustit watchdog v režimu "časovače"
 sei(); // globální povolení přerušení
 set_sleep_mode(SLEEP_MODE_PWR_DOWN); // volím režim spánku Power Down (nejhlubší)
 
 while (1){ // kdykoli se čip probudí
	 	
  volt = get_volt(); // změří napětí
  if(volt < TURN_OFF_THR){ // pokud je menší jak "vypínací" napětí
   if(counter > 3){ // alespoň třikrát po sobě
    DISABLE_LOAD; // tak vypne zátěž
   }else{ // pokud ještě nebylo třikrát po sobě
    counter++; // započítá ho
   }
  }else if(volt > TURN_ON_THR){ // pokud je napětí větší jak "zapínací"
   if(counter > 3){ // alespoň třikrát po sobě
    ENABLE_LOAD; // zapne zátěž
   }else{
    counter++;
   }
  }else{ // jinak nuluje počítadlo / filtr
   counter = 0;
  }
  sleep_mode(); // MCU jde spát
  asm("nop"); // to je tu asi zbytečně (možná jsem to tam měl kvůli debugu)
  asm("nop"); // to je tu asi zbytečně
 }
}

// funkce pro měření napětí
uint16_t get_volt(void){
 uint16_t tmp;
 
 PRR &=~(1<<PRADC); // nejprve zpět povolí clock pro ADC
 DIDR0 = 0b111111; // tohle je tu asi navíc
 ADMUX = 0b11; // Zvolit VCC jako refrenci pro ADC a jako vstup pin PB3 (ADC3)
 ADCSRA = (1<<ADEN) | (1<<ADPS1); // Zapne ADC s clokem 1.2MHz / 4 = 300kHz
 ADCSRA |= (1<<ADSC); // spustí převod
 while(ADCSRA & (1<<ADSC)){} // počká na jeho dokončení
 tmp = ADC; // vyčte výsledek
 ADCSRA = 0; // vypne ADC
 PRR = (1<<PRTIM0) | (1<<PRADC); // vypne clock všem periferiím (tedy i ADC, timer už ho má vypnutý)
 return tmp; // vrátí výsledke převodu
}


