/// 非接触IR回転計					CCS-C source file			///
/// PIC16F876-20   12MHz Clock							///
/// Ver. 1.00					M.Mine		2005-7-7		///

#include	<16f876.h>
#fuses HS, NOWDT, PUT, NOPROTECT, NOBROWNOUT,NOLVP
#device ADC=10							// 10bit ADC
#use delay(clock=12000000)						// CLOCK 12MHz
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)

static long adc_data;
static int seg_0, seg_1, seg_2, seg_3;
static int dot_position, w_dot_p;
static int counter;

///// BCD to SEGMENT TABLE /////

int const LED_SEG[12] =
		{0x7E,0x0C,0xB6,0x9E,0xCC,0xDA,0xFA,0x0E,0xFE,0xCE,0x80,0x00};

///// Timer0 Interrupt ///// LED Display /////

#int_timer0
void isr0()
{
		static int led_flag;				// column flag
		
		#asm
		movlw	0b11000011			// LED Drive0,1,2,3 off
		andwf	0x06, f				// PORTB
		#endasm
				
		switch (led_flag)
		{
			case 0:
			{
				output_C(LED_SEG[seg_0]);				// Display  culumn 0
				if ((dot_position == 1) | (dot_position == 5))
					output_high(PIN_B6);				// dot on
				else
					output_low(PIN_B6);				// dot off
				output_high(PIN_B2);					// Display0 on
				led_flag = 1;
				break; 
			}
			case 1:
			{
				output_C(LED_SEG[seg_1]);				// Display culumn 10
				if ((dot_position == 2) | (dot_position == 5))
					output_high(PIN_B6);
				else
					output_low(PIN_B6);
				output_high(PIN_B3); 
				led_flag = 2;
				break; 
			}
			case 2:
			{
				output_C(LED_SEG[seg_2]);				// Display culumn 100
				if ((dot_position == 3) | (dot_position == 5))
					output_high(PIN_B6);
				else
					output_low(PIN_B6);
				output_high(PIN_B4); 
				led_flag = 3;
				break; 
			}
			case 3:
			{
				output_C(LED_SEG[seg_3]);				// Display culumn 1000
				if ((dot_position == 4) | (dot_position == 5))
					output_high(PIN_B6);
				else
					output_low(PIN_B6);
				output_high(PIN_B5); 
				led_flag = 0;
				break; 
			}
			default:
			{
				led_flag = 0;
				break; 
			}
		}
}

///// Timer1 Interrupt ///// Pulse interbal count /////

#int_timer1						//
void isr1()							// Start: timer1, Counter clear 
{
	if (counter < 10)					// 1,747.5mS
		counter ++;
}
			
///// PORT initialize
void port_init()
{
	setup_adc_ports(RA0_ANALOG);				// 1ch. Analog input mode
	setup_adc(ADC_CLOCK_DIV_2);				// ADC clock Fosc/2
	port_b_pullups(TRUE);					// portB pull-up Enable
	set_tris_a(21);					// A0,A2,A4 input
	set_tris_b(131);					// B0,B1,B7 input
	set_tris_c(1);					// C1, input
	setup_timer_2(T2_DIV_BY_16,0xFF,1);			// full count
}

///// ADC input /////
void adc_in(int an)
{
	set_adc_channel(an);
     	delay_us(50);
      	adc_data = read_adc();
}

//// Zero suppress /////
void zero_suppress()
{
	if (seg_3 == 0)					// zero suppress
		seg_3 = 11;				// Blank
	if ((seg_3 == 11) && (seg_2 == 0))
		seg_2 = 11;
	if ((seg_2 == 11) && (seg_1 == 0))
		seg_1 = 11;
}

///// main program /////
void main()
{
	int	pc0in;
	int pc1in;
	int blade;
	unsigned long cnt_wrk;
	unsigned long timer_buf;
	float w_time;
	float cnt_rpm;
	
	port_init();						// initialeze port direction
	output_high(PIN_A1);					// 12F629 MCLR  on
	
	seg_0 = 0;
	seg_1 = 0;
	seg_2 = 0;
	seg_3 = 0;
	zero_suppress();					// LED segment clear
	
	/// Timer0 Initialize        (5mS for LED Display)
	setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);		// timer_0 set 5mS start
	set_timer0(0);
	
	/// Timer1 Initialize 
	set_timer1(0);					// 174.75mS (Max count : 16Bit)
	counter = 0;					// Upper byte of timer_1 (0-10)
	setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);		// timer start
	
	/// Interrupt Enable
	enable_interrupts(INT_TIMER0);				// Timer0 Interrupt Enable
	enable_interrupts(INT_TIMER1);				// Timer1 Interrupt Enable
	enable_interrupts(GLOBAL);				// interrupt enable
	
	while(1)
	{
		output_bit(PIN_A3, input(PIN_B7));		// IR (12F629) ON/OFF
		
		if (!input(PIN_B7))				// sw0 ON ?
		{				
			pc0in = pc1in;			// previous IR input data
			pc1in = input(PIN_C0); 		// IR input data
		
			if ((pc0in == 1) && (pc1in == 0))		// down edge (IR Data) 
			{
				if (counter < 10)
				{
					setup_timer_1(T1_DISABLED);					// Timer1 Stop
					timer_buf = (long) get_timer1();

					w_time = (float)(timer_buf * 174.75 / 65536) + (counter * 174.75);
					cnt_rpm = (float) (1000 / w_time *60);				// convert to RPM
					cnt_wrk = (long) cnt_rpm;
					cnt_wrk = cnt_wrk / blade;					// Brade Numbers
					
					if ((cnt_wrk >= 1) && (cnt_wrk < 10000))			// under 10,000 RPM
					{
						seg_0 = cnt_wrk % 10;
						cnt_wrk = cnt_wrk / 10;
						seg_1 = cnt_wrk % 10;
						cnt_wrk = cnt_wrk / 10;
						seg_2 = cnt_wrk % 10;
						cnt_wrk = cnt_wrk / 10;
						seg_3 = cnt_wrk % 10;
						dot_position = 0;
						w_dot_p = 0;
						zero_suppress();
					}
					else if ((cnt_wrk >= 10000) && (cnt_wrk < 100000))		// over 10,000 RPM
					{
						cnt_wrk = cnt_wrk / 10;
						seg_0 = cnt_wrk % 10;
						cnt_wrk = cnt_wrk / 10;
						seg_1 = cnt_wrk % 10;
						cnt_wrk = cnt_wrk / 10;
						seg_2 = cnt_wrk % 10;
						cnt_wrk = cnt_wrk / 10;
						seg_3 = cnt_wrk % 10;
						dot_position = 3;	
						w_dot_p = 3;
						zero_suppress();
					}
					else
					{
					seg_0 = 10;				// '----'
					seg_1 = 10;
					seg_2 = 10;
					seg_3 = 10;
					dot_position = 0;
					w_dot_p = 0;
					}
				}
				else
				{
					seg_0 = 10;				// '----'
					seg_1 = 10;
					seg_2 = 10;
					seg_3 = 10;
					dot_position = 0;
					w_dot_p = 0;
				}
				
				set_timer1(0);					// 174.75mS
				counter = 0;					// upper count byte of timer1
				pc0in = pc1in;					// previous IR input data 
				pc1in = input(PIN_C0); 				// IR input data
						
				while (!((pc0in == 1) && (pc1in == 0)))			// down edge of IR input data
				{
					pc0in = pc1in;				// previous IR input　data
					pc1in = input(PIN_C0); 			// IR input data
					set_timer1(0);		
					counter = 0;				// upper count byte of timer1
				}
				setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);		// Timer1 Start
				if (!(input(PIN_A4)))	
					delay_ms(20);				// 20mS of chatter flee delay	
				if (!(input(PIN_A2)))
					delay_ms(100);				// 100mS of chatter flee delay	
			}
		}
		else
		{
			blade = (input(PIN_B0)) + ((input(PIN_B1)) * 2) + 1;			// blade sw read
		
			adc_in(0);
			if (adc_data > 424)						//  1.244/3.00*1024	 (3V)
			{
				dot_position = 5;					// Low Battery Voltage Alarm
			}
			else
				dot_position = w_dot_p;
		}
	}
}

