/**
 * Analog radio control servo driver on the pic16f628a.  Demands a 4MHz 
 * clock.
 *
 * Timer 0 runs in a continuous loop causing interrupts at roughly 30hz.
 * Every interrupt kicks it into a time-delay loop, pausing anywhere
 * between one millisecond to two milliseconds.
 *
 * The position of the servo can be controlled by sending binary bytes 
 * to the PIC's RS232 input at 9600 baud N 8 1.  0 is the shortest 
 * pulse, 1 the longest.
 */
#define __16f628a
#include "pic16f628a.h"
#include "tsmtypes.h"
#include "tsmdelay.h"
#include "tsmserial.h"
 
// Set the __CONFIG word:
// I usually set it to _EXTCLK_OSC&_WDT_OFF&_LVP_OFF&_DATA_CP_OFF&_PWRTE_ON
Uint16 at 0x2007  __CONFIG = CONFIG_WORD;

// Saves precalculated values for the delay loop.
volatile struct dvars precalc;
 
static void Intr(void) interrupt 0
{
	T0IF = 0;	// Clear the Timer 0 interrupt.

	PORTA=1;
		// The minimum delay for each CALL_SMALL_US is 14 
		// microseconds at 4Mhz, so subtract that from 1000L.
		DELAY_BIG_US(1000L - (14L * 4L));
		CALL_SMALL_US(precalc);
		CALL_SMALL_US(precalc);
		CALL_SMALL_US(precalc);
		CALL_SMALL_US(precalc);
	PORTA=0;
//	PORTA++;	// Toggle the state of the LSB of the port bits

//	GIE=1;		// Globally enable interrupts.
			/** We don't need to do this ourselves since
			 *  the compiler ALWAYS ADDS THIS FOR US
			 *  in interrupt functions!
			 *  If you try and DISable interrupts in an
			 *  interrupt function it WON'T WORK since
			 *  the compiler ALWAYS turns them back ON!
			 */
}

void main(void)
{
	TRISA = 0x00;	// All Port A latch outputs are enabled.

#ifdef  __16f628a	// Only compile this section for PIC16f628a
	CMCON = 0x07;	/** Disable comparators.  NEEDED FOR NORMAL PORTA
			 *  BEHAVIOR ON PIC16f628a!
			 */
#endif

	T0CS = 0;	// Clear to enable timer mode.
	PSA = 0;	// Clear to assign prescaler to Timer 0.

	PS2 = 1;	// Set up prescaler to 1:128.  
	PS1 = 1;
	PS0 = 0;

	INTCON = 0;	// Clear interrupt flag bits.
	GIE = 1;	// Enable all interrupts.

	T0IE = 1;	// Set Timer 0 to 0.  
	TMR0 = 0;	// Enable peripheral interrupts.

	ASYNC_INIT();
	CREN=1;

	// With 0 being one end stop and 255 being the other, start
	// the servo near the far end.
	SAVE_SMALL_US(precalc, 240L+14L);

	// Loop forever.  
	while(1)
	{
		if(RCIF)
		{
			Uint8 d=RCREG;
			// Disable interrupts while we update precalc
			GIE=0;
				SAVE_SMALL_US(precalc, (d)+14L);
			GIE=1;
		}
	}
}  
