This is article 7 of 8 in a series about robust DS18B20 / 1-Wire system design.
Please see the introductory topic:
Introduction
Based on comments from gfvalvo and robtillaart in the discussion of that article
"DS18B20 Optical Feedback – Visualizing Conversion Time with an LED"
(special thanks for the inspiration
), I decided to run a few simple performance tests that anyone can easily reproduce.
The question raised in that discussion was essentially about how efficiently temperature values are obtained from a DS18B20 and whether using the “get by index” functions is a good idea when only one sensor is connected to the bus.
Two points were mentioned:
- retrieving a sensor by index may internally require a bus scan
- retrieving it by address avoids this step
Rather than speculating, it seemed useful to simply measure the timing of different approaches.
The following four small test programs compare:
- Blocking mode using the DallasTemperature library
- Non-blocking mode using the DallasTemperature library
- Direct OneWire bus access without the DallasTemperature abstraction
- Non-blocking MCU busy time (time required to start and read a measurement)
All tests were run on a typical Arduino Uno setup with a single DS18B20 connected to pin 2.
Each measurement is executed 10 times, and the minimum, maximum and average time are reported.
Test 1
Blocking Mode Time Requirement
This first test uses the DallasTemperature library in blocking mode.
The sensor conversion is completed before the timing measurement begins, so only the temperature read operation itself is measured.
Two methods are compared:
getTempCByIndex(0)getTempC(sensorAddress)
The sensor address is retrieved once in setup() and then reused.
Code
/*
DS18B20 Read Method Comparison
--------------------------------
Test 1: Blocking Mode Time Requirement
Purpose
-------
Measure the execution time of two DallasTemperature read methods:
1) getTempCByIndex()
2) getTempC(address)
Conditions
----------
- Blocking mode (waitForConversion = true)
- Sensor resolution: 12 bit
- Conversion finished before timing starts
- Only the read operation is measured
*/
#include <OneWire.h>
#include <DallasTemperature.h>
constexpr uint8_t busPin = 2;
constexpr uint8_t samples = 10;
OneWire oneWire(busPin);
DallasTemperature sensors(&oneWire);
DeviceAddress sensorAddress;
unsigned long timeIndex[samples];
unsigned long timeAddress[samples];
void setup()
{
Serial.begin(115200);
Serial.println("DS18B20 Blocking Mode Time Requirement");
sensors.begin();
sensors.setWaitForConversion(true);
if (!sensors.getAddress(sensorAddress, 0))
{
Serial.println("Sensor not found");
while (true);
}
sensors.setResolution(sensorAddress, 12);
sensors.requestTemperatures();
delay(750);
Serial.println("Starting measurements...\n");
for (uint8_t i = 0; i < samples; i++)
{
unsigned long t1;
unsigned long t2;
t1 = micros();
sensors.getTempCByIndex(0);
t2 = micros();
timeIndex[i] = t2 - t1;
t1 = micros();
sensors.getTempC(sensorAddress);
t2 = micros();
timeAddress[i] = t2 - t1;
}
printResults("getTempCByIndex()", timeIndex);
printResults("getTempC(address)", timeAddress);
}
void loop()
{
}
void printResults(const char *label, unsigned long data[])
{
unsigned long minVal = data[0];
unsigned long maxVal = data[0];
unsigned long sum = 0;
for (uint8_t i = 0; i < samples; i++)
{
if (data[i] < minVal) minVal = data[i];
if (data[i] > maxVal) maxVal = data[i];
sum += data[i];
}
float avg = sum / (float)samples;
Serial.println(label);
Serial.print("Min: "); Serial.print(minVal); Serial.println(" us");
Serial.print("Max: "); Serial.print(maxVal); Serial.println(" us");
Serial.print("Avg: "); Serial.print(avg); Serial.println(" us");
Serial.println();
}
Result
getTempCByIndex()
Min: 26848 us
Max: 27028 us
Avg: 26869.20 us
getTempC(address)
Min: 12348 us
Max: 12356 us
Avg: 12350.40 us
Test 2
Non-Blocking Mode Time Requirement
The second test repeats the comparison but uses non-blocking mode.
Here the conversion time is handled explicitly using
millisToWaitForConversion().
Again, the timing measurement only covers the temperature read call itself, not the conversion phase.
Code
/*
DS18B20 Read Method Comparison
--------------------------------
Test 2: Non-Blocking Mode Time Requirement
Purpose
-------
Measure the execution time of two DallasTemperature read methods
in NON-BLOCKING mode:
1) getTempCByIndex()
2) getTempC(address)
Conditions
----------
- waitForConversion = false
- Sensor resolution: 12 bit
- Conversion wait handled manually using millisToWaitForConversion()
- Only the read operation itself is measured
Method
------
Each method is measured 10 times.
The program outputs:
- Minimum time
- Maximum time
- Average time
Hardware
--------
Arduino Uno
DS18B20 connected to pin 2
Note
----
Temperature conversion is started with requestTemperatures()
and the program waits explicitly for the required conversion
time before performing the timed read operation.
*/
#include <OneWire.h>
#include <DallasTemperature.h>
constexpr uint8_t busPin = 2;
constexpr uint8_t samples = 10;
OneWire oneWire(busPin);
DallasTemperature sensors(&oneWire);
DeviceAddress sensorAddress;
uint32_t waitTime;
unsigned long timeIndex[samples];
unsigned long timeAddress[samples];
void setup()
{
Serial.begin(115200);
Serial.println("DS18B20 Non-Blocking Mode Time Requirement");
sensors.setWaitForConversion(false);
sensors.begin();
if (!sensors.getAddress(sensorAddress, 0))
{
Serial.println("Sensor not found");
while (true);
}
sensors.setResolution(sensorAddress, 12);
waitTime = sensors.millisToWaitForConversion(sensors.getResolution());
Serial.println("Starting measurements...\n");
for (uint8_t i = 0; i < samples; i++)
{
unsigned long t1;
unsigned long t2;
sensors.requestTemperatures();
delay(waitTime);
t1 = micros();
sensors.getTempCByIndex(0);
t2 = micros();
timeIndex[i] = t2 - t1;
t1 = micros();
sensors.getTempC(sensorAddress);
t2 = micros();
timeAddress[i] = t2 - t1;
}
printResults("getTempCByIndex()", timeIndex);
printResults("getTempC(address)", timeAddress);
}
void loop()
{
}
void printResults(const char *label, unsigned long data[])
{
unsigned long minVal = data[0];
unsigned long maxVal = data[0];
unsigned long sum = 0;
for (uint8_t i = 0; i < samples; i++)
{
if (data[i] < minVal) minVal = data[i];
if (data[i] > maxVal) maxVal = data[i];
sum += data[i];
}
float avg = sum / (float)samples;
Serial.println(label);
Serial.print("Min: "); Serial.print(minVal); Serial.println(" us");
Serial.print("Max: "); Serial.print(maxVal); Serial.println(" us");
Serial.print("Avg: "); Serial.print(avg); Serial.println(" us");
Serial.println();
}
Result
getTempCByIndex()
Min: 26848 us
Max: 26856 us
Avg: 26850.40 us
getTempC(address)
Min: 12348 us
Max: 12356 us
Avg: 12350.80 us
Test 3
OneWire Level Time Requirement
The final test removes the DallasTemperature library entirely and reads the sensor directly on the OneWire protocol level.
The following sequence is timed:
- bus reset
- ROM select
- scratchpad read (9 bytes)
This provides a reference for the pure bus-level transaction time.
Code
/*
DS18B20 Read Method Comparison
--------------------------------
Test 3: OneWire Level Time Requirement
Purpose
-------
Measure the execution time of a DS18B20 temperature read
performed directly on the OneWire bus without using the
DallasTemperature library.
Sequence measured
-----------------
- OneWire reset
- ROM select
- READ SCRATCHPAD command
- Reading 9 scratchpad bytes
Conditions
----------
- Sensor resolution: 12 bit
- Conversion completed before timing starts
- Only the OneWire communication is measured
Method
------
Measurement repeated 10 times.
The program outputs:
- Minimum time
- Maximum time
- Average time
Hardware
--------
Arduino Uno
DS18B20 connected to pin 2
Note
----
This test measures the raw OneWire transaction time
required to read the sensor scratchpad. It represents
the lowest-level access used by higher-level libraries.
*/
#include <OneWire.h>
constexpr uint8_t busPin = 2;
constexpr uint8_t samples = 10;
OneWire oneWire(busPin);
byte sensorAddress[8];
byte scratchpad[9];
unsigned long timeBus[samples];
void setup()
{
Serial.begin(115200);
Serial.println("DS18B20 OneWire Level Time Requirement");
if (!oneWire.search(sensorAddress))
{
Serial.println("Sensor not found");
while (true);
}
oneWire.reset_search();
Serial.println("Starting measurements...\n");
startConversion();
delay(750);
for (uint8_t i = 0; i < samples; i++)
{
unsigned long t1;
unsigned long t2;
t1 = micros();
oneWire.reset();
oneWire.select(sensorAddress);
oneWire.write(0xBE);
for (uint8_t j = 0; j < 9; j++)
{
scratchpad[j] = oneWire.read();
}
t2 = micros();
timeBus[i] = t2 - t1;
}
printResults("OneWire scratchpad read", timeBus);
}
void loop()
{
}
void startConversion()
{
oneWire.reset();
oneWire.select(sensorAddress);
oneWire.write(0x44);
}
void printResults(const char *label, unsigned long data[])
{
unsigned long minVal = data[0];
unsigned long maxVal = data[0];
unsigned long sum = 0;
for (uint8_t i = 0; i < samples; i++)
{
if (data[i] < minVal) minVal = data[i];
if (data[i] > maxVal) maxVal = data[i];
sum += data[i];
}
float avg = sum / (float)samples;
Serial.println(label);
Serial.print("Min: "); Serial.print(minVal); Serial.println(" us");
Serial.print("Max: "); Serial.print(maxVal); Serial.println(" us");
Serial.print("Avg: "); Serial.print(avg); Serial.println(" us");
Serial.println();
}
Result
OneWire scratchpad read
Min: 11284 us
Max: 11284 us
Avg: 11284.00 us
Test 4
Non-Blocking MCU Busy Time
The fourth test looks at a slightly different aspect of the non-blocking approach: how long the microcontroller is actually busy when interacting with the sensor.
Instead of measuring only the read operation, this test measures three parts separately:
requestTemperatures()– time required to start the measurementgetTempC(address)– time required to read the result- Total MCU busy time – start + read
During the sensor’s internal conversion (~750 ms at 12-bit resolution) the DS18B20 works autonomously and the MCU is free to perform other tasks. This additional measurement was included as suggested by robtillaart, to illustrate how much processor time is actually occupied versus how much time remains available for parallel work.
Code
/*
DS18B20 Read Method Comparison
--------------------------------
Test 4: Non-Blocking MCU Busy Time
Purpose
-------
Measure how long the MCU is actually busy when using the
DS18B20 in non-blocking mode.
The following operations are timed separately:
1) requestTemperatures() -> start conversion
2) getTempC(address) -> read temperature
3) total MCU busy time
Conditions
----------
- waitForConversion = false
- Sensor resolution: 12 bit
- Conversion time handled manually
- Only MCU execution time is measured
Method
------
Measurement repeated 10 times.
The program outputs:
- Minimum time
- Maximum time
- Average time
Hardware
--------
Arduino Uno
DS18B20 connected to pin 2
Note
----
During the sensor conversion (~750 ms at 12-bit resolution)
the DS18B20 performs the measurement internally. The MCU
can execute other tasks during this period.
*/
#include <OneWire.h>
#include <DallasTemperature.h>
constexpr uint8_t busPin = 2;
constexpr uint8_t samples = 10;
OneWire oneWire(busPin);
DallasTemperature sensors(&oneWire);
DeviceAddress sensorAddress;
uint32_t waitTime;
unsigned long timeRequest[samples];
unsigned long timeRead[samples];
unsigned long timeTotal[samples];
void setup()
{
Serial.begin(115200);
Serial.println("DS18B20 Non-Blocking MCU Busy Time");
sensors.setWaitForConversion(false);
sensors.begin();
if (!sensors.getAddress(sensorAddress, 0))
{
Serial.println("Sensor not found");
while (true);
}
sensors.setResolution(sensorAddress, 12);
waitTime = sensors.millisToWaitForConversion(sensors.getResolution());
Serial.println("Starting measurements...\n");
for (uint8_t i = 0; i < samples; i++)
{
unsigned long t1;
unsigned long t2;
// measure start of conversion
t1 = micros();
sensors.requestTemperatures();
t2 = micros();
timeRequest[i] = t2 - t1;
// wait for sensor conversion (MCU free)
delay(waitTime);
// measure read operation
t1 = micros();
sensors.getTempC(sensorAddress);
t2 = micros();
timeRead[i] = t2 - t1;
// total MCU busy time
timeTotal[i] = timeRequest[i] + timeRead[i];
}
printResults("requestTemperatures()", timeRequest);
printResults("getTempC(address)", timeRead);
printResults("Total MCU busy time", timeTotal);
}
void loop()
{
}
void printResults(const char *label, unsigned long data[])
{
unsigned long minVal = data[0];
unsigned long maxVal = data[0];
unsigned long sum = 0;
for (uint8_t i = 0; i < samples; i++)
{
if (data[i] < minVal) minVal = data[i];
if (data[i] > maxVal) maxVal = data[i];
sum += data[i];
}
float avg = sum / (float)samples;
Serial.println(label);
Serial.print("Min: "); Serial.print(minVal); Serial.println(" us");
Serial.print("Max: "); Serial.print(maxVal); Serial.println(" us");
Serial.print("Avg: "); Serial.print(avg); Serial.println(" us");
Serial.println();
}
Result
requestTemperatures()
Min: 2088 us
Max: 2272 us
Avg: 2108.00 us
getTempC(address)
Min: 12344 us
Max: 12344 us
Avg: 12344.00 us
Total MCU busy time
Min: 14432 us
Max: 14616 us
Avg: 14452.00 us
Preliminary Conclusion
Even with this very simple setup, the measurements already show a few interesting points:
- Direct addressing is noticeably faster than reading by index.
- Blocking vs. non-blocking mode does not significantly affect the read time itself.
- The raw OneWire transaction is faster than the full DallasTemperature call stack.
- In non-blocking mode the MCU is actually busy only for a very small fraction of the total sensor cycle; most of the time is spent inside the sensor’s internal conversion process.
Exactly how much this matters in a real application probably depends on the specific design goals. In many projects the difference may be negligible, while in others (for example when reading many sensors or operating on tight timing budgets) it could become relevant.
Either way, these small tests might provide a useful starting point for further discussion — and of course I’d be interested to see results from other setups as well.