DS18B20 can not change resolution

Hi,

I have a DS18B20 Temperature Sensor with which I measure changes on an peltier element, but the default Resolution of 12 seems to be too slow to measure the temperature the DS18B20 can not handle temperature changes with a rate of > 1°C/s.

So I wanted to change the Resolution to 9 or 10, but it does not work.

I tried the following code from a tutorial:

    #include <OneWire.h>
     
    #define OUT_PIN 3 // output digital pin
     
    OneWire ds(OUT_PIN); // Connect your 1-wire device to pin "OUT_PIN"
    byte addr[10][8];
    byte device_nb = 0;
     
    void setup(void) {
      Serial.begin(9600);
      SearchDevices(); // search 1-wire devices
     
      // Set configuration
      for( device_nb = 0; device_nb < 10; device_nb++) {  
        if (addr[device_nb][0] == 0x28){
          Serial.print("\r\nScratch Pad before modification: \r\n");
          ReadScratchPad(addr[device_nb]); // display scratchpad
          WriteScratchPad(addr[device_nb], 10); // write scratchpad configuration, ask for a 9, 10, 11 or 12 bits resolution
          Serial.print("\r\nScratch Pad after modification: \r\n");
          ReadScratchPad(addr[device_nb]); // display scratchpad
          Serial.print("\r\n");
        }
      }
    }
     
    void loop(void) {
      // do nothing
    }
     
    void SearchDevices(){
      byte i;
     
      Serial.print("Looking for 1-Wire devices...\n\r");
      while(ds.search(addr[device_nb])) {
        if ( OneWire::crc8( addr[device_nb], 7) != addr[device_nb][7]) {
            Serial.print("CRC is not valid!\n");
          break;
          }
        if (device_nb < 10){
          device_nb++;    
        } else {
          Serial.print("More than 10 devices, unable to load them all\n");
          break;
        }
      }
      ds.reset_search();
     
      if (device_nb < 9){
         addr[device_nb][0] = 0; // erase last 1-wire device as it is accounted 2 times  
      }
     
      for( device_nb = 0; device_nb < 10; device_nb++) {
        if (addr[device_nb][0] == 0x28){
          Serial.print("Device Number ");
          Serial.print(device_nb);
          Serial.print(" : ");
          for( i = 0; i < 8; i++) {    
            Serial.print(addr[device_nb][i], HEX);
            Serial.print(" ");
          }
         Serial.print("\n\r");
        }
      }
    }
     
     
    void ReadScratchPad(byte addr[8]){
      byte data[12];
      byte i;
     
      ds.reset();
      ds.select(addr);    
      ds.write(0xBE);         // Read Scratchpad
     
      for ( i = 0; i < 9; i++) {           // we need 9 bytes
        data[i] = ds.read();
        Serial.print(data[i], HEX);
        Serial.print(" ");
      }
    }
     
    void WriteScratchPad(byte addr[8], byte res_bit){
      byte reg_cmd;
      switch(res_bit){
        case 9: reg_cmd = 0x1F; break;
        case 10: reg_cmd = 0x3F; break;
        case 11: reg_cmd = 0x5F; break;
        case 12: reg_cmd = 0x7F; break;
        default: reg_cmd = 0x7F; break;
      }
     
      ds.reset();
      ds.select(addr);
      ds.write(0x4E);     // Write scratchpad command
      ds.write(0x00);        // TL data
      ds.write(0x00);        // TH data
      ds.write(0x3F);
      //ds.write(reg_cmd);  // Configuration Register (resolution) 7F=12bits 5F=11bits 3F=10bits 1F=9bits
      ds.reset();         // This "reset" sequence is mandatory
      ds.select(addr);    // it allows the DS18B20 to understand the copy scratchpad to EEPROM command
      ds.write(0x48);     // Copy Scratchpad command
    }

But the Scratchpad content does not seem to change, the program prints the following:

Looking for 1-Wire devices...

Device Number 0 : 28 61 64 11 B2 4B 9F 48 


Scratch Pad before modification: 
6D 1 FF FF 7F FF FF FF 6B 
Scratch Pad after modification: 
6D 1 FF FF 7F FF FF FF 6B

What am I doing wrong? I also tried using the DallasTemperature Library to change the resolution, but that did not work as well.

I also tried several different Sensors, but I can not modify the resolution on any of those.

After this command

  ds.write(0x48);     // Copy Scratchpad command

the Dallas library has a delay(20) to allow time for the EEPROM to write the data. Give it a try.

Pete

TitusJonas:
I also tried using the DallasTemperature Library to change the resolution, but that did not work as well.

Maybe you are mixing codes. If you are using the DallasTemperature library in some standard code, like this, I think it just a matter of keeping the names right.

// Assign the unique addresses of your 1-Wire temp sensors.
DeviceAddress insideThermometer = { 0x28, 0x94, 0xE2, 0xDF, 0x02, 0x00, 0x00, 0xFE };

void setup(void)
{
  sensors.begin();
  sensors.setResolution(insideThermometer, 10);
........etc

@OP

After changing the resolution, you are reading the 64-bit ROM/Address Code of the sensor; you don't see any change here; accordingly, you think that the resolution change has not taken place. Actual facts are: This is not correct. Please, see Post#4 @el_supremo

1. 64-Bit ROM/Address Code is always a fixed value for each and every sensor. No two sensors will have the same code.

2. The resolution value is reflected in byte-4 of the Scratchpad Data of the DS18B20 sensor. Therefore, you need to read the Scratchpad memory to see the change. Please see the following figure:

3. Byte-4 of the figure of Step-2 is the Configuration Register which contains the values of the R1-R0 bits that determine the resolution as per following definition:

4. The execution of the following Sketch prints the 64-bit ROM/Address Code and the Resolution of the Sensor.

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 3
OneWire ds(3);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;
byte data[9];  //to hold Scratch Pad data of Ds18B20

void setup(void)
{

  Serial.begin(9600);
  //  Serial.println("Dallas Temperature IC Control Library Demo");
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  //  Serial.print("Parasite power is: ");
  if (sensors.isParasitePowerMode())
  {
    Serial.println("ON");
  }
  else
  {
    ;//   Serial.println("OFF");
  }

  if (!sensors.getAddress(insideThermometer, 0))
  {
    Serial.println("Unable to find address for Device 0");
  }

  // Serial.print("Device 0 Address/64-Bit Fixed ROM Code: ");
  // printAddress(insideThermometer);
  Serial.println();
  sensors.setResolution(insideThermometer, 9); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)

 // Serial.print("Device 0 Resolution: ");
  //Serial.print(sensors.getResolution(insideThermometer), DEC);
 // Serial.println();

  ds.reset();
  ds.select(insideThermometer);//addr2);  //selectimg the desired DS18B20
  ds.write(0xBE);    //Function command to read Scratchpad Memory (9Byte)
  ds.read_bytes(data, 9); //data comes from DS-scratchpad  and are saved into buffer data[8]
 // Serial.print("Configuration Register for Resolution = ");
 // Serial.println(data[4], BIN); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)

  Serial.print("Fixed 64-Bit ROM/Address Code = ");
  printAddress(insideThermometer);

  Serial.print("    : Sensor Resolution = ");
  Serial.print(data[4], HEX); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)
  Serial.print(" (");
  Serial.print(sensors.getResolution(insideThermometer), DEC);
  Serial.println(")");
//  while (1);
}

void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop(void)
{
//  Serial.println("Requesting temperatures...");
  sensors.requestTemperatures();
 // Serial.println("DONE");

  printTemperature(insideThermometer); // Use a simple function to print out the data
  delay(1000);
}

void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

Change the resolution value in the program as 9, 10, 11,, and 12. Re-run the program and observe that the new value has been reflected in the Configuration Register. Also, observe that the 64-bit ROM/Address code has not changed.

After changing the resolution, you are reading the 64-bit ROM/Address Code of the sensor

No he isn't. The code reads and prints the ROM address, reads and prints the scratchpad, writes to the scratchpad and then reads and prints the scratchpad again.

The problem is the missing delay after copying the scratchpad with ds.write(0x48);
The code copies the scratchpad and immediately tries to read the scratchpad. This does not give the device time to write the scratchpad data to the EEPROM. There must be a delay of at least 10ms after issuing the copy scratchpad command and before trying to access the sensor again.

@OP: One thing you might try at the same time is to use 0x20 instead of 0x3F for the resolution. The bottom 5 bits can't be changed anyway so don't bother trying :slight_smile:

Pete

@TitusJonas: I tried your code on a Nano. At first, I couldn't get it to work even with the delay. I meddled with the code a bit and then it started to work. Now I have gone back to your original code without the delay and it also works. I then tried with a different DS18B20 and the original code still works.
Hmmm. Gremlins? :slight_smile:

P.S. I wouldn't count on the code working without the delay after issuing the Copy Scratchpad command. It is required even if it appears to work sometimes without it. Add a delay(20).

Pete

el_supremo:
No he isn't. The code reads and prints the ROM address, reads and prints the scratchpad, writes to the scratchpad and then reads and prints the scratchpad again.

Yes! You are right. The OP was reading/printing Scratchpad Memory. I stand corrected!

TitusJonas:
Scratch Pad before modification:
6D 1 FF FF 7F FF FF FF 6B
Scratch Pad after modification:
6D 1 FF FF 7F FF FF FF 6B

I tried it with the DallasTemperature Library as well, but it didn't work.

Maybe my Temperature sensors are defect or at least their memory is, I'm going to buy a new one and test if with works with that one.

It's really hard to debug hardware and to find where exactly it is, it could be everywhere :confused:

TitusJonas:
It's really hard to debug hardware confuse:

I guess that's true, but the sensors are not that likely to be defective and they are pretty robust. There is a possibilty that they aren't actually DS18B20s. You won't be the first to have that but, if they really look like sensors rather than transistors, they probably are sensors. Your code seems to be unnecessarily complicated, try there.

The sensors are almost certainly DS18B20 because they return a valid-looking ROM code: 28 61 64 11 B2 4B 9F 48.
The contents of the scratchpad also look correct. The only problem is that it doesn't change.

Pete

The following complete codes set the resolution to a desired value (9, 10, 11, 12) and reads it back from the scratchpad. The OP may try it.

Fragment Codes:

sensors.setResolution(insideThermometer, 9); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)

  ds.reset();
  ds.select(insideThermometer);//addr2);  //selectimg the desired DS18B20
  ds.write(0xBE);    //Function command to read Scratchpad Memory (9Byte)
  ds.read_bytes(data, 9); //data comes from DS-scratchpad  and are saved into buffer data[8]

 Serial.print("    : Sensor Resolution = ");
  Serial.print(data[4], HEX); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)
  Serial.print(" (");
  Serial.print(sensors.getResolution(insideThermometer), DEC);
  Serial.println(")");

Complete Codes:

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 3
OneWire ds(3);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;
byte data[9];  //to hold Scratch Pad data of Ds18B20

void setup(void)
{

  Serial.begin(9600);
  //  Serial.println("Dallas Temperature IC Control Library Demo");
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  //  Serial.print("Parasite power is: ");
  if (sensors.isParasitePowerMode())
  {
    Serial.println("ON");
  }
  else
  {
    ;//   Serial.println("OFF");
  }

  if (!sensors.getAddress(insideThermometer, 0))
  {
    Serial.println("Unable to find address for Device 0");
  }

  // Serial.print("Device 0 Address/64-Bit Fixed ROM Code: ");
  // printAddress(insideThermometer);
  Serial.println();
  sensors.setResolution(insideThermometer, 9); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)

 // Serial.print("Device 0 Resolution: ");
  //Serial.print(sensors.getResolution(insideThermometer), DEC);
 // Serial.println();

  ds.reset();
  ds.select(insideThermometer);//addr2);  //selectimg the desired DS18B20
  ds.write(0xBE);    //Function command to read Scratchpad Memory (9Byte)
  ds.read_bytes(data, 9); //data comes from DS-scratchpad  and are saved into buffer data[8]
 // Serial.print("Configuration Register for Resolution = ");
 // Serial.println(data[4], BIN); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)

  Serial.print("Fixed 64-Bit ROM/Address Code = ");
  printAddress(insideThermometer);

  Serial.print("    : Sensor Resolution = ");
  Serial.print(data[4], HEX); // 0 R1 R0 1 1 1 1 1; R1 R0 = 00 (9); 01 (01); 10; 10 (11); 11 (12)
  Serial.print(" (");
  Serial.print(sensors.getResolution(insideThermometer), DEC);
  Serial.println(")");
//  while (1);
}

void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop(void)
{
//  Serial.println("Requesting temperatures...");
  sensors.requestTemperatures();
 // Serial.println("DONE");

  printTemperature(insideThermometer); // Use a simple function to print out the data
  delay(1000);
}

void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

Edit: # added in the 1st line that was absent in the original post.

That doesn't work on a Nano. You've instantiated two OneWire objects on the same pin.
Change this:

OneWire ds(3);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

to this:

OneWire ds(ONE_WIRE_BUS);
DallasTemperature sensors(&ds);

Pete

el_supremo:
That doesn't work on a Nano. You've instantiated two OneWire objects on the same pin.

Interestingly, I have checked the program with NANO now being inspired by your post; it works.

The program works for both UNO and NANO.

I figured out why it didn't work for me. I have the DS18B20 on pin 4 on the Nano. I changed the define of ONE_WIRE_BUS to 4 but didn't change "OneWire ds(3);" to 4. It would still be best to use the fix I suggested do that the pin number is defined in one place. Also, the first line has "include" which should, of course, be "#include".

Pete

I appreciate your observations and comments. It really does not look very good/professional to have redundant definitions --

#define ONE_WIRE_BUS 3
OneWire ds(3);
OneWire oneWire(ONE_WIRE_BUS);

I hope to make an optimum version of my Post#10 so that it may work as a good tutorial.

BTW: # was left behind due to copy/paste process.