/*********************************************
*	Author: Chris @ PyroElectro.com
*
*	Description: This firmware is made for the
*   PIC 18F452 microcontroller and goes with the
*	animatronic eyes tutorial on PyroElectro.com
*	The following firmware controls 6 servo motors
*   independently and has a special move command
*   so that the motors move slowly, with a varying
*   speed option.
*
*	Date: August 9th, 2011
*
*	For Full Details On This Firmware Please
*	Visit: http://www.pyroelectro.com/tutorials/animatronic_eyes/
*********************************************/

#include <p18f452.h>
#include <timers.h>
#include <delays.h>

/******Static Eyebrow Max/Min Locations********/
//Right Eyebrow
#define right_level 0xF100
#define right_down 0xF400
#define right_up 0xEB00
//Left Eyebrow
#define left_level 0xF000
#define left_down 0xED00
#define left_up 0xF600

/******Static Eye Max/Min Locations********/
//Right Eye
#define right_eye_straight 0xF259
#define right_eye_left 0xF600
#define right_eye_right 0xEC09

#define right_eye_level 0xEFA9
#define right_eye_up 0xF5C9
#define right_eye_down 0xEC59

//Left Eye
#define left_eye_straight 0xF259
#define left_eye_left 0xF600
#define left_eye_right 0xEC09

#define left_eye_level 0xEE59
#define left_eye_up 0xF2C9
#define left_eye_down 0xEC59


					//Declare all functions 
void move(unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,unsigned int);
void slow_move(unsigned int);
void delay(unsigned int);
void InterruptHandlerHigh (void);

unsigned int count = 0;		 //Counts every Timer1 Interrupt

//The servos are all set to go to an initial 
			//state when the system is powered on
int servo0 = right_level; // Right Eyebrow
int servo1 = left_level;  // Left Eyebrow
int servo2 = left_eye_straight; // Left Eye Left/Right
int servo3 = left_eye_level;  // Left Eye Up/Down
int servo4 = right_eye_straight; // Right Eye Left/Right
int servo5 = right_eye_level;  // Right Eye Up/Down
		
unsigned int servo_0_dest = right_level;
unsigned int servo_1_dest = left_level;
unsigned int servo_2_dest = left_eye_straight;
unsigned int servo_3_dest = left_eye_level;
unsigned int servo_4_dest = right_eye_straight;
unsigned int servo_5_dest = right_eye_level;

unsigned int servo_0_current = right_level;
unsigned int servo_1_current = left_level;
unsigned int servo_2_current = left_eye_straight;
unsigned int servo_3_current = left_eye_level;
unsigned int servo_4_current = right_eye_straight;
unsigned int servo_5_current = right_eye_level;

unsigned int speed = 0xB1DF;

/******** Variable Movement Speed*********
//This speed can be changed at any time to
change how fast the servos are updated, thus
changing the servo's movement speed.
******************************************
[1] speed = 0xB1DF; // Slowest
[2] speed = 0xD1DF; // Slow
[3] speed = 0xE1DF; // Medium
[4] speed = 0xF1DF; // Fast
[5] speed = 0xF9DF; // Fastest
******************************************/

void main(void)
{
				//Set I/O ports
TRISD = 0x00;
				//Clear Output Ports
PORTD = 0x00;

				//Setup Interrupts
RCON = 0b000000000; 
INTCON = 0b10100000;

				//Setup Timers 1 & 2
OpenTimer0( TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_2 );
OpenTimer1( TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_2 & T1_OSC1EN_OFF & T1_SYNC_EXT_OFF );
OpenTimer3( TIMER_INT_ON & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_1 & T3_SYNC_EXT_OFF );
				//Initialize Timers 1 & 2
WriteTimer0( 0x3CAF );
WriteTimer1( 0xF63B );
WriteTimer3( speed ); // 20,000 Instructions Until Interrupt

	while(1){

//Move Level/Straight
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(5);
//Move Up
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_up,		//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_up,		//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(5);
//Move Down
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_down,		//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_down,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(8);
//Move Level/Straight
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(5);
//Move Left
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_left,		//Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_left,	//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(5);
//Move Right
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_right,	//Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_right,	//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(6);
//Move Level/Straight
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(10);

/** Complete Circle **/

// Move Up
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_up,		//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_up,		//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(3);
// Move Left
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_left,		//Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_left,	//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(3);
// Move Down
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_down,		//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_down,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(3);
// Move Right
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_right,	//Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_right,	//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(3);
// Back Up
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_up,		//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_up,		//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(6);
//Move Level/Straight
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_down,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_down,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(4);
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(30);

/** Right/Left Eye Independent **/

// Look Out
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_left, //Left Eye Left/Right
		 left_eye_down,	//Left Eye Up/Down
		 right_eye_right,//Right Eye Left/Right
		 right_eye_up,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(10);
// Look In
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_right, //Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_left,//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(10);
// Look Up/Down
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_right, //Left Eye Left/Right
		 left_eye_up,	//Left Eye Up/Down
		 right_eye_left,//Right Eye Left/Right
		 right_eye_down,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(10);
// Look Down/Up
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_down,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_up,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(10);
// Straight
	move(0,					//Right Eyebrow
		 0,					//Left Eyebrow
		 left_eye_straight, //Left Eye Left/Right
		 left_eye_level,	//Left Eye Up/Down
		 right_eye_straight,//Right Eye Left/Right
		 right_eye_level,	//Right Eye Up/Down
		 0xFADF);			//Movement Speed
	delay(500);
	}

}

	//The move function sets all servo values
void move(unsigned int one, unsigned int two, unsigned int three, unsigned int four,
		  unsigned int five, unsigned int six, unsigned int variable_speed)
{

	speed = variable_speed;

	if(one){
		// Right Eyebrow
		servo_0_dest = one;
	}
	if(two){
		// Left Eyebrow
		servo_1_dest = two;
	}
	if(three){
		// Right Eyebrow
		servo_2_dest = three;
	}
	if(four){
		// Left Eyebrow
		servo_3_dest = four;
	}
	if(five){
		// Right Eyebrow
		servo_4_dest = five;
	}
	if(six){
		// Left Eyebrow
		servo_5_dest = six;
	}
}

//INTERRUPT CONTROL
#pragma code InterruptVectorHigh = 0x08		//interrupt pointer address (0x18 low priority)
void InterruptVectorHigh (void)
{
        _asm						//assembly code starts
        goto InterruptHandlerHigh	//interrupt control
        _endasm						//assembly code ends
}
#pragma code
#pragma interrupt InterruptHandlerHigh		//end interrupt control

void InterruptHandlerHigh()		// Declaration of InterruptHandler
{									//This gets run when either timer overflows from FFFF->0000
        if(INTCONbits.TMR0IF)		//check if TMR0 interrupt flag is set
        {
				WriteTimer0( 0x3CAF );  //Reset Timer0 for 20mS Delay
				WriteTimer1( 0xFC00 );  //Reset Timer1
				count = 0;				//Reset Timer1 Interrupt Counter
			    INTCONbits.TMR0IF = 0;	//Clear TMR0 Flag               
        }
        if(PIR1bits.TMR1IF == 1)        
        {								//If Timer1 interrupts, do your thing...
		count++;						//Increment Timer1 Interrupt Counter
				switch(count){			//Choose which servo to modify
			case 1:     PORTD = 0x01; 
					    WriteTimer1( servo0 );	//Right Eyebrow
						break;
			case 2:		PORTD = 0x02;
						WriteTimer1( servo1 );	//Left Eyebrow
						break;
			case 3:		PORTD = 0x04;
						WriteTimer1( servo2 );	//Left Eye Left/Right
						break;
			case 4:		PORTD = 0x08;
						WriteTimer1( servo3 );	//Left Eye Up/Down
						break;
			case 5:		PORTD = 0x10;
						WriteTimer1( servo4 );	//Right Eye Left/Right
						break;
			case 6:		PORTD = 0x20;
						WriteTimer1( servo5 );	//Right Eye Up/Down
						break;
			case 7:		PORTD = 0x00;
						WriteTimer1( 0 );
						break;
				}

                PIR1bits.TMR1IF = 0;		//Clear Timer1 flag
        }
        if(PIR2bits.TMR3IF == 1)        
        {								//If Timer3 interrupts, do your thing...
			if(servo_0_dest < servo_0_current){
				servo_0_current--;
				servo0 = servo_0_current;
			}
			else if(servo_0_dest > servo_0_current){
				servo_0_current++;
				servo0 = servo_0_current;
			}
	
			if(servo_1_dest < servo_1_current){
				servo_1_current--;
				servo1 = servo_1_current;
			}
			else if(servo_1_dest > servo_1_current){
				servo_1_current++;
				servo1 = servo_1_current;
			}

			if(servo_2_dest < servo_2_current){
				servo_2_current--;
				servo2 = servo_2_current;
			}
			else if(servo_2_dest > servo_2_current){
				servo_2_current++;
				servo2 = servo_2_current;
			}

			if(servo_3_dest < servo_3_current){
				servo_3_current--;
				servo3 = servo_3_current;
			}
			else if(servo_3_dest > servo_3_current){
				servo_3_current++;
				servo3 = servo_3_current;
			}


			if(servo_4_dest < servo_4_current){
				servo_4_current--;
				servo4 = servo_4_current;
			}
			else if(servo_4_dest > servo_4_current){
				servo_4_current++;
				servo4 = servo_4_current;
			}


			if(servo_5_dest < servo_5_current){
				servo_5_current--;
				servo5 = servo_5_current;
			}
			else if(servo_5_dest > servo_5_current){
				servo_5_current++;
				servo5 = servo_5_current;
			}

				WriteTimer3( speed ); // Reset Instruction Speed Until Interrupt
                PIR2bits.TMR3IF = 0;		//Clear Timer3 flag
        }
    INTCONbits.GIE = 1;						//Re-enable all interrupts
}

//Delay delay_val*100mS
void delay(unsigned int delay_val){
unsigned int i=0;

for(i=0;i<delay_val;i++){
Delay10KTCYx(50);
}

}