/////////////////////////////////////////////////////////////////////////
/* UTI EVALUATION BOARD PROGRAM
   written by Alexander Kerezov
   Tecnical University,
   Sofia, Bulgaria
   e-mail: akerezov@tu-sofia.acad.bg

   This program is configuring the UTI, doing the measurements
   and sending the result according to the user request using 
   a standart RS232 interface - 8 data bit, 1 stop bit,
   No parity error check. The Baud rate is set authomaticaly
   after sending the character '@'.
   In order to read the on line help, type 'H' or 'h'.
   
   Please feel free to copy and distribute this program free of charge.
   The autor does not accept any lyability for any damages done as a
   result from the application of that program or a part of it.

   For more details please contact the autor.
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	FAST UTI PROGRAM !
		last revision: 01.07.2001
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

*/

#include <16F73.H>

/* Pin definitions */


#define SFmode		PIN_B0
#define PowerDown	PIN_B2
#define PD		02	/* PIN_B2 */
#define CML		PIN_A3
#define OUTPUT		PIN_C2
#define Sync	PIN_C3
#define SEL1	PIN_B5
#define SEL2	PIN_B4
#define SEL3	PIN_A5
#define SEL4	PIN_B1

#define CLR	PIN_A1
#define SCK	PIN_A2
#define DATA	PIN_A0

#byte 	PORTA =	0x05
#byte 	PORTB =	0x06
#byte 	PORTC =	0x07
#byte   PIR1  =	0x0C
#byte   CCPR1H=	0x16
#byte   CCPR1L=	0x15
#byte   RCSTA =	0x18
#byte   RCREG =	0x1A
#byte	TMR1L =	0x0E
#byte	TMR1H =	0x0F
#byte   SPBRG = 0x99
#byte   TXSTA = 0x98
#byte   FSR   = 0x04
#byte   INDF  = 0x00

#bit    RCIF  =	PIR1.5
#bit    CCP1IF= PIR1.2
#bit    carry = 0x03.0
#bit    Zero  = 0x03.2
#bit    CREN  =	RCSTA.4
#bit    BRGH  = TXSTA.2
#bit    TMR1IF= PIR1.0
#bit    RxD_pin  = PORTC.7

long TMR_1;
#byte   TMR_1  = 0x0E

/* PIC16c73 configuration */

#use 	fast_io(B)
#use 	fast_io(C)
#use delay(clock=20000000)
#fuses   HS,NOPROTECT,NOWDT,PUT,NOLVP,NOBROWNOUT
//#fuses   HS,NOPROTECT,NOWDT,PUT
#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7)
#priority timer1,ccp1

/* Variables definition */
int	TMR_compare,answer,Phases,buffer_pointer,softT1;
int	pnt_s,bp,temp_softT1,k,Save_Status,Save_PCLATH,Save_FSR;
long	pnt_h;
short	RESET_FLG,EnableTransmission,Corect_Phase,PreCorect_Phase,Syncronize,PreSyncronize,Mode3_FLG;

#bit    BP_0 = buffer_pointer.0


struct capture {
	int	softwareT;
	long	hardwareT;
		} old_CCP,new_CCP,compare,buffer[10],TxD_buffer[10];
int	*pTxD_buffer,*pBuffer;

#byte   new_CCP_H  = new_CCP+2
#byte   old_CCP_H  = old_CCP+2


int  const Line1[128] = {"\r\n\n              U T I   E V A L U A T I O N   B O A R D   H E L P
\r
\r       s -> Set Slow Mode            f -> Set Fast Mode"};

int  const Line2[232] = {"\r\n       t -> CML = 1 (CMUX12)         n -> CML = 0 (CMUX02)
\r       m -> Single measurement       M -> Infinite measurement cycle
\r                                     p -> Power down
\r       0 -> Mode 0  - 5 Capacitors, 0÷2 pF"};

int  const Line3[225] = {"\r\n       1 -> Mode 1  - 3 Capacitors, 0÷2 pF
\r       2 -> Mode 2  - 5 Capacitors, 0÷12 pF
\r       3 -> Mode 3  - Capacitors, 0÷2 pF if CML=0 / 0÷12 pF if CML=1
\r       4 -> Mode 4  - 3 Capacitors, variable range to 300 pF"};

int  const Line4[230] = {"\r\n       5 -> Mode 5  - Platinium resistor Pt100 - Pt1000, 4 wire
\r       6 -> Mode 6  - Termistor 1k÷25k, 4 wire
\r       7 -> Mode 7  - 2 or 3 platinium resistors Pt100 - Pt1000
\r       8 -> Mode 8  - 2 or 3 termistors 1k÷25k"};

int  const Line5[208] = {"\r\n       9 -> Mode 9  - Resistive bridge, ref. is Vbridge,+/- 200 mV
\r       A -> Mode 10 - Resistive bridge, ref. is Vbridge,+/- 12.5 mV
\r       B -> Mode 11 - Resistive bridge, ref. is Ibridge,+/- 200 mV"};

int  const Line6[207] = {"\r\n       C -> Mode 12 - Resistive bridge, ref. is Ibridge,+/- 12.5 mV
\r       D -> Mode 13 - Resistive bridge and 2 resistors,+/- 200 mV
\r       E -> Mode 14 - Resistive bridge and 2 resistors,+/- 12.5 mV"};

int  const Line7[77] = {"\r\n       F -> Mode 15 - 3 Potentiometers 1k÷50k
\r    Please Make a Choise :"};

/* Timer 1 overflow interrupt service routine */
#int_timer1
void timer1_isr() 
{
   softT1++;
}

/* Input Capture 1 interrupt service routine */
#int_ccp1
/* Input Capture 1 interrupt service routine */
void ccp1_isr() 
{


 if (Mode3_FLG)	// Mode 3
 {
   buffer_pointer++;

   if (BP_0)		//First pass
   {
	output_low (Data);	// Preload 0 as Data
	output_low (SCK);	// Serial Clock generation

  	// Save the captures
	old_CCP.softwareT = softT1;
        old_CCP.hardwareT = CCP_1;
	TMR_compare = TMR1H;
	if (!TMR1IF)
        	if (CCPR1H == 0xFF && TMR_compare == 00) 
			old_CCP.softwareT = softT1-1;
   	if (buffer_pointer == 1)
  	{
		TxD_buffer[1] = buffer[1];
		TxD_buffer[2] = buffer[2];
		TxD_buffer[3] = buffer[3];
		TxD_buffer[4] = buffer[4];
		TxD_buffer[5] = buffer[5];
		TxD_buffer[6] = buffer[6];
		TxD_buffer[7] = buffer[7];
		TxD_buffer[8] = buffer[8];
		TxD_buffer[9] = buffer[9];

		EnableTransmission = 1;	// Transmit - once per sycle
  	}

   }
   else		//Second pass
   {
	//Pulse measurement - Read the captures
	new_CCP.softwareT = softT1;
        new_CCP.hardwareT = CCP_1;
	TMR_compare = TMR1H;
	if (!TMR1IF)
        	if (CCPR1H == 0xFF && TMR_compare == 00) 
			new_CCP.softwareT = softT1-1;

   	// Calculate phase duration
	//old_CCP = new_CCP - old_CCP;
	#asm
		MOVF   	old_CCP.hardwareT,W
		SUBWF  	new_CCP.hardwareT,W
		MOVWF  	old_CCP.hardwareT
		BTFSC  	Carry
		goto	NoOvf_1
		incf	old_CCP_H,f
		BTFSC  	Zero
		incf	old_CCP.softwareT,f
	NoOvf_1:
		MOVF   	old_CCP_H,W
		SUBWF  	new_CCP_H,W
		MOVWF  	old_CCP_H
		BTFSS  	Carry
		incf	old_CCP.softwareT,f
		MOVF   	old_CCP.softwareT,W
		SUBWF  	new_CCP.softwareT,W
		MOVWF  	old_CCP.softwareT
	#endasm
		// Error protection, if old_CCP.softwareT > 0x80 the time is more then 1.6 seconds
		if (old_CCP.softwareT > 0x80) old_CCP.softwareT = 0; // Error protection, 
		
	//	pBuffer = buffer + 3 * (buffer_pointer / 2);
	#asm
		bcf	Carry
		rrf	buffer_pointer,W
		addlw	buffer
		addwf	buffer_pointer,w
		movwf	pBuffer
	#endasm
	// Write the result in the buffer
	*pBuffer = old_CCP.softwareT;
	#asm
		incf	FSR,f
		movf	old_CCP.hardwareT,W
		movwf	INDF
		incf	FSR,f
		movf	old_CCP_H,W
		movwf	INDF
	#endasm

	//Shift MUX & Sync generation

	// Syncronization pulse generation routine
   	if (!(buffer_pointer < (Phases << 1)))	
		{
		output_low (CLR);	// Clear MUX Begin
		output_high (Data);	// Data = 1 on the first pulse
		buffer_pointer = 0;
		output_low(Sync);
		output_high (CLR);	// Clear MUX End
		}
   	else	output_high(Sync);

	output_high (SCK);	// Serial Clock generation - Latch the DATA

	CCP1IF = 0;		// Clear possible switching interrupts
   }

 }
 else	// All the other Modes
 {
 	buffer_pointer++;
	// Syncronization pulse generation routine

   	if (buffer_pointer > Phases)		
		{
		buffer_pointer = 0;
		output_low(Sync);
		if (Corect_Phase)  EnableTransmission = 1;	// Transmit - once per sycle
		if (PreSyncronize) Syncronize = 1; 		// Syncronize - once per sycle
		}
   	else	output_high(Sync);

	//Pulse measurement

   	// Save the captures
	new_CCP.softwareT = softT1;
        new_CCP.hardwareT = CCP_1;
	TMR_compare = TMR1H;
	if (!TMR1IF)
        	if (CCPR1H == 0xFF && TMR_compare == 00) 
			new_CCP.softwareT = softT1-1;

   	// Calculate phase duration
	/*
		if(new_CCP.hardwareT < old_CCP.hardwareT) old_CCP.softwareT++;
      	 	old_CCP.softwareT = new_CCP.softwareT - old_CCP.softwareT;
		old_CCP.hardwareT = new_CCP.hardwareT - old_CCP.hardwareT;
	*/ 	
	#asm
		MOVF   	old_CCP.hardwareT,W
		SUBWF  	new_CCP.hardwareT,W
		MOVWF  	old_CCP.hardwareT
		BTFSC  	Carry
		goto	NoOvf_11
		incf	old_CCP_H,f
		BTFSC  	Zero
		incf	old_CCP.softwareT,f
	NoOvf_11:
		MOVF   	old_CCP_H,W
		SUBWF  	new_CCP_H,W
		MOVWF  	old_CCP_H
		BTFSS  	Carry
		incf	old_CCP.softwareT,f
		MOVF   	old_CCP.softwareT,W
		SUBWF  	new_CCP.softwareT,W
		MOVWF  	old_CCP.softwareT
	#endasm

	//	pBuffer = buffer + 3 * buffer_pointer;
	//	pBuffer = buffer + buffer_pointer + (buffer_pointer<<1);
	#asm
		bcf	Carry
		rlf	buffer_pointer,W
		addlw	buffer
		addwf	buffer_pointer,w
		movwf	pBuffer
	#endasm
	// Write the result in the buffer
	*pBuffer = old_CCP.softwareT;
	#asm
		incf	FSR,f
		movf	old_CCP.hardwareT,W
		movwf	INDF
		incf	FSR,f
		movf	old_CCP_H,W
		movwf	INDF
	#endasm
        old_CCP = new_CCP;	   // Save the old values
 }
}

void syncr()
{
  if (!Mode3_FLG)	// Mode = All but Mode 3
  {
    // Syncronize once per sycle
    PreSyncronize = 1;
    if(Syncronize)
    {
	Syncronize = 0;

	// Find the first phase in the sequense - find the lowerst number 
	bp=1;
	compare.softwareT=buffer[1].softwareT; 
	compare.hardwareT=buffer[1].hardwareT;

	// Extend the buffer for compare
 	buffer[Phases+1].softwareT=buffer[0].softwareT; 
	buffer[Phases+1].hardwareT=buffer[0].hardwareT;

	for (k=2; k<=Phases; k++)
		{
			if (compare.softwareT > buffer[k].softwareT) 
			{
	   			bp=k;
				compare.softwareT=buffer[k].softwareT; 
				compare.hardwareT=buffer[k].hardwareT;
 			}
			if (compare.softwareT == buffer[k].softwareT) 
	  		{
	    			if (compare.hardwareT > buffer[k].hardwareT) 
				{
					bp=k;
					compare.softwareT=buffer[k].softwareT; 
					compare.hardwareT=buffer[k].hardwareT;
 				}
	  		}
		}
	if (buffer[bp-1].softwareT < buffer[bp+1].softwareT) bp--;
	if (buffer[bp-1].softwareT == buffer[bp+1].softwareT) 
		if (buffer[bp-1].hardwareT < buffer[bp+1].hardwareT) bp--;

	if (bp == 0) 	
	{
		if (PreCorect_Phase == 1)	Corect_Phase = 1;
		PreCorect_Phase = 1;

		TxD_buffer[0] = buffer[0];
		TxD_buffer[1] = buffer[1];
		TxD_buffer[2] = buffer[2];
		TxD_buffer[3] = buffer[3];
		TxD_buffer[4] = buffer[4];
		TxD_buffer[5] = buffer[5];
		TxD_buffer[6] = buffer[6];
	}
	else
	{ 
		PreSyncronize = 0;
		PreCorect_Phase = 0;
		Corect_Phase = 0;
		while (buffer_pointer != Phases);
		buffer_pointer = (buffer_pointer - bp);
	}
    }
  }

}
/* Set Slow mode routine */
void SetSlowMode(void){
	output_low(SFmode);
	output_high(PowerDown);
	answer=0;
	}

/* Set Fast mode routine */
void SetFastMode(void){
	output_high(SFmode);
	output_high(PowerDown);
	answer=0;
	}

/* Set CML routine */
void SetCML(void){
if (Mode3_FLG)	{
	output_high(CML);
	output_high(PowerDown);
	answer=0;
		}
	}

/* Clear CML routine */
void ClrCML(void){
	output_low(CML);
	output_high(PowerDown);
	answer=0;
	}

/* Set Power Down mode routine */
void SetPDMode(void){
	output_low(PowerDown);
	answer=0;
	}

/* Set Input Mode routine */
void SetMode(S1,S2,S3,S4,Ph){
int	i;

	output_bit(SEL1,S1);
	output_bit(SEL2,S2);
	output_bit(SEL3,S3);
	output_bit(SEL4,S4);
	output_low(CML);
	Phases=Ph;
	output_high(PowerDown);
	answer=0;
	RESET_FLG=1;

	}

/* Measurent and result send routine */
void NewShowMeasurement(void)
{
int	i;

  if (bit_test(PORTB,PD))
  {

	if (Mode3_FLG)
	{
		while (!EnableTransmission);
		EnableTransmission = 0;

  		for (i=1; !(i > Phases); i++)
		{
		//	pnt_s = TxD_buffer[i].softwareT;
		//	pnt_h = TxD_buffer[i].hardwareT;
	
			if (buffer[i].softwareT != 0) printf("%X",buffer[i].softwareT);
			printf("%lX ",buffer[i].hardwareT);
		}
		printf("\r\n");
		if (answer == 'm')	answer=0;
	}
	else	
	{
		// Wait new sycle
		if (EnableTransmission) 
		{
			EnableTransmission = 0;

			/* Calculate the first phase duration */
			pnt_s=TxD_buffer[0].softwareT+TxD_buffer[1].softwareT;
			pnt_h=TxD_buffer[0].hardwareT+TxD_buffer[1].hardwareT;
			if (carry) pnt_s++;

			if (pnt_s != 0) printf("%X",pnt_s);
			printf("%lX ",pnt_h);
		
  			for (i=2; i<=Phases; i++)
			{
				pnt_s=TxD_buffer[i].softwareT;
				pnt_h=TxD_buffer[i].hardwareT;
	
				if (pnt_s != 0) printf("%X",pnt_s);
				printf("%lX ",pnt_h);
			}
  			printf("\r\n");
			if (answer == 'm')	answer=0;
		}
	}
  }
}


/* Print Help message routine */
void ShowHelp(void)
{
	for (k = 0; k < 128; k++)	putc ( Line1[k] );
	for (k = 0; k < 232; k++)	putc ( Line2[k] );
	for (k = 0; k < 225; k++)	putc ( Line3[k] );
	for (k = 0; k < 230; k++)	putc ( Line4[k] );
	for (k = 0; k < 208; k++)	putc ( Line5[k] );
	for (k = 0; k < 207; k++)	putc ( Line6[k] );
	for (k = 0; k < 77 ; k++)	putc ( Line7[k] );

   	answer=0;
	}


void main(void) 
	{
 	set_TRIS_A(0x00);
   	set_TRIS_B(0x00);
   	set_TRIS_C(0x86);

   	setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   	setup_CCP1(ccp_capture_re);
   	setup_CCP2(ccp_capture_fe);
  
   	output_low(PowerDown); 	/* Put the device in Power Down Mode */
   	output_low(SFmode); 	/* Put the device in Slow Mode */
   	output_low(CML); 	/* Put the device in Normal Mode */

// Configure USART : 0x40 should be send for correct 
// Baud rate calculation - 7 logical 0 (start bit included)


	do
	{
//	   printf ("\r\nWaiting...");
	   while (RxD_pin);	// Wait Start bit
	   TMR_1 = 0;
	   while (!RxD_pin);	// Wait logical 1 after 7 bits in logical 0
	   pnt_h = get_Timer1();	
	   while (RxD_pin);	// Wait logical 0 of the MSB
	   old_CCP.hardwareT = get_Timer1();	
	   while (!RxD_pin);	// Wait Stop bit
	   new_CCP.hardwareT = get_Timer1();

//	   printf ("\r\nCaracter received");

	   // Check if the transmitted value was 0x40	

	   new_CCP.hardwareT -= old_CCP.hardwareT; 	// logical 0 duty
	   old_CCP.hardwareT -= pnt_h; 	// logical 1 duty
	
//	   printf ("\r\n%lX %lX %lX",new_CCP.hardwareT,old_CCP.hardwareT,pnt_h);

	   new_CCP.hardwareT = new_CCP.hardwareT - old_CCP.hardwareT;
	   if ( new_CCP.hardwareT > 0x8000)  new_CCP.hardwareT = 0xFFFF - new_CCP.hardwareT;
	   if (new_CCP.hardwareT < 10)
	   {
		new_CCP.hardwareT = pnt_h / 7;	// 7 logical 0 duty
		new_CCP.hardwareT = new_CCP.hardwareT - old_CCP.hardwareT;
		if ( new_CCP.hardwareT > 0x8000)  new_CCP.hardwareT = 0xFFFF - new_CCP.hardwareT;

		if (new_CCP.hardwareT < 10) break; // it was 0x40, go out	
	   }
	delay_ms(2);	
	} while (1);

//	   printf ("\r\nOUT");

	BRGH  = 1;	// High Baud rates
	// SPBRG calculation: (7 bits duration * 16) / 450
	pnt_h = pnt_h << 4;
	pnt_h = pnt_h / 450;
	SPBRG = pnt_h;
	
	RESET_FLG=0;
 	CREN=0;	     /* Clear Possible Errors  */
	CREN=1;	     /* Enable Continous Receive  */
 	answer = RCREG; 
 	answer = RCREG;		// Empty RxD stack
 	answer = 0;
	Mode3_FLG = 0;

   	enable_interrupts(int_timer1);
   	enable_interrupts(int_ccp1);
   	enable_interrupts(global);


   	do 	{
  
		answer = getc();
   		CREN=0;	     /* Clear Possible Errors  */
  		CREN=1;	     /* Enable Continous Receive  */
		switch(answer)
			{
			case'H':ShowHelp();
				break;
			case'h':ShowHelp();
				break;
			case'?':ShowHelp();
				break;
			case'0':SetMode(0,0,0,0,5);
				break;
			case'1':SetMode(0,0,0,1,3);
				break;
			case'2':SetMode(0,0,1,0,5);
				break;
			case'3':SetMode(0,0,1,1,9);
				Mode3_FLG = 1;
				answer = getc();
   				CREN=0;	     /* Clear Possible Errors  */
  				CREN=1;	     /* Enable Continous Receive  */
				switch(answer)
				{
					case'1': Phases = 1;
						break;
					case'2': Phases = 2;
						break;
					case'3': Phases = 3;
						break;
					case'4': Phases = 4;
						break;
					case'5': Phases = 5;
						break;
					case'6': Phases = 6;
						break;
					case'7': Phases = 7;
						break;
					case'8': Phases = 8;
						break;
					case'9': Phases = 9;
						break;
					default: break;
				}
				break;
			case'4':SetMode(0,1,0,0,3);
				break;
			case'5':SetMode(0,1,0,1,4);
				break;
			case'6':SetMode(0,1,1,0,4);
				break;
			case'7':SetMode(0,1,1,1,5);
				break;
			case'8':SetMode(1,0,0,0,5);
				break;
			case'9':SetMode(1,0,0,1,3);
				break;
			case'A':SetMode(1,0,1,0,3);
				break;
			case'B':SetMode(1,0,1,1,3);
				break;
			case'C':SetMode(1,1,0,0,3);
				break;
			case'D':SetMode(1,1,0,1,5);
				break;
			case'E':SetMode(1,1,1,0,5);
				break;
			case'F':SetMode(1,1,1,1,5);
				break;
			default:break;
			}
		} while (!RESET_FLG);

   	do 	{
		syncr();
		if(RCIF){ 
			answer=getc();
   			CREN=0;	     /* Clear Possible Errors  */
  			CREN=1;	     /* Enable Continous Receive  */
			}
		switch(answer)
			{
			case'H':ShowHelp();
				break;
			case'h':ShowHelp();
				break;
			case'?':ShowHelp();
				break;
			case's':SetSlowMode();
				break;
			case'f':SetFastMode();
				break;
			case'p':SetPDMode();
				break;
			case't':SetCML();
				break;
			case'n':ClrCML();
				break;
			case'm':NewShowMeasurement();
				break;
			case'M':NewShowMeasurement();
				break;
			default:break;
			}
		} while (TRUE);
	}

