#include	<16F84.H>
#include	<STDLIB.H>

#use		delay(clock=4000000)

#include	"1WIRE.H"
#include	"MAX7219.H"

#inline
signed long readSingleDS1820()
{

	int temperatureLSB, temperatureMSB, ok=0;
	signed long temperature, countRemainLong,countDegCLong;
	
	ok+=initialise1_wire_with_error_check(); // initialise DS1820.
		
	send1_wire(0xCC); // send 'Skip ROM' command to DS1820.
	send1_wire(0x44); // send 'Convert T' command to DS1820.
	
	output_high(PIN_B0);
	delay_ms(500); // leave 1-wire high for 500ms to provide power for temp. conversion.

	ok+=initialise1_wire_with_error_check(); // initialise DS1820.
		
	send1_wire(0xCC); // send 'Skip ROM' command to DS1820.
	send1_wire(0xBE); // send 'Read Scratchpad' command to DS1820.
	
	temperatureLSB = read1_wire();
	temperatureMSB = read1_wire();
	
	read1_wire(); // skip the TH, TL and reserved bytes.
	read1_wire();
	read1_wire();
	read1_wire();
	
	countRemainLong = (signed long)read1_wire();
	countDegCLong = (signed long)read1_wire();
		
	ok+=initialise1_wire_with_error_check(); // initialise DS1820.
	temperature=(long)temperatureLSB;
	
	if (bit_test(temperatureMSB,1))  // check MSB for negative temperature.
	{	
		bit_set(temperature,15);
		bit_set(temperature,14);
		bit_set(temperature,13);
		bit_set(temperature,12);
		bit_set(temperature,11);
		bit_set(temperature,10);
		bit_set(temperature,9);
		bit_set(temperature,8);
		shift_right(&temperature,1,1); // discard the inaccurate last half degree.
		
	}
	else
	{
		shift_right(&temperature,1,0); // discard the inaccurate last half degree.
	}
	
	 
	temperature*=10; // then multiply by ten to avoid having to use floating point numbers.
	
	temperature+=((-25+(100*(countDegCLong-countRemainLong))/countDegCLong)/10);

	if (ok==3)
	{
		return( temperature );
	}
	else
	{
		return( 10000 );
	}

}


display(int digit,int show)
{

	long data=0;
	int count;
	long digitLong;

	digitLong=(long) digit;
	
	for(count=0; count<8; ++count)
	{				// form data to pass to display driver,
		shift_left(&digitLong,2,0); // by shifting digit number 8 places left,
	}

	digitLong+=show;			// and adding the symbol code.

	send7219( digitLong );	

}	


showTemp(signed long temperatureToShow, short metric, int offset)
{

	signed long temperatureToShowDiv10;

	int digit;
	long decode;
	
	
	temperatureToShowDiv10=temperatureToShow/10;


	send7219(0b0000110000000000);
	decode=0b0000100100001111;

	for (digit=1; digit<=4; digit++)
	{

		display(digit,0b1111);		

		if (digit==offset)
		{
		
			if (temperatureToShow<=-10)
			{
				display( digit, 0b1010);
			}
			else
			{
				if (temperatureToShow>=100)
				{
					display( digit,(int)(temperatureToShowDiv10/10)%10);
				}
			}

		}

		if (digit==offset+1)
		{
			if (temperatureToShow>-10 && temperatureToShow<0)
			{
				display( digit, 0b1010);
			}
			else
			{
				if (temperatureToShow>=10 || temperatureToShow<=-10)
				{
					display( digit,(int)(temperatureToShowDiv10)%10);
				}
			}
		}


		if (digit==offset+2)
		{
			display( digit,(int)temperatureToShow%10);
		}

		
		if (digit==offset+3)
		{
			
			if (digit==1) bit_clear(decode,0);
			if (digit==2) bit_clear(decode,1);
			if (digit==3) bit_clear(decode,2);
			if (digit==4) bit_clear(decode,3);

			if (metric) 
			{
				display( digit, 0b11001110 ); // deg C on fourth.
			}
			else
			{
			 	 display( digit,0b11000111); // deg F on fourth.
			}
		}
	}

	send7219(decode);
	send7219(0b0000110000000001);

}


main()
{

	const int scrollDelay=60; // scroll delay in ms
	const int displayStyle=1; // 1 for 'bouncing' display, 2 for left-scrolling display, 3 for right-scrolling display

	signed long temperature, temperatureToShow;
	int temperatureDecimal,metricI,metricNotI;
	signed int pos;
	short int roundUpC=false, roundUpF=false, metric=false, started=false;

	port_b_pullups(TRUE); // set input pullups so 1-wire stays high
	send7219(0b0000101100000011); // scan 4 digits.
	send7219(0b0000101000001111); // full intensity.

	do 
	{	
		do
		{
			temperature = readSingleDS1820();
		}
		while (temperature==10000);

		if (started) {

			delay_ms(7000);



			for (pos=1; pos>=-3; pos--)
			{
#if (displayStyle==1)
				showTemp(temperatureToShow,metric,(metricNotI*pos)+(metricI*(2-pos))); // for 'bouncing' display
#endif
#if (displayStyle==2)
				showTemp(temperatureToShow,metric,pos); // for left-scrolling display
#endif
#if (displayStyle==3)
				showTemp(temperatureToShow,metric,2-pos); // for right-scrolling display
#endif
				delay_ms(scrollDelay);
			}	

		}
		started=1;

		metric=!metric;

		metricI=(int)metric;
		metricNotI=(int)!metric;

		if (!metric)
		{
			temperature*=9;
			temperature/=5;
			temperature+=320;
		}

		temperatureDecimal=temperature%10;
		temperatureToShow=temperature/10;

		if (temperatureDecimal<4)
		{		
			if (metric) 
			{
				roundUpC=false;
			}
			else
			{
				roundUpF=false;
			}
		} 
	
		if (temperatureDecimal>6)
		{
			if (metric)
			{
				roundUpC=true;
			}
			else
			{
				roundUpF=true;
			}
		}
	
		if ((roundUpC && metric) || (roundUpF && !metric)) temperatureToShow++;

		for (pos=5; pos>=1; pos--)
		{

#if (displayStyle==1)
			showTemp(temperatureToShow,metric,(metricI*pos)+(metricNotI*(2-pos))); // for 'bouncing' display
#endif
#if (displayStyle==2)
			showTemp(temperatureToShow,metric,pos); // for left-scrolling display
#endif
#if (displayStyle==3)
			showTemp(temperatureToShow,metric,2-pos); // for right-scrolling display
#endif
			delay_ms(scrollDelay);
		}
		
	}
	while (TRUE);

}
