/****************************************************************************
ds1820_2a.c

Reads and displays temperature.

                   ---------         --------
           +5--20-|Vdd    B0|-21-11-|D0      |
                  |       B1|-22-12-|D1      |
          Gnd---8-|Vss    B2|-23-13-|D2      |
          Gnd--19-|Vss    B3|-24-14-|D3      |
         6MHz--10-|Xtal   B4|-25--6-|EN      |
             ---9-|Xtal   B5|-26--4-|RS      |
                  |         |        --------
                  | 16F876  |-1----MCLR
                  |       B6|-26---Clock
                  |       B7|-27---Data
                  |         |
       DataIn---11|C0       |
                   ---------

**********************************************************/

#include < 16F876.H >
#include < jonsinc.h >
#fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, NOWRT

#define DS1820_DATA_IN_PIN          PIN_C0
#define DS1820_FET_CONTROL_PIN      PIN_C1
#define DS1820_SKIP_ROM             0xCC
#define DS1820_READ_SCRATCHPAD      0xBE
#define DS1820_CONVERT_T            0x44
// LCD STUFF
#define LCD_D0      PIN_B0
#define LCD_D1      PIN_B1
#define LCD_D2      PIN_B2
#define LCD_D3      PIN_B3
#define LCD_EN      PIN_B4
#define LCD_RS      PIN_B5
#define LINE_1      0x00
#define LINE_2      0x40
#define CLEAR_DISP  0x01
#define DEGREE_SYM  0xdf

#use delay ( clock=6000000 )
#use standard_io ( A )
#use standard_io ( B )
#use standard_io ( C )

void ResetDS1820 ( void );
void WriteDS1820 ( void );
void ReadDS1820 ( void );
void WaitForConversion ( void );
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );

static char cShiftBit,cDataOut;
static long iTemperature,iDataIn;

void main ( void )
    {
    delay_ms ( 200 );

    LCD_Init();
    LCD_SetPosition ( LINE_1 + 0 );
    printf ( LCD_PutChar, "Temperature is" );
    while ( TRUE )
        {
        ResetDS1820();
        cDataOut = DS1820_SKIP_ROM;
        WriteDS1820();
        cDataOut = DS1820_CONVERT_T;
        WriteDS1820();
        WaitForConversion();

        ResetDS1820();
        cDataOut = DS1820_SKIP_ROM;
        WriteDS1820();
        cDataOut = DS1820_READ_SCRATCHPAD;
        WriteDS1820();
        ReadDS1820();
        iTemperature = iDataIn / 2;
        LCD_SetPosition ( LINE_2 + 5 );
        printf ( LCD_PutChar, "%lu%cC %lu%cF   ", iTemperature, DEGREE_SYM, ( ( 9 * iTemperature ) / 5 ) + 32, DEGREE_SYM  );
        }
    }

void ResetDS1820 ( void )
    {
    output_low ( DS1820_DATA_IN_PIN );         // low
    delay_us ( 480 );                               // reset pulse width
    output_float ( DS1820_DATA_IN_PIN );          // high
    delay_us ( 480 );                               // presence pulse width
    }

void WriteDS1820 ( void )             // ~70uS per bit
    {
    for ( cShiftBit = 1; cShiftBit <= 8; ++cShiftBit )
        {
        output_low ( DS1820_DATA_IN_PIN );
        delay_us ( 5 );
        output_bit ( DS1820_DATA_IN_PIN, shift_right ( &cDataOut, 1, 0 ) );
        delay_us ( 60 );
        output_float ( DS1820_DATA_IN_PIN );
        delay_us ( 5 );         // recovery time between slots
        }
    //delay_us ( 200 );           // ???
    }

void ReadDS1820 ( void )             // ~70uS per bit
    {
    iDataIn = 0;
    for ( cShiftBit = 1; cShiftBit <= 16; ++cShiftBit )
       {
       output_low ( DS1820_DATA_IN_PIN );
       delay_us ( 5 );
       output_float ( DS1820_DATA_IN_PIN );
       delay_us ( 5 );
       shift_right ( &iDataIn, 2, input ( DS1820_DATA_IN_PIN ) );   // sample bit
       delay_us ( 55 );         // includes recovery time between slots
       }
    ResetDS1820();              // terminate remainder of scratchpad register transmission
    }

void WaitForConversion ( void )             // ~70uS per bit
    {
    while ( TRUE )
       {
       output_low ( DS1820_DATA_IN_PIN );
       delay_us ( 5 );
       output_float ( DS1820_DATA_IN_PIN );
       delay_us ( 5 );
       if ( input ( DS1820_DATA_IN_PIN ) == 1 )   // sample bit
           {
           break;
           }
       delay_us ( 55 );         // includes recovery time between slots
       }
    }

void LCD_Init ( void )
    {
    LCD_SetData ( 0x00 );
    delay_ms ( 200 );       // wait enough time after Vdd rise
    output_low ( LCD_RS );
    LCD_SetData ( 0x03 );   // init with specific nibbles to start 4-bit mode
    LCD_PulseEnable();
    LCD_PulseEnable();
    LCD_PulseEnable();
    LCD_SetData ( 0x02 );   // set 4-bit interface
    LCD_PulseEnable();      // send dual nibbles hereafter, MSN first
    LCD_PutCmd ( 0x2C );    // function set (all lines, 5x7 characters)
    LCD_PutCmd ( 0x0C );    // display ON, cursor off, no blink
    LCD_PutCmd ( 0x01 );    // clear display
    LCD_PutCmd ( 0x06 );    // entry mode set, increment
    }

void LCD_SetPosition ( unsigned int cX )
    {
    // this subroutine works specifically for 4-bit Port A
    LCD_SetData ( swap ( cX ) | 0x08 );
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );
    LCD_PulseEnable();
    }

void LCD_PutChar ( unsigned int cX )
    {
    // this subroutine works specifically for 4-bit Port A
    output_high ( LCD_RS );
    LCD_SetData ( swap ( cX ) );     // send high nibble
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );     // send low nibble
    LCD_PulseEnable();
    output_low ( LCD_RS );
    }

void LCD_PutCmd ( unsigned int cX )
    {
    // this subroutine works specifically for 4-bit Port A
    LCD_SetData ( swap ( cX ) );     // send high nibble
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );     // send low nibble
    LCD_PulseEnable();
    }

void LCD_PulseEnable ( void )
    {
    output_high ( LCD_EN );
    delay_us ( 10 );
    output_low ( LCD_EN );
    delay_ms ( 5 );
    }

void LCD_SetData ( unsigned int cX )
    {
    output_bit ( LCD_D0, cX & 0x01 );
    output_bit ( LCD_D1, cX & 0x02 );
    output_bit ( LCD_D2, cX & 0x04 );
    output_bit ( LCD_D3, cX & 0x08 );
    }