Code listing

Below is our code for the project. To skip to the transmitter code, click here.

To access the original .c files, click click here for the main code and click here for the transmit code

Main Code
//
// Cornell 2005
// Edward Lo and Sihan Goi
// ECE476 final project
// Temperature sensor and fan controller
//
#include <mega32.h> 
#include <stdio.h>
#include <string.h>       
#include <delay.h>

//number of supported fans
#define MAXFAN 2

//wireless packet definitions (maintain DC balance)
#define start_packet 0b10100110
#define stop_packet  0b11010010

//timeout values for each task
#define t1 20000   //Update LCD
#define t2 20000   //Hyperterminal display
#define t3 1000    //Hyperterminal input
#define t4 500     //Read temperature
#define t5 100     //Adjust fan speed
#define t6 5000    //PWM pulse stretching

//values for temperature calibration
#define inittemp  0.76
#define roomtemp  72.0
#define opampGain 4.00
#define Arefvolt  5.09

//other thresholds
#define t_lockedrotor 5  //when a fault occurs for this many cycles, the user is notified

//conversion macros
#define getTemp(input) ((float)(roomtemp +( ((float)((float)input-fproomtemp)/255.0)*Arefvolt/(0.01 * opampGain) )))
#define getRpm(input)  ((unsigned int)(60000.0 / (((float)input/10.0) * tachdivider)))

//I like these definitions
#define begin {
#define end   }
#define LCDwidth 16 //characters

//lcd definitions
#asm
    .equ __lcd_port=0x15
#endasm
#include <lcd.h> // LCD driver routines

enum { pwm, dac, off };        //fan mode
enum { user, auto };           //opmode
enum { wireless, computer };   //inputmode
enum { start, data, stop };    //wireless data packets

//variables
unsigned char i;                                                    //local counter
unsigned char j;                                                    //counter in ISR
unsigned char opmode, inputmode, fanmode[MAXFAN];                   //operation modes
unsigned int  counttime, time1, time2, time3, time4, time5, time6;  //task scheduling timeout counters

//wireless stuff
unsigned char rstate;  //receive state
unsigned char datain;  //data from serial in

//lcd stuff
unsigned char lcddispnum;     //remembers which fan we are displaying status for
char          lcd_buffer[17]; //LCD display buffer

//alarm stuff
unsigned char f_alarm, f_alarmsound;  //flags to determine if an alarm should light and sound

//temperature sensing stuff
unsigned char sensornum;            //remembers which temperature sensor we are currently reading from
unsigned char tempsensor[MAXFAN];   //temperature reading from ADC register
unsigned char t_mintemp[MAXFAN];    //minimum temperature threshold when fan turns on
unsigned char t_alarmtemp[MAXFAN];  //maximum temperature threshold when alarm sounds
float fpcurrtemp[MAXFAN];           //current temperature
float t_fpmintemp[MAXFAN];          //min threshold temperature
float t_fpalarmtemp[MAXFAN];        //max threshold temperature
float fproomtemp;                   //room temperature (for calibration)
float fpmaxtemp;                    //temporary variable for calculating fan speed

//fan tachometer detection stuff
int           tachhi[MAXFAN];        //counts time spent in high phase of tach pulse
int           tachlo[MAXFAN];        //counts time spent in low phase of tach pulse
unsigned char rpmsensor[MAXFAN];     //holds current tach pulse value
unsigned char f_readrpm[MAXFAN];     //flag to read rpm
unsigned char f_tachphase[MAXFAN];   //flag to remember which phase of the tach pulse we are in
unsigned char f_lockedrotor[MAXFAN]; //flag to detect a locked rotor
unsigned int  rpm[MAXFAN];           //holds the calculated rpm of a fan
float         tachdivider;           //adjust for each fan - pulses per revolution

//pwm and dac stuff
unsigned char dacout;    //holds dac value (0-15)
unsigned char pwmspeed;  //holds pwm duty cycle (0-255)
unsigned char pwmcnt;    //specifically for fan 2 rpm detection
float         fanspeed;  //speed to drive fan at: 1.0 = 100% power, 0.0 = 0% power

//keyboard input stuff
char         cmd;
unsigned int val1;

//RXC ISR variables
unsigned char r_index;          //current string index
unsigned char r_buffer[90];     //input string 
unsigned char r_ready;          //flag for receive done
unsigned char r_char;           //current character  

//TX empth ISR variables
unsigned char t_index;          //current string index
unsigned char t_buffer[90];     //output string 
unsigned char t_ready;          //flag for transmit done
unsigned char t_char;           //current character

//the subroutines
void gets_int(void);            //starts getting a string from serial line
void puts_int(void);            //starts a send to serial line
void initialize(void);          //all the usual mcu stuff 

//scheduled tasks
void DispScreen(void);
void DispLCD(void);
void ReadTemp(void);
void Sysadmin(void);
void AdjustFanSpeed(void);
void PWMPulseStretch(void);


//**********************************************************
//timer 2 comparison ISR
//  This ISR ticks down the timers used to run scheduled tasks.
//  It generates the square wave for the piezo buzzer when an alarm should sound.
//  It reads the tachometer pulses from the fans and detects rpm.
//  It detects locked fan rotors based on the behaviour of the tach pulses
interrupt [TIM2_COMP] void timer2_compare(void)
begin
  //Decrement the scheduler times if they are not already zero
  if (time1>0)  --time1;
  if (time2>0)  --time2;
  if (time3>0)  --time3;
  if (time4>0)  --time4;
  if (time5>0)  --time5;
  if (time6>0)  --time6;
  
  //generates square wave for the alarm
  if( counttime-- == 0 ) {
    if( f_alarmsound ) PORTD.5 ^= 1;
    counttime = 10;
  }

  //turn off pwm mode pulse stretching after getting tachometer reading
  if( (fanmode[1] == pwm) && (pwmcnt == 3) ) {
    TCCR0 = 0b01101011;  //resume normal pwm mode
    f_readrpm[1] = 0;    //don't read rpm anymore
  }

  //cycle through each fan and get rpm data
  for( j = 0; j < MAXFAN; j++ ) {
    //get rpm sensor reading
    rpmsensor[j] = (PINA >> (j+4)) & 0x1;

    //sample tachometer pulses
    if( f_readrpm[j] == 1 ) {
      //tachometer pulse is HIGH
      if (rpmsensor[j] == 1) {
        f_tachphase[j] = 1;
        if (tachhi[j] > 600) f_lockedrotor[j] = t_lockedrotor;  //rotor is locked in place
        tachhi[j]++;                                            //counts in 0.1ms intervals
      }
      //tachnometer pulse is LOW
      else {
        //check for falling edge
        if (f_tachphase[j] == 1) {
          //check for locked rotor here! (check if time difference between phases is > factor of 3)
          if( ((tachhi[j]-tachlo[j]) > (3*tachlo[j])) && (f_lockedrotor[j] < t_lockedrotor) ||
              ((tachlo[j]-tachhi[j]) > (3*tachhi[j])) && (f_lockedrotor[j] < t_lockedrotor) ) {
            f_lockedrotor[j]++;
          }
          else {
            //rotor operating normally
            f_lockedrotor[j] = 0;
          
            //pwm fan 2
            if( fanmode[j] == pwm ) pwmcnt++;  //for pwm pulse stretching, count number of cycles
          }
      
          if( fanmode[j] == pwm ) {
            if( pwmcnt == 3 ) rpm[j] = getRpm(tachlo[j]);  //converts ms to rpm
          }
          else {
            rpm[j] = getRpm(tachlo[j]);  //converts ms to rpm
          }
          tachhi[j] = 0;               //reset for counting next cycle
          tachlo[j] = 0;               //reset for counting next cycle
        }
        f_tachphase[j] = 0;
        if (tachlo[j] > 600) f_lockedrotor[j] = t_lockedrotor;  //rotor is locked in place
        tachlo[j]++;                                            //counts in 0.1ms intervals
      }
    }
    
  }  //for loop
  
end  


//**********************************************************
//UART character-ready ISR
interrupt [USART_RXC] void uart_rec(void)
begin
    r_char=UDR;    //get a char

    //computer input mode
    if( inputmode == computer ) {
      UDR=r_char;    //then print it
      //build the input string
      if (r_char != '\r') r_buffer[r_index++]=r_char;
      else
      begin
        putchar('\n');          //use putchar to avoid overwrite
        r_buffer[r_index]=0x00; //zero terminate
        r_ready=1;              //signal cmd processor
        UCSRB.7=0;              //stop rec ISR
      end
    }

    //wireless input mode
    else {
      if( (rstate == start) && (r_char == start_packet) ) {
        rstate = data;
      }
      else if( rstate == data ) {
        datain = r_char;
        rstate = stop;
      }
      else if( (rstate == stop) && (r_char == stop_packet) ) {
        rstate = start;  
      }
      else {
        rstate = start;
      }
   }
end

/**********************************************************/
//UART xmit-empty ISR
interrupt [USART_DRE] void uart_send(void)
begin
    t_char = t_buffer[++t_index];
    if (t_char == 0) 	
    begin
      UCSRB.5 = 0;     //kill isr 
      t_ready = 1;     //transmit done 
    end
    else UDR = t_char; //send the char 
end


//********************************************************** 
//  -- non-blocking keyboard check initializes ISR-driven
// receive. This routine merely sets up the ISR, which then
// does all the work of getting a command.
void gets_int(void) 
begin
  memset(r_buffer,0x00,90);
  r_ready = 0;
  r_index = 0;
  UCSRB.7 = 1;
end


//********************************************************** 
//  -- nonblocking print: initializes ISR-driven
// transmit. This routine merely sets up the ISR, then
// send one character. The ISR does all the work.   
void puts_int(void) 
begin
  t_ready = 0;
  t_index = 0;
  if (t_buffer[0]>0) 
  begin
    putchar(t_buffer[0]);
    UCSRB.5=1;
  end 
end


//**********************************************************       
//Entry point and task scheduler loop
//  Handles mux selection, alarm and lights, and operation modes.
//  Calls various task timers based on the timeout counters.
void main(void)
begin  
  initialize();

  //main task scheduler loop -- never exits!
  while(1)
  begin     
    if (time1==0)	DispLCD();         //display system status on LCD
    if (time2==0)	DispScreen();      //display information on terminal
    if (time3==0)	Sysadmin();        //gets input from keyboard
    if (time4==0)	ReadTemp();        //reads temperature sensors
    if (time5==0)	AdjustFanSpeed();  //adjusts fan speeds
    if (time6==0)	PWMPulseStretch(); //sets PWM to max for rpm detection

    //wireless or computer mode?
    inputmode = PINB.1;

    //mux output
    PORTB.0 = opmode;
    PORTB.2 = inputmode;

    //alarm system
    f_alarm = 0;
    for( i = 0; i < MAXFAN; i++ ) {
      if( (fanmode[i] != off) &&
          ((fpcurrtemp[i] > t_fpalarmtemp[i]) ||
          ((fpcurrtemp[i] > t_fpmintemp[i]) && (f_lockedrotor[i] == t_lockedrotor))) ) {
        f_alarm = 1;
        break;
      }
    }
    f_alarmsound = f_alarm;
    PORTD.4      = f_alarm;  //alarm status light

    //status lights
    PORTD.2 = (opmode == auto);
    PORTD.3 = (inputmode == wireless);

    //manual mode
    if( opmode == user ) {
      TCCR0   = 0;
      PORTB.3 = 1;       //drive PWM at full power to maintain rpm detection
      PORTA.2 = 1;       //enable fan 2 so it will spin
      f_readrpm[0] = 1;  //continue rpm detection
      f_readrpm[1] = 1;  //continue rpm detection
      pwmcnt  = 0;       //so interrupt will always read rpm
    }

    //auto mode
    if( opmode == auto ) {
      //fan 2 (pwm fan)
      if( (fanmode[1] != off) && (fpcurrtemp[1] > t_fpmintemp[1]) ) {
        // turn on fan
        if( f_readrpm[1] == 0 ) {
          OCR0 = pwmspeed;   //only set PWM speed if rpm is not being detected
        }
        TCCR0 = 0b01101011;  //clear OC0 on upcount
      }
      else {
        // turn off fan
        OCR0    = 0;
        TCCR0   = 0;
        PORTB.3 = 0;         //don't drive PWM  
        rpm[1]  = 0;
        f_lockedrotor[1] = 0;
      }

      //fan1 (dac fan)
      if( (fanmode[0] != off) && (fpcurrtemp[0] > t_fpmintemp[0]) ) {
        PORTA.2 = 1;         //enable fan
      }
      else {
        PORTA.2 = 0;         //disable fan
        rpm[0]  = 0;
        f_lockedrotor[0] = 0;
      }

      //output dac value to port B
      PORTB = PINB & 0x0f | (dacout << 4);
    }

    //wireless input
    if( inputmode == wireless ) {
      switch( datain ) {
        case 0b11000010: t_fpmintemp[0] += 1.0; break;
        case 0b10100010: t_fpmintemp[0] -= 1.0; break;
        case 0b10010010: t_fpmintemp[1] += 1.0; break;
        case 0b10001010: t_fpmintemp[1] -= 1.0; break;
        case 0b10000110: opmode ^= 1;
                           if( opmode == auto ) f_readrpm[1] = 0;
                           break;
      }
      datain = 0;  //clears received data
    }
  end   
end  


//**********************************************************          
//Adjusts fan speeds
//  This function uses the temperature detected from the sensors
//  and adjusts the fan speed accordingly. It assumes linear ramping.
//  The percentage of power to use is stored in 'fanspeed'.
void AdjustFanSpeed(void) 
begin
  time5=t5;

  for( i = 0; i < MAXFAN; i++ ) {
    //get percentage of max speed to use
    fpmaxtemp = (t_fpalarmtemp[i] - t_fpmintemp[i]) * 0.75;
    fanspeed = (fpcurrtemp[i] - t_fpmintemp[i]) / fpmaxtemp;

    //pwm adjustment (fan 2)
    if( i == 1 ) {
      if( fanspeed >= 1.0 ) {
        pwmspeed = 255;
      } else if( fanspeed <= 0 ) {
        pwmspeed = 0;
      } else {
        pwmspeed = (unsigned char)( fanspeed * 255.0 );
      }
    }

    //4 bit DAC adjustment (fan 1)
    if( i != 1 ) {
      if( fanspeed >= 1.0 ) {
        dacout = 15;
      } else if( fanspeed <= 0 ) {
        dacout = 0;
      } else {
        dacout = (unsigned char)( fanspeed * 15.0 );
      }
    }
  }
end


//**********************************************************          
//Reads Temperature Sensors
//  This function reads the ADC result from the temperature sensors.
//  It continuously muxes between the different sensors and
//  alternatingly gets their readings and sets up for the next one.
void ReadTemp(void) 
begin
  time4=t4;  //reset the task timer

  // reads current sensor
  tempsensor[sensornum] = ADCH;
  fpcurrtemp[sensornum] = getTemp(tempsensor[sensornum]);

  //switch to next sensor and starts next conversion
  if( sensornum++ == (MAXFAN-1) ) sensornum = 0;
  ADMUX = 0b00100000 | sensornum;
  ADCSR.6 = 1;
end


//**********************************************************          
//PWM Pulse Stretching
//  If fan is running in PWM mode, then we need to run it at full power
//  periodically in order to get RPM information. It sets the f_readrpm
//  flag to 1 so the interrupt will gather RPM for the PWM fan.
void PWMPulseStretch(void) 
begin
  time6=t6;  //reset the task timer 

  //use pulse stretching to handle pwm rpm monitoring
  if( (fanmode[1] == pwm) && (fpcurrtemp[1] > t_fpmintemp[1]) ) {
    OCR0  = 255;            //drive PWM at full power
    TCCR0 = 0b01101011;     //clear OC0 on upcount
    f_readrpm[1] = 1;       //read rpm signals flag
    pwmcnt = 0;
  }
end


//**********************************************************          
//Displays to LCD
//  This function outputs the fan + temperature status to the LCD in
//  an alternating fashion.
void DispLCD(void) 
begin
  time1=t1;  //reset the task timer 

  //toggle between different fan info
  if( lcddispnum++ == (MAXFAN-1) ) lcddispnum = 0;
  
  //current rpm + temperature
  lcd_clear();
  sprintf( lcd_buffer, "%d: %4d rpm %2.0fF", lcddispnum+1, rpm[lcddispnum], fpcurrtemp[lcddispnum] );
  lcd_gotoxy(0,0);
  lcd_puts( lcd_buffer );
end  


//********************************************************** 
//Displays fan controller information to the computer terminal
void DispScreen(void)
begin
  time2=t2;

  //prints out title and mode on the hyperterminal  
  while ( !t_ready );
  sprintf(t_buffer, "\f\n\rFan Controller (");
  puts_int();
  while ( !t_ready );
  if( opmode == auto ) sprintf( t_buffer, "auto, " );
  else                 sprintf( t_buffer, "user, " );
  puts_int();
  while ( !t_ready );
  if( inputmode == wireless ) sprintf( t_buffer, "wireless)\n\r" );
  else                        sprintf( t_buffer, "terminal)\n\r" );
  puts_int();
  
  //prints fan status
  for( i = 0; i < MAXFAN; i++ ) {
    while ( !t_ready );
    if( (f_lockedrotor[i] == t_lockedrotor) && (fpcurrtemp[i] > t_fpmintemp[i]) && ((fanmode[i] != off) ||
        (opmode == user)) )
      sprintf(t_buffer, "Fan%d: %4drpm %4.1fF min=%3.0f max=%3.0f - FAULT detected!\n\r",
              i+1, rpm[i], fpcurrtemp[i], t_fpmintemp[i], t_fpalarmtemp[i]);
    else
      sprintf(t_buffer, "Fan%d: %4drpm %4.1fF min=%3.0f max=%3.0f\n\r",
              i+1, rpm[i], fpcurrtemp[i], t_fpmintemp[i], t_fpalarmtemp[i]);
    puts_int();
  }

  //prints user prompt
  while ( !t_ready );
  sprintf(t_buffer, "> %s", r_buffer);
  puts_int();
end


//********************************************************** 
//Serial port input from the computer
//  Gets commands from the keyboard and parses them.
void Sysadmin(void)
begin
  time3=t3;

  //get user input
  if ( r_ready )    
  begin
    sscanf(r_buffer, "%c%d", &cmd, &val1);
    gets_int();     

    switch( cmd ) begin
      //set pwmspeed
      case 'a': t_fpmintemp[0]   = val1; break;
      case 'b': t_fpalarmtemp[0] = val1; break;
      case 'c': t_fpmintemp[1]   = val1; break;
      case 'd': t_fpalarmtemp[1] = val1; break;
      case 'o': opmode = opmode ^ 1;
                if( opmode == auto ) f_readrpm[1] = 0;
                break;
      case 'f': if( val1 == 1 ) {
                  if( fanmode[0] == off ) fanmode[0] = dac;
                  else                    fanmode[0] = off;
                }
                if( val1 == 2 ) {
                  if( fanmode[1] == off ) fanmode[1] = pwm;
                  else                    fanmode[1] = off;
                }
                break;
      case 't': tachdivider = val1; break;
    end

  end
end


//********************************************************** 
//Initialize program settings
//  Sets up port pins, timers, flags, and interrupts.
void initialize(void)
begin
  //temperature and rpm sensing
  DDRA  = 0x84;  //A.2 = enable DAC fan
  PORTA = 0xff;

  //dac, pwm, mode output and wireless toggle input
  DDRB  = 0xfd;
  PORTB = 0x00;

  //lcd output
  DDRC  = 0xff;
  PORTC = 0xff;

  //serial and status lights and alarm
  DDRD  = 0xff;
  PORTD = 0xff;

  //serial setop for debugging using printf, etc.
  UCSRB = 0x18;
  UBRRL = 207;  //4800
  putsf("\r\nCornell Starting...\r\n");  

  //set up timer 0 for PWM
  TCNT0 = 0;
  OCR0  = 0;
  TCCR0 = 0b01001011;     //prescalar to CLK, CTC, PWM, init with no OC0 operation

  //set up timer 2 for time based scheduler
  TCNT2 = 0;
  OCR2  = 24;             //0.1 ms
  TIMSK = 1<<7;           //turn on timer 2 cmp-match ISR 
  TCCR2 = 0b00001011;     //prescalar to CLK / 64
  
  //init the task timers
  time1=t1;
  time2=t2;
  time3=t3;
  time4=t4;
  time5=t5;
  time6=t6;
  counttime = 10;

  //lcd stuff
  lcd_init(LCDwidth);      	//initialize the display
  lcd_clear();       		//clear the display
  putsf("\r\nLCD init complete...\r\n");

  //temperature reading stuff
  sensornum = 0;
  ADMUX = 0b00100100;       //use port A.4 for input (left aligned)
  ADCSR = 0b11000111;	    //prescalar to 1/128*16Mhz = 125kHz, start conversion
  fproomtemp = (inittemp * opampGain / Arefvolt) * 255.0;  //calibrate roomtemp with sensor 1
  for( i = 0; i < MAXFAN; i++ ) {
    t_fpmintemp[i]   = 72;  //initial thresholds
    t_fpalarmtemp[i] = 80;
    t_mintemp[i]     = 72;
    t_alarmtemp[i]   = 80;
  }

  //fan speed and failure detection stuff
  for( i = 0; i < MAXFAN; i++ ) {
    tachhi[i]  = 0;
    tachlo[i]  = 0;
    f_readrpm[i]         = 1;
    f_lockedrotor[i]     = 0;
  }
  f_readrpm[1] = 0;            //fan 2 is a pwm fan

  //selects fan modes
  opmode     = auto;
  inputmode  = computer;
  fanmode[0] = dac;
  fanmode[1] = pwm;

  //pwm and dac stuff
  dacout   = 0;
  pwmspeed = 0;
  pwmcnt   = 0;

  //transmit and receive flags
  r_ready = 0;
  t_ready = 1;
  rstate  = start;
  datain  = 0;

  //crank up the ISRs
  #asm
  	sei
  #endasm  

  //serial port input
  gets_int();

  //our fan
  tachdivider = 2;

end  

Transmitter code

Below is the transmitter code:

//
// Cornell 2005
// Edward Lo and Sihan Goi
// ECE476 final project
// Temperature sensor and fan wireless transmitter
//
#include <Mega32.h>
#include <stdio.h>
#include <stdlib.h>

//I like these definitions
#define begin {
#define end   }

//task scheduling timers
#define t1 30  //30 ms debounce state machine

//wireless packet definitions (maintain DC balance)
#define start_packet 0b10100110
#define stop_packet  0b11010010

enum { NoPush, MaybePush, Pushed, MaybeNoPush };

unsigned int  time1;                        //task scheduling timeout counter
unsigned char buttons, buttons2, inbutton;  //saves the button press
unsigned char butstate;	                    //debounce state machine
unsigned char cdata;                        //data byte to transmit

void initialize(void);  //set everything up
void getInput(void);    //debounce buttons


//**********************************************************
//Timer0 compare ISR
//  Simply ticks down the task timers.
interrupt [TIM0_COMP] void timer0_compare(void)
{
  if (time1>0)  --time1;
}


//**********************************************************
//Transmit the data byte
//  Encapsulates the data packet with a start and end packet.
//  Send 0xaa's to setup receiver gain.
void senddata(void)
{
  //setup the receiver for proper gain and sync
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xaa);
  putchar(0xff);
  putchar(0x00);
  //send data
  putchar(start_packet);
  putchar(cdata);
  putchar(stop_packet);

  cdata = 0;
}


//**********************************************************
//Button debouncing state machine
//  Gets the button presses into "inbutton" and then encodes it
//  into the "cdata" variable.  This becomes the data packet.
void getInput(void)
{
  time1=t1;

  //button debounce
  switch( butstate )
  begin
    case NoPush:
      buttons = PINA;
      if( ~buttons != 0 ) butstate = MaybePush; break;

    case MaybePush:
      buttons2 = PINA;
      if( buttons2 == buttons )
      begin
        butstate = Pushed;
        inbutton = ~buttons;
      end  
      else butstate = NoPush;
      break;

    case Pushed:
      buttons2 = PINA;
      if( buttons2 == buttons ) butstate = Pushed;
      else                      butstate = MaybeNoPush; break;
             
    case MaybeNoPush:
      buttons2 = PINA;
      if( buttons2 == buttons ) butstate = Pushed;
      else
      begin
         butstate = NoPush;
         inbutton = 0;
      end
      break;
  end

  //parse input
  switch( inbutton ) {
    case 0b10000000:
    case 0b01000000:
    case 0b00100000:
    case 0b00010000: cdata = 0b10000000 | (inbutton >> 1) | 0b10;
                     inbutton = 0;
                     break;
    case 0b00000001: cdata = 0b10000110;
                     inbutton = 0;
                     break;
  }
}


//**********************************************************
//Main program
//  Debounce buttons and send presses to serial port.
void main(void)
{
  initialize();

  while(1)
  {
    if( time1 == 0 ) getInput();  //get debounced input
    if( cdata != 0 ) senddata();  //transmits button press
  }
}


//**********************************************************
//Get everyting started
void initialize(void)
{
  //setup ports
  DDRA  = 0x00;		// buttons
  PORTA = 0xff;		// pull-up resistors
  DDRD  = 0xff;		// output for status light and transmitter
  PORTD = 0xff;		// power status on

  //serial setop for debugging using printf, etc.
  UCSRB = 0x18;
  UBRRL = 207;  //4800

  //setup timer0 for 1ms
  TIMSK = 2;
  OCR0  = 249;
  TCCR0 = 0b00001011;

  //initialize timers
  time1 = t1;
  time2 = t2;

  //setup debounce states
  butstate = NoPush;
  inbutton = 0;

  cdata = 0;

  #asm ("sei");

  //turns on LED
  PORTD.7 = 0;
}