//  MCP9701_1.c, Temperature Measurement using a MCP9701A
//
// copyright, Peter H. Anderson, Baltimore, MD, April, '23, '10

#ifdef DESCRIPTION

Continually measure the output of a Microchip MCP9701A on AN0.  Calculates
temperature in degrres C and degrees F and displays to LCD.

Note that function;

       admeas(byte channel, byte num_samples) 
       
performs the specified number of A/D readings and averages. 

There are up to 12 A/D channels, seven in terminals associated with PORTB 
and five with PORTA.  The ANSELA and ANSELB registers control whether a terminal
is configured with an A/D input or a digital input.  A point of minor confusion 
is that the bits in ANSELB map into the PORTB bits and not the A/D.  For 
example, bit ANSB3 corresponds to PORTB3 which is AN9.
 
Notable improvements are the ADNREF and ADPREF1 & 0 bits in ADCON1 which permit
a host of voltage reference options.

********************

The MCP9701A is an inexpensive temperature sensor available in a TO-92 package.

For a 5V reference, the temperature is calculated as;

      TC_10 = 2 * adval  + adval / 2 - 205; // 2.5 * adval - 205
      TF_10 = 9 * TC_10 / 5 + 320;  // 1.8 * TC
      
A more complete explanation is at;

      http://www.phanderson.com/PIC/PICC/sourceboost/mcp9701.html


********************

   +5
    |
    MCP9701 -------------- AN0 (term 17)   
    |
   GRD                                     TX (term8) ------ Serial LCD
   

Open on PORTB4 displays in degrees C.  GRD on PORTB4 displays in F.  Note that
the internal weak pullup resistors are used.
    
#endif

#case

#device PIC16F1827 ICD=TRUE

#include <defs_1827.h>
#include <string.h>

#rom 0x8007 = {0x09e4, 0x0003}  // Manual Section 4.0

#define TRUE 1
#define FALSE 0

#define MINUS 0
#define POSITIVE 1

#define SUCCESS 1
#define FAILURE 0

long admeas(byte channel, byte num_samples);

void display_float_1(long x);
void asynch_setup(void);
void ser_char(char ch);

void delay_10us(byte t);
void delay_ms(long t);
void delay_s(long t);


int main()
{
   long adval, TF_10, TC_10;

   ANSELA = 0x01;  // AN0 on RA0 - terminal 17
   ANSELB = 0x00;
   OSCCON = 0x6b; // 4.0 MHz internal

   WPUB = 0x10;
   wpuen_ = 0;  

   asynch_setup();
   delay_ms(10);

   printf(ser_char, "?f");
   delay_ms(25);
   
   while(1)
   {
      adval = admeas(0, 32); // Ch 0, 32 sample average
      TC_10 = 2 * adval  + adval / 2 - 205;
      TF_10 = 9 * TC_10 / 5 + 320;
      if (portb4 == 0)
      {
         display_float_1(TF_10);
         printf(ser_char, " degs F?n");
      }
      else
      {
         display_float_1(TC_10);
         printf(ser_char, " degs C?n");
      }
      delay_s(30); // every 30 seconds
   }
}

long admeas(byte channel, byte num_samples)
{
   // A/D is discussed in Manual Section 15.
   long sum, adval, avg;
   byte n;
   
   // assume that ANSELA and ANSELH have been configured.  Manual Section 12.
  
   ADCON0 = 0x01 | (channel << 2);
   ADCON1 = 0xf0;
   // adfm = 1,  adcs2, adcs1, adcs0 = 111, adnref = 0, adpref1, adpref0 = 00
   sum=0;
   for (n=0; n < num_samples; n++)
   {
      go = 1;
      while(go)
      { // wait for bit to go to zero
      }
      adval = ADRESH;
      adval = (adval << 8) + ADRESL;
      
      sum = sum + adval;
   }
   avg = sum / num_samples;
   return(avg);
}

void display_float_1(long x)
{  // assumes x is positive 
   byte whole, fract;
   whole = x/10;
   fract = x%10;
   printf(ser_char, "%d.%d", whole, fract);
}

void ser_char(char ch)
{
    TXREG = ch;
    while(trmt == 0) // wait for trmt to return to logic one
    {
    }
}

void asynch_setup(void)
{
    txcksel = 0;    // assign TX to RB2
    rxdtsel = 0;    // RX to RB1
    trisb2 = 1;
    trisb1 = 1;    // TX

    spen = 1;     // enable serial port
    sync = 0;     // asynchronous
    txen = 1;     // enable transmitter

    brgh = 1;
    brg16 = 1;
    SPBRGH = 0x00;
    SPBRGL = 103; // 9600 at 4.0 MHz clock
}


void delay_s(long t)
{
   while(t--)
   {
      delay_ms(1000);
   }
}

void delay_ms(long t)   // delays t millisecs
{
   do
   {
     delay_10us(100);
   } while(--t);
}

void delay_10us(byte t)
{
#asm
//      BCF STATUS, RP0
DELAY_10US_1:
      CLRWDT
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      DECFSZ t, F
      GOTO DELAY_10US_1
#endasm
}