#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <stdio.h>

//port a bity pro enkoder:
volatile uint8_t &pinENK = PIND;
const uint8_t bitCK = 5;
const uint8_t bitDT = 4;
const uint8_t bitBT = 3;
//perioda a stred:
const uint8_t max = 6;
const uint8_t stred = 3;

void inicializace()
{
  DDRD = (1 << 2);  //PD2 vystup
  PORTD = (1 << 2); //OC4B povolen

  PCICR =(1 << PCIE2);  //Pin Change PD povolen
  //PD5 (PCINT21), PD3 (PCINT19) povoleny:
  PCMSK2 =(1 << bitCK) | (1 << bitBT);

  //neinv. rezim OC4B, PWM (f+k+ICR4), D = 1024:
  TCCR4A = (1 << COM4B1);
  TCCR4B = (1 << WGM43) | (1 << CS42) | (1 << CS40);
  ICR4 = max;
  OCR4B = stred;

  //normalni rezim, casovac, nabezna hrana T3, STOP:
  TCCR3A = 0;
  TCCR3B = 0;
}

inline void start()
{
  TIFR3 = (1 << TOV3);  //nulovani priznaku preteceni
  TCNT3 = 0;  //nulovani obsahu
  //cita nabezne hrany T3:
  TCCR3B = (1 << CS32) | (1 << CS31) | (1 << CS30);
}

inline void stop()
{
  TCCR3B = 0;
}

uint8_t getbit(volatile uint8_t reg, uint8_t bit)
{
  return (reg & (1 << bit)) >> bit;
}

int main(void)
{
  uint16_t kmitocet;
  
  inicializace();
  sei();  //preruseni povoleno

  printf("Mereni kmitoctu OC4B:\n");

  while (1)
  {
    start();
    _delay_ms(1000);
    stop();
    
    if(getbit(TIFR3, TOV3))  //test preteceni
    {
      printf("citac pretekl\n");
    }
    else
    {
      kmitocet = TCNT3;  //namereny kmitocet
      printf("f = %u Hz\n", kmitocet);
    }
  }
}

//obsluha preruseni enkoderu:
ISR(PCINT2_vect)
{
  uint8_t stav = ~pinENK;

  if(getbit(stav, bitCK))  //detekce otaceni
  {
    if(getbit(stav, bitDT))  //detekce smeru
    {
      if(OCR4B < max)  //po smeru hod. rucek
        OCR4B++;
    }
    else
    {
      if(OCR4B > 0)    //proti smeru hod. rucek
        OCR4B--;
    }
  }

  if(getbit(stav, bitBT))  //stredove tlacitko
  {
    OCR4B = stred;
  }
}