Saturday, February 13, 2010

Experiment No. 11: Temperature Data Logger Using PIC16F628A Microcontroller

This project is the combination of the two experiments that we already did in past: Experiment No. 4 and 10. In experiment 4, we demonstrated how to use the mikroC 1-wire library to read temperature data from a digital sensor DS1820, and display the value on a LCD screen. Now we are going to use the hardware UART to transfer the temperature data from the PIC to a PC (Exp. No. 10). The Hyper-Terminal program running on a PC will receive the temperature values and display on screen. The temperature data from the microcontroller will be sent in every 15 sec.

Experimental Setup:

The setup for this experiment is same as the Experiment no. 10 with a DS1820 inserted in its 3-pin female header receiver on the board. The data output of DS1820 is connected to RB.0 (see articles  Exp. No. 4 and 1-Wire Protocol for detail). You need to rebuild the same TTL to RS232 level shifter circuit on a breadboard and set up a hyper-terminal to receive data at 9600 baud rate.



Software:

 /*
 * Project name:
     Temperature Data Logger
    PIC16F628A reads digital temperature data from a DS1820 chip, and
    send it to a PC through RS232 port to display on hyperterminal window.
 * Copyright:
     (c) Rajendra Bhatt, 2009.
*/

// String array to store temperature value to display
char *temp = "000.00";

// Temperature Resolution : No. of bits in temp value = 9
const unsigned short TEMP_RES = 9;

// Variable to store temperature register value
unsigned temp_value;

void Display_Temperature(unsigned int temp2write) {
  const unsigned short RES_SHIFT = TEMP_RES - 8;

  // Variable to store Integer value of temperature
  char temp_whole;

  // Variable to store Fraction value of temperature
  unsigned int temp_fraction;

  // check if temperature is negative
  if (temp2write & 0x8000) {
     temp[0] = '-';
     // Negative temp values are stored in 2's complement form
     temp2write = ~temp2write + 1;
     }

  // Get temp_whole by dividing by 2 (DS1820 9-bit resolution with
  // 0.5 Centigrade step )
  temp_whole = temp2write >> RES_SHIFT ;

  // convert temp_whole to characters
  if (temp_whole/100)
  // 48 is the decimal character code value for displaying 0 on LCD
     temp[0] = temp_whole/100  + 48;
  else
     temp[0] = '0';

  temp[1] = (temp_whole/10)%10 + 48;             // Extract tens digit
  temp[2] =  temp_whole%10     + 48;             // Extract ones digit

  // extract temp_fraction and convert it to unsigned int
  temp_fraction  = temp2write << (4-RES_SHIFT);
  temp_fraction &= 0x000F;
  temp_fraction *= 625;

  // convert temp_fraction to characters
  temp[4] =  temp_fraction/1000    + 48;         // Extract tens digit
  temp[5] = (temp_fraction/100)%10 + 48;         // Extract ones digit

  // Send temperature to RS232
  UART1_Write(10); // Line Feed
  UART1_Write(13); // Carriage Return
  UART1_Write_Text("Temperature= ");
  UART1_Write_Text(temp);

 }

//unsigned char _data = 0x1E;
void main() {
CMCON = 7;       // Disable Comparators
UART1_Init(9600);
Delay_ms(100);
 //--- main loop
  do {
    //--- perform temperature reading
    Ow_Reset(&PORTB, 0);      // Onewire reset signal
    Ow_Write(&PORTB, 0, 0xCC);   // Issue command SKIP_ROM
    Ow_Write(&PORTB, 0, 0x44);   // Issue command CONVERT_T
    Delay_ms(600);
    // If this delay is less than 500ms, you will see the first reading on LCD
    //85C which is (if you remember from my article on DS1820)
    //a power-on-reset value.

    Ow_Reset(&PORTB, 0);
    Ow_Write(&PORTB, 0, 0xCC);    // Issue command SKIP_ROM
    Ow_Write(&PORTB, 0, 0xBE);    // Issue command READ_SCRATCHPAD

    // Read Byte 0 from Scratchpad
    temp_value =  Ow_Read(&PORTB, 0);
    // Then read Byte 1 from Scratchpad and shift 8 bit left and add the Byte 0
    temp_value = (Ow_Read(&PORTB, 0) << 8) + temp_value;

    //--- Format and display result on Lcd
    Display_Temperature(temp_value);
    Delay_ms(30000);

    } while (1);
}

Output:

7 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. #include

    #define DIGIT1 RA0
    #define DIGIT2 RA1
    #define DIGIT3 RA2
    #define ON 0
    #define OFF 1

    /*
    RA5 - Segment a
    RC5 - Segment b
    RC4 - Segment c
    RC3 - Segment d
    RC2 - Segment e
    RC1 - Segment f
    RC0 - Segment g

    RA4 - Thermistor
    */

    __CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT \
    & UNPROTECT & BORDIS & IESODIS & FCMDIS);


    const char LEDDigit[10] = {
    0b0000001, // Digit Zero
    0b1001111, // Digit One
    0b0010010, // Digit Two
    0b0000110, // Digit Three
    0b1001100, // Digit Four
    0b0100100, // Digit Five
    0b0100000, // Digit Six
    0b0001111, // Digit Seven
    0b0000000, // Digit Eight
    0b0000100}; // Digit Nine


    int Temperature, TempDigit, DisplayPos, D1, j;
    int ADCState;

    int i, j, d, t, temp;
    main()
    {
    /////////// INIT ////////////

    PORTA = 0;
    PORTC = 0;
    TRISA = 0b010000; // All Bits of PORTA are Outputs except RA4
    TRISC = 0; // All Bits of PORTC are Outputs

    CMCON0 = 7; // Turn off Comparators
    ANSEL = 1 << 4; // RA4 is ADC input
    ADCON0 = 0b00001101; // Left justify, Use Vdd, Channel 4 (AN3), Do not start, Turn on
    ADCON1 = 0b00010000; // run oscillatr as 8 x prescalar

    DisplayPos = 0;
    j = 0;
    Temperature = 0;
    ADCState = 0;


    //// MAIN LOOP ////

    while(1)
    {
    /////////// DISPLAY READOUT ///////////

    DIGIT1 = OFF;
    DIGIT2 = OFF;
    DIGIT3 = OFF;

    if(DisplayPos == 0) //Light 1st segment
    {
    TempDigit = Temperature % 10; //Just get "1"s place
    RA5 = LEDDigit[TempDigit] >> 6; //Turn on digit
    PORTC = LEDDigit[TempDigit];
    DIGIT3 = ON;
    for(D1=0;D1<414;D1++); //Delay for 7ms

    }else if(DisplayPos == 1) //Light 2nd segment
    {
    TempDigit = Temperature % 100; //Just get "10"s place (strip off "100"s place)
    TempDigit = TempDigit / 10; // and convert to "1"s place
    RA5 = LEDDigit[TempDigit] >> 6; //Turn on digit
    PORTC = LEDDigit[TempDigit];
    DIGIT2 = ON;
    for(D1=0;D1<400;D1++); //Delay for 7ms
    }else //Light 3rd segment
    {
    TempDigit = Temperature / 100; //Just get "100"s place
    RA5 = LEDDigit[TempDigit] >> 6; //Turn on digit
    PORTC = LEDDigit[TempDigit];
    DIGIT1 = ON;
    for(D1=0;D1<400;D1++); //Delay for 7ms
    }

    DisplayPos = (DisplayPos + 1) % 3; //Next segment


    j++;
    if(j == 50) //Time to update temp?
    {
    j = 0;

    switch(ADCState)
    {
    case 0: //Start ADC operation
    GODONE = 1;
    ADCState = 1;
    break;
    case 1:
    ADCState = 0;
    Temperature = ADRESH - 82;
    break;
    }
    }
    }
    }

    this the code but i donno how to store data every 30 mins inside internal eeprom. please help me

    ReplyDelete
  3. I have done EEPROM Read/Write in my experiment no. 6. Check this out: http://pic16f628a.blogspot.com/2009/10/experiment-no-6-readwrite-internal.html

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Have you worked with PIC microcontrollers before? Let me know what have you got first? Do you have a PIC programmer?

    - MicroGuru
    http://learnpicmicrocontrollers.blogspot.com

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. I don't have a schematic for just this project. I am doing all these experiments with my tutorial board that built by myself. You can find the circuit for that in one of my articles, "Make your own PIC develpment board". Then in experimental setup section, I describe what additional connections should be made using jumper wires to do a specific experiment. The software is right above in the blog article. It is in C, I am using mikroC compiler.

    ReplyDelete

Microcontroller-based Embedded Systems Design