// Debounce demo 
// Mega644 version
// used as an example of a state machine.      
             
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

//timeout values for each task
#define t1 200  
#define t2 50
#define t3 50  
 
//I like these 
#define begin {
#define end   }   

//State machine state names
#define NoPush 1 
#define MaybePush 2
#define Pushed 3
#define MaybeNoPush 4
 
//the three task subroutines
void task1(void);  	//inc LEDs
void task2(void);	//non-debounced button 0
void task3(void);	//debounced button 1

void initialize(void); //all the usual mcu stuff 
          
volatile unsigned char time1, time2, time3;	//timeout counters 
unsigned char PushFlag;		//message indicating a button push 
unsigned char led;			//LED count
unsigned char PushState;	//state machine  
         
//**********************************************************
//timer 0 comare match ISR
ISR (TIMER0_COMPA_vect) 
begin
  //Decrement the three times if they are not already zero
  if (time1>0)	--time1;
  if (time2>0) 	--time2;
  if (time3>0)	--time3;
end  

//**********************************************************       
//Entry point and task scheduler loop
int main(void)
begin  
  initialize();
  
  //main task scheduler loop 
  while(1)
  begin     
    if (time1==0)	task1();
    if (time2==0) 	task2();
    if (time3==0)	task3();
  end

end  
  
//**********************************************************          
//Task subroutines
//Task 1
void task1(void) 
begin  
  time1=t1;  //reset the task timer

  if (PushFlag)  //check for a button press
  begin
  	//reset flag
  	PushFlag = 0;
  	//increment the LEDs	
  	++led;	
  	PORTC = ~led;
  end
end  
 
//******************************* 
//Task 2  
void task2(void) 
begin
  time2=t2;  //reset the task timer

  if (~PIND & 0x01)  //button push
  begin  
     PushFlag = 1;
  end
end  
 
//*******************************   
//Task 3  
void task3(void) 
begin
  time3=t3;     //reset the task timer
  switch (PushState)
  begin
     case NoPush: 
        if (~PIND & 0x02) PushState=MaybePush;
        else PushState=NoPush;
        break;
     case MaybePush:
        if (~PIND & 0x02) 
        begin
           PushState=Pushed;   
           PushFlag=1;
        end
        else PushState=NoPush;
        break;
     case Pushed:  
        if (~PIND & 0x02) PushState=Pushed; 
        else PushState=MaybeNoPush;    
        break;
     case MaybeNoPush:
        if (~PIND & 0x02) PushState=Pushed; 
        else 
        begin
           PushState=NoPush;
           PushFlag=0;
        end    
        break;
  end
end
  
//********************************************************** 
//Set it all up
void initialize(void)
begin
//set up the ports
  DDRD = 0x00;	// PORT D is an input
  DDRC = 0xff;    // PORT C is an ouput 
  PORTC = 0xff ;  // turn off leds
           
  //set up timer 0 for 1 mSec timebase 
  OCR0A = 249;  		//set the compare re to 250 time ticks
  TIMSK0= (1<<OCIE0A);	//turn on timer 0 cmp match ISR 
  //set prescalar to divide by 64 
  TCCR0B= 3; //0b00000011;	
  // turn on clear-on-match
  TCCR0A= (1<<WGM01) ;
    
  //init the LED status (all off)
  led=0x00; 
  PORTC = ~led; 

  //init the task timers
  time1=t1;
  time2=t2;
  time3=t3;    
  
  //init the  message
  //for no button push
  PushFlag = 0;
  //init the state machine
  PushState = NoPush;
      
  //crank up the ISRs
  sei() ;
  
end 

   
