OneWire - DS18B20 - PIC18F4550 code query

Discussion in 'Embedded Systems and Microcontrollers' started by GrafZeppelin, Jun 15, 2016.

  1. GrafZeppelin

    Thread Starter New Member

    May 3, 2013
    11
    0
    Hello all,

    I am trying to read temperature from DS18B20 sensor using the OneWire protocol (non parasitic) and a PIC18F4550 (Aptinex development board with a built-in DS18B20). I've read both OneWire and DS18B20 datasheets, then I tried to look up some example codes just to understand how it all works, but the more I tried to understand the main function part, the more confused I got. I think I understand how reset, write and read functions work (clear explanations in the datasheet), but the part that confuses me the most is how to actually read data from the sensor. Below is a code that I found somewhere on the net, and after I build it, the result is in the pic. Also, after 3 seconds, the screen goes blank. The LCD module is 100% working. I really do not understand what is going on this part:

    tempL = read();
    tempH = read();

    tempL >>= 4;
    tempH <<= 4;
    tempH += tempL;
    tempL = DEC2BCD(tempH);


    Could someone please give any insights what is going on in that part and why the outcome is like that. Any help will be greatly appreciated!

    Code (Text):
    1. #define _XTAL_FREQ 8000000
    2.  
    3. #include <xc.h>
    4. #include <stdio.h>
    5. #include "delay.h"
    6. #include "LCD_4bit_config.h"
    7.  
    8. #define DEC2BCD(dec) (((dec / 10) << 4) + (dec % 10))
    9.  
    10. #define Skip_ROM 0xCC                // 0b11001100
    11. #define Convert_temperature 0x44    // 0b01000100
    12. #define Read_scratchpad 0xBE            // 0b10111110
    13. #define Write_scratchpad 0x4E
    14.  
    15. #define Data_pin LATB0
    16.  
    17. unsigned short tempL, tempH;
    18.  
    19. char reset()
    20. {
    21. TRISB0 = 0;             // Drive bus low
    22. __delay_us(480);        // Delay 480us
    23. TRISB0 = 1;                // Release bus
    24. __delay_us(70);            // Delay 70us
    25.  
    26. if (Data_pin == 0)        // Sample bus
    27.     {
    28.         __delay_us(410);
    29.         return 0;        // Device present
    30.     }
    31.     else
    32.     {
    33.         __delay_us(410);
    34.         return 1;        // No device present
    35.     }
    36. }
    37.  
    38. write(char a)
    39. {
    40.     char i;
    41.     Data_pin = 1;
    42.    
    43.         for (i=0;i<8;i++)
    44.         {
    45.             if ((a & (1<<i)) != 0 )
    46.             {
    47.                 TRISB0 = 0;            // Write 1 bit
    48.                 Data_pin = 0;
    49.                 __delay_us(6);
    50.                 TRISB0 = 1;
    51.                 __delay_us(64);  
    52.             }  
    53.            
    54.             else
    55.             {
    56.                 TRISB0 = 0;            // Write 0 bit
    57.                 Data_pin = 0;
    58.                 __delay_us(60);
    59.                 TRISB0 = 1;  
    60.                 __delay_us(10);
    61.             }
    62.         }      
    63. }
    64.  
    65. char read()
    66. {
    67.     char i, result = 0;
    68.     TRISB0 = 1;                //RB0 as input
    69.        
    70.         for (i=0;i<8;i++)
    71.         {
    72.             TRISB0 = 0;        // Drive bus low
    73.             Data_pin = 0;    // Generate low pulse for 2us
    74.             __delay_us(6);
    75.             TRISB0 = 1;        // Release the bus
    76.             __delay_us(9);
    77.            
    78.             if (Data_pin != 0)            // Sample bus to read bit from slave
    79.                 {
    80.                     result |= 1<<i;
    81.                     __delay_us(55);  
    82.                 }
    83.             return result;  
    84.         }  
    85. }
    86.  
    87. main()
    88. {
    89.     char s[20];
    90.    
    91.     OSCCON = 0b11110100;    // Set internal oscillator to 8 MHz
    92.     ADCON1 = 0x0F;            // Set all pins as digital I/O
    93.     CMCON = 0x07;             // Set all comparators as digital I/O
    94.  
    95.     TRISD = 0x00;                // Set PORTD as digital OUTPUT for the LCD
    96.     LATD = 0;                  // Clear PORTD
    97.    
    98.     TRISB = 0xFF;                // Set PORTB as digital INPUT
    99.     LATB = 0;                // Clear PORTB
    100.    
    101.     LCD_init();        // Initialize LCD module
    102.     LCD_clr();
    103.    
    104.     while (1)
    105.     {
    106.         if (!reset())
    107.         {
    108.             write(Skip_ROM);          
    109.             write(Convert_temperature);
    110.             delay_ms(750);
    111.            
    112.             reset();
    113.            
    114.             write(Skip_ROM);
    115.             write(Read_scratchpad);
    116.            
    117.             tempL = read();
    118.             tempH = read();
    119.            
    120.             tempL >>= 4;
    121.             tempH <<= 4;
    122.             tempH += tempL;
    123.             tempL = DEC2BCD(tempH);
    124.                    
    125.             sprintf(s,"%d  %d",tempL,tempH);
    126.            
    127.             LCD_setCursor(1,1);
    128.             LCD_writeString(s);
    129.         }  
    130.     }
    131. }
    IMG_1352.JPG OneWire_DS18B20.JPG
     
  2. JWHassler

    Member

    Sep 25, 2013
    201
    33
    The code seems to be doing this:
    - Read the lower byte of the temperature into TempL
    - Read the upper byte into TempH
    - Divide the LSB by 16, removing the fractional degrees
    - multiply the MSB by 16, dropping of four unneeded sign bits
    - Merge the two numbers, making a value in the +125 to -55 range.. you will be seeing the middle 8 bits of the values in Table 2 of the datasheet

    I never liked that datasheet
     
  3. dannyf

    Well-Known Member

    Sep 13, 2015
    1,811
    362
    If I were you, I would feed tempL and tempH known good numbers right after you read thee device so you know if the issue is with your display routines or not.

    Go from there.
     
  4. GrafZeppelin

    Thread Starter New Member

    May 3, 2013
    11
    0
    Thanks guys for your input. I have fiddled around with the wires connecting the MCU and LCD, and now the result is stable, almost. The outcome now is:

    IMG_1353.JPG

    Though for a short moment on a second line it displays 0-016.. I have no idea why. The code now is:
    Code (Text):
    1. void main()
    2. {
    3.     char s[16];
    4.    
    5.     short tempL;
    6.     short tempH;
    7.  
    8.     OSCCON = 0b11110010;    // Set PIC18F4550 internal oscillator at 8MHz
    9.  
    10.     ADCON1 = 0x0F;            // Set all pins as digital I/O
    11.     CMCON = 0x07;             // Set all comparators as digital I/O
    12.  
    13.     LATD = 0;                // Clear port D
    14.     TRISD = 0b00000000;        // Set all port D pins as digital outputs
    15.  
    16.     LATB = 0;
    17.     TRISB = 0x00;
    18.  
    19.     LCD_init();                // Initialize LCD
    20.  
    21.     while(1)
    22.     {
    23.         LCD_setCursor(1,1);
    24.         LCD_writeString("Temperature:");
    25.      
    26.      
    27.          if (!reset())
    28.         {
    29.             write(Skip_ROM);        
    30.             write(Convert_temperature);
    31.             delay_ms(750);
    32.          
    33.             reset();
    34.          
    35.             write(Skip_ROM);
    36.             write(Read_scratchpad);
    37.          
    38.             tempL = read();
    39.             tempH = read();
    40.          
    41.             tempL >>= 4;
    42.             tempH <<= 4;
    43.             tempH += tempL;
    44.             tempL = DEC2BCD(tempH);
    45.                  
    46.             sprintf(s,"%d-%d",tempL,tempH);
    47.          
    48.             LCD_setCursor(2,1);
    49.             LCD_writeString(s);
    50.         }
    51.      }
    52. }
    @MMcLaren, how should I create an 8-bit variable instead of 16bit?
    And to add to my question, how should I display true temperature from a single variable?
     
    Last edited: Jun 15, 2016
  5. GrafZeppelin

    Thread Starter New Member

    May 3, 2013
    11
    0
    OK, so I got something working. I've tried combining the maxim code with some of the codes I found on the web, and of course the glorious DS18B20 datasheet was a big help. I am now able to see presence pulse(0), family code(0x28) and the temperature(11). The problem now is that in my room the tremperature is ~27 degrees C. Anybody know why the output is like that? Please see my codes:

    DS18B20 header:
    Code (Text):
    1. #define __XTAL_FREQ 8000000
    2.  
    3. #define Data_pin RB2
    4. #define Data_bus TRISB2
    5. #define Skip_ROM 0xCC                // 0b11001100
    6. #define Convert_temperature 0x44    // 0b01000100
    7. #define Read_scratchpad 0xBE            // 0b10111110
    8. #define Read_deviceFamily 0x33
    9.  
    10. int OneWire_reset()
    11. {
    12.     Data_bus = 0;        //Set as output
    13.     Data_pin = 0;        //Drive Low
    14.     __delay_us(480);
    15.     Data_bus = 1;        //Release, Set back as input
    16.     __delay_us(70);
    17.  
    18. if (Data_pin == 0)        // Sample bus
    19.     {
    20.         __delay_us(410);
    21.         return 0;        // Device present
    22.     }
    23.     else
    24.     {
    25.         __delay_us(410);
    26.         return 1;        // No device present
    27.     }
    28. }
    29.  
    30. int OneWire_readByte(void)
    31. {
    32.     int l, result = 0;
    33.     for(l=0;l<8;l++)
    34.     {
    35.         result >>= 1;
    36.         if(OneWire_readBit())
    37.             result |= 0x80;
    38.     }
    39.     return result;
    40. }
    41.  
    42. int OneWire_readBit(void)
    43. {
    44.     unsigned int Read_state = 0;
    45.    
    46.     Data_bus = 0;        //Set as output
    47.     Data_pin = 0;        //Drive low
    48.     __delay_us(6);
    49.     Data_bus = 1;        //Release, set as input
    50.     __delay_us(9);
    51.     Read_state = Data_pin;
    52.    
    53.     return Read_state;
    54. }
    55.  
    56. void OneWire_writeBit(unsigned int b)
    57. {
    58.     Data_bus = 0;        //Set as output
    59.        Data_pin = 0;        //Drive low
    60.  
    61.     if(b == 1)
    62.     {
    63.         __delay_us(3);
    64.         Data_bus = 1;    //Release, set as input
    65.         __delay_us(62);
    66.     }
    67.     else
    68.     {
    69.         __delay_us(57);
    70.         Data_bus = 1;    //Release, set as input
    71.         __delay_us(7);
    72.     }
    73. }
    74.  
    75. void OneWire_writeByte(unsigned int data)
    76. {
    77.     int l;
    78.     for(l=0;l<8;l++)
    79.     {
    80.         OneWire_writeBit(data & 0x01);
    81.         data >>= 1;
    82.     }
    83. }
    And the main code:
    Code (Text):
    1. #define _XTAL_FREQ 8000000
    2.  
    3. #include <xc.h>
    4. #include <stdio.h>
    5. #include "LCD_4bit_config.h"
    6. #include "DS18B20_config.h"
    7. #include "delay.h"
    8.  
    9. OneWire_init()
    10. {
    11.         int i;
    12.         char buf1[10];
    13.         char buf2[10];
    14.        
    15.         LCD_setCursor(1,1);
    16.         LCD_writeString("Presence:");
    17.        
    18.         i = OneWire_reset();
    19.            
    20.         sprintf(buf1,"%d",i);
    21.         LCD_setCursor(2,1);
    22.         LCD_writeString(buf1);
    23.        
    24.         delay_ms(3000);
    25.         LCD_clr();
    26.            
    27.         OneWire_reset();
    28.        
    29.         LCD_setCursor(1,1);
    30.         LCD_writeString("Device family:");
    31.            
    32.         OneWire_writeByte(Read_deviceFamily);
    33.            
    34.         i = OneWire_readByte();
    35.            
    36.         sprintf(buf2,"%d",i);
    37.         LCD_setCursor(2,1);
    38.         LCD_writeString(buf2);
    39.            
    40.         delay_ms(3000);
    41.         LCD_clr();
    42.            
    43.            OneWire_reset();
    44. }
    45.  
    46. void main()
    47. {  
    48.     char temp_lsb,temp_msb,temp;
    49.    
    50.     char buf3[10];
    51.    
    52.     char getBit[10];
    53.  
    54.     int k;
    55.    
    56.     OSCCON = 0b11110010;    // Set PIC18F4550 internal oscillator at 8MHz
    57.    
    58.     ADCON1 = 0x0F;            // Set all pins as digital I/O
    59.     CMCON = 0x07;             // Set all comparators as digital I/O
    60.    
    61.     LATD = 0;                // Clear port D
    62.     TRISD = 0b00000000;        // Set all port D pins as digital outputs
    63.    
    64.     LATB = 0;
    65.     TRISB = 0x00;
    66.    
    67.     LCD_init();                // Initialize LCD
    68.     OneWire_init();
    69.  
    70.                
    71.     while(1)
    72.     {
    73.              
    74.                if (!OneWire_reset())
    75.                {
    76.                LCD_setCursor(1,1);
    77.             LCD_writeString("Temperature:");
    78.            
    79.             OneWire_writeByte(Skip_ROM);        
    80.             OneWire_writeByte(Convert_temperature);
    81.        
    82.             OneWire_reset();
    83.             delay_ms(750);
    84.            
    85.             OneWire_writeByte(Skip_ROM);
    86.             OneWire_writeByte(Read_scratchpad);
    87.            
    88.             for (k=0;k<9;k++)
    89.                 {
    90.                     getBit[k] = OneWire_readByte();  
    91.                 }
    92.                
    93.             temp_msb = getBit[1];
    94.             temp_lsb = getBit[0];
    95.                            
    96.             temp = (temp_msb << 8) + temp_lsb;
    97.            
    98.             temp = temp >> 4;
    99.            
    100.             sprintf(buf3,"%d",temp);
    101.             LCD_setCursor(2,1);
    102.             LCD_writeString(buf3);
    103.            
    104.             delay_ms(1000);
    105.                }
    106.        }
    107. }
     
  6. dannyf

    Well-Known Member

    Sep 13, 2015
    1,811
    362
    That's a nice temperature. If you don't like it, dial up or down the thermostat.
     
  7. GrafZeppelin

    Thread Starter New Member

    May 3, 2013
    11
    0
    Well it's a hot summer where I am :) And by a problem, I meant it looks like I made a mistake somewhere in the code. If I put a hot cigarette lighter (not lit, just after it was lit for 5 sec), the temperature goes from 11 to 12 and then 13, and when I remove it, value goes from 13 to 11 again. So it means the problem is not with the actual sensor, I'm just really bad at coding :) Any help? Please?
     
Loading...