//DS18S20 (Dallas Semiconductor 1-wire Bus Temperature Sensor) Interfacing Example in PICCLITE.
//PIC pins used: LCD Display: RB5 - RB0, Temp Sensor: RD0.
//This example works for any LCD Module made by Optrex, Hitachi, etc.
//This example is based on information in the DS18S20 datasheet 
//and Dallas Semiconductor App Note #162 "Interfacing the DS18x20 1-wire temp
//sensor in a microcontroller environment
//Chip Type: PIC16F877
//Clock Frequency: 13.5 MHz
//Written by KEH on 11/01/2003
//LCD Display Type: 20 char X 2 line
//***********************************************************************
//LCD Display Module connections to the PIC 
//   	LCD Pin  LCD Pin #   PIC Sig  PIC Pin #
//      	1		GND			---		---
//       	2   	Vcc			---		---
//		 	3		Vee (Gnded for full contrast)
//			4		RS			RB5		P38
//			5		R/W* (Gnded, since we will only write to LCD module)
//			6		E			RB4		P37
//			7-10 	DB0-DB3 (Not used)	---
//			11		DB4			RB0		P33
//			12		DB5			RB1		P34
//			13		DB6			RB2		P35
//			14		DB7			RB3		P36
//***********************************************************************
	#include <pic.h>
	#define RS 			RB5
	#define RSCMD		0
	#define RSDTA		1
	#define E			RB4

	void initialize_lcd(void);
	void delayms(unsigned char);
	void lcdsendnyb(unsigned char);
	void lcdsendbyte(unsigned char);

	unsigned char one_wire_reset(void);
	void delay6us(unsigned int);
	void write_byte_one_wire(char);
	unsigned char read_byte_one_wire(void);
	unsigned char write_bit_one_wire(char);
	unsigned char read_bit_one_wire(void);
	unsigned char presence;

	void main(void)
{		
	unsigned char j;
	char scratchdat[10],msbtemp,lsbtemp;
	int temp,quot,lschar,middlechar,mschar,fractchar;

PORTB = 0;
TRISB = 0xC0;	// Make RB5-0 all outputs	
TRISD0 = 1;		//RD0 is pulled high through 4.7 kilohm external pullup resistor.
initialize_lcd();
for(;;)
 {	
	one_wire_reset();
	write_byte_one_wire(0xcc);	//skip ROM
	write_byte_one_wire(0x44);	//Start Conversion
	delay6us(18);
	one_wire_reset();
	write_byte_one_wire(0xcc);	//Skip ROM
	write_byte_one_wire(0xBE);	//Read Scratch Pad inside Temp Sensor
	lsbtemp = read_byte_one_wire();
	msbtemp = read_byte_one_wire();
	for(j=0;j<7;j++)
			scratchdat[j] = read_byte_one_wire();
	temp = lsbtemp + (msbtemp<<8);
	if (temp & 1 == 1) fractchar = '5'; else fractchar = '0';
	temp = temp>>1;	 //Get the temperature in degrees C instead of half degrees
	quot = temp/10;
	lschar = (temp - 10*quot) + 0x30;
	temp = quot;
	quot = temp/10;
	middlechar = (temp - 10*quot) + 0x30;
	temp = quot;
	quot = temp/10;
	mschar = (temp - 10*quot) + 0x30;
	RS=RSDTA;
	lcdsendbyte(mschar);
	lcdsendbyte(middlechar);
	lcdsendbyte(lschar);
	lcdsendbyte('.');
	lcdsendbyte(fractchar);
	RS=RSCMD;
	lcdsendbyte(2);		//Position Cursor at "Home Position"
  }
}


void initialize_lcd(void)
{
//initializes LCD Display
	delayms(20);	
	RS=RSCMD;		
	E=0;
	lcdsendnyb(0x3);	// Function Set Command, Gen'l format: 0 0 1 DL N F * *
	delayms(0x5);	// Note that DL = 1 => 8-bit interface mode (Display must be started in 8-bit mode)
					// Note that the N F * * (low order 4 bits) are not connected, and may be any value.
	lcdsendnyb(0x3); 	// Repeat a second time.
	delayms(0x1);
	lcdsendnyb(0x3);	// Repeat a 3rd time
	lcdsendnyb(0x2); 	// Function Set Command - Now we can set interface to 4-bit (nybble) mode

					// Now that we are in nybble mode, we can send all 8 bits of each command via
					// two back-to-back calls to lcdsendnyb( ).
	lcdsendbyte(0x28); // Function Set Command Format: 0 0 1 DL N F * *
								// We just sent:                0 0 1 0  1 0 0 0 
								//  DL=0 => 4-bit mode,
								//	N=1 => 1/8 duty cycle
								//  F=0 => 5 X 7 dot font
	lcdsendbyte(0x08); // Display OFF command
	lcdsendbyte(0x01); // Clear Display command
	lcdsendbyte(0x06);	// Entry mode set command format: 0 0 0 0 0 1 I/D S
							// I/D = 1 => Increment display addr ptr.
							// S = 0 => Do not shift (scroll) display
	lcdsendbyte(0x0C);	// Display ON command
}


void delayms(unsigned char nrms)
{
// Uses Timer #2 to delay the nr of ms specified assuming clock freq = 13.5 MHz
	unsigned char i;
	T2CON=0b0000111;	//Timer 2 tick time = (4/13.5 Mhz)*16 = 0.474E-5 s
						//Nr Ticks in 1 ms = 1E-3 / 0.474E-5 = 210.94 ticks.
	for (i = 0; i < nrms; i++)
		{
			TMR2=256-211;		//Schedule TMR2IF flag to be set in 1 ms
			TMR2IF = 0;			//Clear TMR2IF timeout flag
			while(TMR2IF == 0)
				continue;		//Wait here for 1 ms, until TMR2IF flag is set
		}
}


void delay6us(unsigned int nr6us)
{	unsigned int i;
	for (i = 0; i < nr6us; i++)
		{
			continue;
		}
}

void lcdsendnyb(unsigned char sendval)
{
	unsigned char portbval;
	portbval = PORTB;
	PORTB = (portbval & 0xF0) + (sendval & 0x0F);
								//Send out most sig 4 bits of sendval on RB3:0
	delayms(1);
	E=1;
	delayms(1);
	E=0;
	delayms(1);
}

void lcdsendbyte(unsigned char sendval)
{
	lcdsendnyb(sendval >> 4);
	lcdsendnyb(sendval & 0x0f);
}

unsigned char one_wire_reset(void)
{
	RD0 = 0;
	TRISD0 = 0;			//Pull DQ line low
	delay6us(80);		//Wait for 480 US
	TRISD0 = 1;			//Allow DQ to e pulled high
	delay6us(12);		//Wait for 70 US
	presence = RD0;		//Read state of DQ (hopefully presence pulse is being sent by temp sens)
	delay6us(68);		//Wait 410 US for presence pulse to finish
	return(presence);	
}

unsigned char read_bit_one_wire(void)
{
	unsigned char i;
	RD0 = 0;
	TRISD0 = 0;			//Pull DQ low to start timeslot
	TRISD0 = 1;			//Then let DQ line be pulled high.
	delay6us(1);		//delay 15 us from start of timeslot
	return(RD0);		//return value of DQ line (as set by temp sens)
}

unsigned char write_bit_one_wire(char bitval)
{	RD0 = 0;
	TRISD = 0;			//Pull DQ low to start timeslot
	if(bitval == 1) TRISD = 1; //Let DQ go high to write a 1
	delay6us(18);		//delay 108 us
	TRISD0 = 1;			//Let DQ line go high to end cycle
}

unsigned char read_byte_one_wire(void)
{
	unsigned char i;
	unsigned char value = 0;
	
	for(i=0;i<8;i++)
		{
			if(read_bit_one_wire()) value=value | 1<<i;  //Read byte in one bit at a time
			delay6us(18);						  //Wait for rest of timeslot
		}
	return(value);
}

void write_byte_one_wire(char val)
{
	unsigned char i;
	unsigned char temp;

	for(i=0;i<8;i++)			//Write byte, one bit at a time
		{
			temp = val>>i;		//Shift ith bit into LSB position
			temp = temp & 1;	//Mask out LSB bit value
			write_bit_one_wire(temp);	//Write it to temp sensor
		}
	delay6us(18);
}
