/*******************************************************
FILE:     encoder.c

DESCRIPTION: To demo use of incremental encoder. Sends
encoder count out the serial port for reading on a PC
terminal program. 

REVISION HISTORY:  
*******************************************************/
//--Includes

#include <16f88.h>
#device ADC=10             // for 10-bit ADC results

//--Setup commands

#fuses INTRC_IO,NOWDT,NOPROTECT,PUT,NOWRT,NOLVP  // internal oscillator
#id 0x1234                     // 4 digit id
#use standard_io(A)
#use standard_io(B)
//#use fast_io(A)
//#use fast_io(B)
#use delay(clock=8000000)      // declare clock speed
#use rs232(baud=19200,xmit=PIN_B5,rcv=PIN_B2) // USART
#priority rda, rtcc  //don't want to miss incoming info

//--Pin definitions
#define LED      PIN_B0   // LED
#define ENC_A    PIN_B3   // Encoder pins
#define ENC_B    PIN_B4

//--Defines


//--Global variables
int1 hflag, senddataflag;
int8 cmd,data;

/*******************************************************
  Functions
*******************************************************/

/*******************************************************
  Send_data()
  Sends a 2-byte frame to host, 10-bit data, 6-bit cmd.
  Byte 0 has lower 8 bits of data, byte 1 has high 2 bits of
  data and 6 bit cmd. 
*******************************************************/

void send_data(int8 cmd, int16 data) {

  putc(make8(data,0));   
  putc((data >> 8) + (cmd << 2)); 
}


/*******************************************************
  flash_led()
  Flash LED n times 
*******************************************************/

void flash_led(int8 n) {
  int8 i;
  for (i=0;i<n;i++) {
    output_high(LED);
    delay_ms(100);
    output_low(LED);
    delay_ms(300);
  }
}

/*******************************************************
  Serial port character receive interrupt service routine
  Incoming data is a 2 byte frame, byte 1 = cmd, byte 2 = data.
*******************************************************/

#int_rda
void serial_isr(void)
{
  cmd = getc();       // get data
  data = getc();
  hflag=1;            // set flag for main program
}


/*******************************************************
  Main starts here
*******************************************************/

void main(void)
{
  int8 enc_old, enc_new, count;

//-------Setup commands

//  set_tris_a(0xFF);   // a is all inputs (for adc)
//  set_tris_b(0xC0);   // b7,b6 in, rest out
  setup_oscillator(OSC_8MHZ);
  
  
//-------Flash led a few times

  flash_led(2);
  
/*------Initialize encoder by getting currrent state. Do this
        by reading entire port b then masking to two encoder
        bits */
  
  enc_old = input_b() & 0x18;
  count = 50;  //initialize count.
  
//-------enable interrupts
                    
  enable_interrupts(INT_RDA);    // receive serial char
  enable_interrupts(GLOBAL);      
  
/*-------Endless loop checking encoder and adjusting count as
         needed. Must sample encoder sufficiently fast to
         not miss any ticks. */

  while (TRUE) {
    enc_new = input_b() & 0x18;  //get encoder value
    if (enc_new != enc_old) { //knob moved, handle it
    
/*----------XOR left bit of new with right bit of old to
            determine direction of turn. Look at encoder data
            sheet to see why this works. */
      if ( (enc_old ^ (enc_new >> 1)) & 0x08 )
        count--;
      else
        count++;
      enc_old = enc_new; //update variables

/*--------Now that we have count, we can do anything with it,
          for example increment/decrement the setting of a 
          volume control display or set the intensity of a 
          light dimmer, or the speed of a motor. Here, something
          simple, which is to send the value to the PC for
          reading on a terminal program*/
          
        printf("\r%3d",count);
    }
    
    if (hflag) {            // handle host command
      hflag=0;
      switch (cmd) {        // branch on host command
        case 1:             // start sending data
          senddataflag=TRUE;
          break;
        case 2:             // stop sending data
          senddataflag=FALSE;
          break;
        case 3:             // flash led
          flash_led(data);
          break;        
        case 255:           // are you there?
          send_data(1,1);
          break;
        default:
          break;
      }    
    }
  }
}


