/********************************************************************
* FileName:        Problem 1.c
* Processor:       PIC18F4520
* Compiler:        MPLAB C18 v.3.06 
*
* This file displays the position and velocity of the RA0 knob value
*                                                                     
*
*       Author               Date              Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// David Fisher

/**  Header Files **************************************************/     
#include <p18f4520.h> 
#include <timers.h>
#include <adc.h>
#include <stdio.h>
#include "LCD Module.h"

/** Configuration Bits *********************************************/     
#pragma config OSC = EC  // EC = External 4MHz Crystal for PICDEM board only
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config BOREN = OFF

/** Define Constants Here ******************************************/
#define TIMER_START_VALUE 49911

/** Local Function Prototypes **************************************/
void low_isr(void);
void high_isr(void);
void updateLCD(int knobPosition, int knobVelocity);

/** Declare Interrupt Vector Sections ****************************/
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
   _asm goto high_isr _endasm
}

#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
   _asm goto low_isr _endasm
}

/** Global Variables ***********************************************/
int RA0result;
int oldRA0result;
	
/*******************************************************************
* Function:        void main(void)
********************************************************************/
#pragma code
void main (void)
{
	// ---- LCD Setup & Initial call to updateLCD ------
	XLCDInit(); 
    XLCDClear();
    updateLCD(0,0);
	// -- LCD Setup & Initial call to updateLCD end ----

	// -------------- RB0 Setup Start ------------------
	TRISBbits.TRISB0 = 0;
	// --------------- RB0 Setup End -------------------
	
	// -------------- ADC Setup Start ------------------
	OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_12_TAD, 
		ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS, 
		0x0E);
	// --------------- ADC Setup End -------------------
	
	// ------- Timer + Interrupt Setup Start -----------
	OpenTimer0( TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_16 );
	WriteTimer0(TIMER_START_VALUE);
	INTCONbits.GIE = 1;				// Turn on Global interrupts
	// -------- Timer + Interrupt Setup End ------------		


	while (1)
    {
		// This area loops forever
    }
}

/*****************************************************************
* Additional Helper Functions
******************************************************************/

/*****************************************************************
* Function:        updateLCD
* Inutps:		   knobPosition - The current ADC reading
*                  knobVelocity - The change in the ADC reading since last ISR
* Outputs:		   none
* Overview:		   Updates the LCD with the knob position and velocity
******************************************************************/
void updateLCD(int knobPosition, int knobVelocity)
{
	char line1[17];		// LCD variables
	char line2[17];

	sprintf(line1,"Position:   %4d",knobPosition);
	XLCDL1home();
	XLCDPutRamString(line1);	
	
	sprintf(line2,"Velocity:  %5d",knobVelocity);
	XLCDL2home();
	XLCDPutRamString(line2);
}
	
/*****************************************************************
* Function:        void high_isr(void)
* Possible sources of interrupt - none
* Overview:
******************************************************************/
#pragma interrupt high_isr
void high_isr(void)
{
	// Add code here for the high priority Interrupt Service Routine (ISR)
	
	if(INTCONbits.TMR0IF)  		// Timer 0 interrupt
	{						
		INTCONbits.TMR0IF = 0;
		PORTBbits.RB0 ^= 1;
		WriteTimer0(TIMER_START_VALUE);
		
		SetChanADC( ADC_CH0 );		// Select the pin
		ConvertADC(); 				// Start conversion
		while( BusyADC() ); 		// Wait for completion
		RA0result = ReadADC(); 		// Read result	
		
		updateLCD(RA0result, RA0result-oldRA0result);
		// A function is not required.  I just did it for fun.  I like functions.
		

		oldRA0result = RA0result;
	}
	
}

/******************************************************************
* Function:        void low_isr(void)
* Possible sources of interrupt - none
* Overview:
********************************************************************/
#pragma interruptlow low_isr
void low_isr(void)
{
	// Add code here for the low priority Interrupt Service Routine (ISR)
}