Tuesday, September 7, 2010

PIC16F628A + DS1820 + 4-Digit Seven Segment C/F Thermometer

Introduction
This project describes how to read temperature from a DS1820 sensor with a PIC16F628A microcontroller and display the temperature value in a multiplexed 4-digit seven segment display. The temperature will be displayed in both Centigrade and Fahrenheit units switching back and forth. The temperature resolution is 1 degree in both the units. Out of 4-digits, the most significant three digits will display numeric temperature values from 00 to 125. The most significant digit will show '-' for negative temperatures, and the least significant digit will display C or F.

On my PIC16F628A board, connect D1 to RA2, D2 to RA1, D3 to RA0, and D4 to RA3. DS1820 data will be read at RA4 port. The seven segments a-g will be driven by RB0-RB6.

Software

/* Project name:
     Seven-segment display digital thermometer
 * Copyright:
     (c) Rajendra Bhatt, 2010.
      MCU:             PIC16F628A
     Oscillator:      XT, 4.0 MHz
*/

// Temperature digits
unsigned short i, DD0=0x3f, DD1=0x3f,DD2=0x3f, CF_Flag=0xff, CF=0x3f, N_Flag;
// CF_Flag = 0: F, 1: C
// Variable to store temperature register value
unsigned temp_value=0, temp_whole;
unsigned int temp_fraction=0;
float temp_F;

//-------------- Function to Return mask for common cathode 7-seg. display
unsigned short mask(unsigned short num) {
  switch (num) {
    case 0 : return 0x3F;
    case 1 : return 0x06;
    case 2 : return 0x5B;
    case 3 : return 0x4F;
    case 4 : return 0x66;
    case 5 : return 0x6D;
    case 6 : return 0x7D;
    case 7 : return 0x07;
    case 8 : return 0x7F;
    case 9 : return 0x6F;
    case 10 : return 0x40;  // Symbol '-'
    case 11 : return 0x39;   // Symbol C
    case 12 : return 0x71;   // Symbol F
    case 13 : return 0x00;  // Blank
  } //case end
}

void display_temp(short DD0, short DD1, short DD2, short CF)    {
    for (i = 0; i<=200; i++) {
      PORTB = DD0;
      RA0_bit = 1;          // Select Ones Digit
      RA1_bit = 0;
      RA2_bit = 0;
      RA3_bit = 0;
      delay_ms(5);
      PORTB = DD1;
      RA0_bit = 0;
      RA1_bit = 1;        // Select Tens Digit
      RA2_bit = 0;
      RA3_bit = 0;
      delay_ms(5);
      PORTB = DD2;
      RA0_bit = 0;
      RA1_bit = 0;
      RA2_bit = 1;        // Select +/- Digit
      RA3_bit = 0;
      delay_ms(5);
      PORTB = CF;
      RA0_bit = 0;
      RA1_bit = 0;
      RA2_bit = 0 ;
      RA3_bit = 1;        // Select CF Digit
      delay_ms(5);
        }
     return;
}


void main() {
  CMCON  |= 7;      // Disable Comparators
  TRISB = 0x00;    // Set PORTB direction to be output
  PORTB = 0x00;    // Turn OFF LEDs on PORTB
  TRISA0_bit = 0;  // RA.0 to RA3 Output
  TRISA1_bit = 0;
  TRISA2_bit = 0;
  TRISA3_bit = 0;


    //--- main loop
  do {

    N_Flag = 0;  // Reset Temp Flag
    //--- perform temperature reading
    Ow_Reset(&PORTA, 4);      // Onewire reset signal
    Ow_Write(&PORTA, 4, 0xCC);   // Issue command SKIP_ROM
    Ow_Write(&PORTA, 4, 0x44);   // Issue command CONVERT_T
    display_temp(DD0, DD1, DD2,CF)   ;
    Ow_Reset(&PORTA, 4);
    Ow_Write(&PORTA, 4, 0xCC);    // Issue command SKIP_ROM
    Ow_Write(&PORTA, 4, 0xBE);    // Issue command READ_SCRATCHPAD

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

    if (temp_value & 0x8000) {
     temp_value = ~temp_value + 1;
     N_Flag = 1;   // Temp is -ive
     }
    if (temp_value & 0x0001) temp_value += 1;   // 0.5 round to 1
    temp_value = temp_value >> 1 ;
    if (CF_Flag == 0) {
     if (N_Flag ==1) {
      temp_F = (32.0-9.0*temp_value/5.0)*10 + 6;
      if (temp_F < 0){
         N_Flag=1;
         temp_value = abs(temp_value);
         }
         else N_Flag = 0;
      }
    else temp_F = (9.0*temp_value/5.0+32.0)*10 + 6; //If decimal is greater or equal
                                             // to 0.5, add 0.5
    temp_value = temp_F/10;
    CF = 12;
    }

    if (CF_Flag == 0xff) CF = 11;

    DD0 = temp_value%10;  // Extract Ones Digit
    DD0 = mask(DD0);
    DD1 = (temp_value/10)%10; // Extract Tens Digit
    DD1 = mask(DD1);
    DD2 =  temp_value/100; // Extract Hundred digit
    CF = mask(CF);
    if (N_Flag == 1) DD2=10;
    else if (DD2 == 0) DD2 = 13 ;
    DD2 = mask(DD2) ;

      PORTB=0x00;
      CF_Flag =~CF_Flag;

    } while (1);
}



Output Pictures





Over 99F temperature reading (touched the sensor with a hot soldering iron )

9 comments:

  1. Perfect mr Raj. I waiting this type of project for a long time.
    Your blog is excellent.
    Very tanks,
    from Brazil.

    ReplyDelete
  2. mr Raj tq for sharing this project.
    did you have a circuit for this project?
    i want know that because i have doing this to my project
    very thank
    from malaysia.

    ReplyDelete
  3. I try to simulate this schematic in Proteus, but in display I have only strange characters :( ... I tried both variant of display, AC and CC ... What could be wrong ? Thanks and regards !

    ReplyDelete
  4. do u have the circuit diagram ti build this project,
    if yes mail me

    theresraj57@gmail.com

    ReplyDelete
  5. Still no answer ... Please, check your mail for schematic. Thanks !

    ReplyDelete
  6. do u have the circuit diagram ti build this project,
    if yes mail me umutozgur@gmail.com

    ReplyDelete
  7. Still not having the schematic for this thermometer :( ... Happy new Year 2016 !

    ReplyDelete
  8. Hello reallynice project. Will you please send the circuit diagram of this project? Thank you...
    s-karaaslan@hotmail.com

    ReplyDelete
  9. Last post on this site is on 2011 ...

    ReplyDelete

Microcontroller-based Embedded Systems Design