milesburton / Arduino-Temperature-Control-Library

Arduino Temperature Library
https://www.milesburton.com/w/index.php/Dallas_Temperature_Control_Library
958 stars 486 forks source link

Using a logic analyzer to analyze the runtime sequence routines #252

Open mayjack0312 opened 2 weeks ago

mayjack0312 commented 2 weeks ago

I want to use a logic analyzer to measure the relevant timing parameters:

  1. The time to initialize the DS18B20 and monitor the online information
  2. The time to wait for the DS18B20 to release the bus
  3. The time to trigger the temperature conversion
  4. The time to send the read data command
  5. The time to read the register value and obtain the temperature value

According to the datasheet, their units should be in microseconds (us), but my actual measurements are in milliseconds (ms). How should I modify my measurement method? Here is my code:

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

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

DeviceAddress DS18B20_ID;

void setup() {
  Serial.begin(9600);

  unsigned long initStartTime = micros();

  sensors.begin();

  unsigned long initEndTime = micros();

  Serial.print("Initialization Time: ");
  Serial.print(initEndTime - initStartTime);
  Serial.println(" us");
}

void loop() {
  if (Serial.available() > 0) {
    String command = Serial.readStringUntil('\n');
    command.trim();

    if (command == "GET") {
      unsigned long waitStartTime = micros();

      delayMicroseconds(550);

      unsigned long waitEndTime = micros();

      unsigned long convStartTime = micros();

      sensors.requestTemperatures();

      unsigned long convEndTime = micros();

      unsigned long readCmdStartTime = micros();

      float temperature = sensors.getTempCByIndex(0);

      unsigned long readCmdEndTime = micros();

      unsigned long readRegStartTime = micros();

      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" C");

      unsigned long readRegEndTime = micros();

      Serial.print("Wait for Bus Release Time: ");
      Serial.print(waitEndTime - waitStartTime);
      Serial.println(" us");

      Serial.print("Trigger Conversion Time: ");
      Serial.print(convEndTime - convStartTime);
      Serial.println(" us");

      Serial.print("Send Read Command Time: ");
      Serial.print(readCmdEndTime - readCmdStartTime);
      Serial.println(" us");

      Serial.print("Read Register Value Time: ");
      Serial.print(readRegEndTime - readRegStartTime);
      Serial.println(" us");
    } else {
      Serial.println("Unknown command.");
    }
  }
}
f770f4ff34d1b538ee5ee64843ae5db
RobTillaart commented 2 weeks ago

Two tips.

Flush serial before measurements Do all your measurements before printing the results

mayjack0312 commented 2 weeks ago

Two tips.

Flush serial before measurements Do all your measurements before printing the results

I tried both methods, but neither seems to work for me.

image

image

RobTillaart commented 2 weeks ago

According to the datasheet, their units should be in microseconds (us), but my actual measurements are in milliseconds (ms). How should I modify my measurement method?

Your code does measure in microseconds.


I tried both methods, but neither seems to work for me.

What is wrong with the numbers? Are they different than you expect? If so, what numbers do you expect?

Think you should read the datasheet carefully as it does mentions variation on the numbers. E.g. the conversion time for 12 bit is max 750 ms which is based upon the worst case conversion (and maybe even a bit extra).


I slightly modified your code, as you do not take into account that printing variables and strings takes time and these affect your measurements. The code below is a bit more stable as it adds delays to wait until the serial output buffer is empty.

Note that there are always variations per call, so you might need to execute your tests 100 times and take the average.

Furthermore you need to know that micro() has a resolution of 4 us. So it will never return 550. (and it will add the overhead of the function call).

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

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

DeviceAddress DS18B20_ID;

void setup() 
{
  Serial.begin(9600);
  while(!Serial);  //  wait until Serial device is ready.
  Serial.println(__FILE__);
  delay(100);  //  wait until output buffer of Serial is empty.

  unsigned long initStartTime = micros();

  sensors.begin();
  sensors.setResolution(12);  //  force an explicit resolution, 9..12

  unsigned long initEndTime = micros();

  Serial.print("Initialization Time: ");
  Serial.print(initEndTime - initStartTime);
  Serial.println(" us");
  delay(100);  //  wait until output buffer of Serial is empty.
}

void loop() 
{
  if (Serial.available() > 0) 
  {
    String command = Serial.readStringUntil('\n');
    command.trim();
    if (command == "GET") 
    {
      delay(100);  //  wait for Serial output empty.

      //  why measure this?
      unsigned long waitStartTime = micros();
      delayMicroseconds(550);
      unsigned long waitEndTime = micros();

      unsigned long convStartTime = micros();
      sensors.requestTemperatures();
      unsigned long convEndTime = micros();

      unsigned long readCmdStartTime = micros();
      float temperature = sensors.getTempCByIndex(0);
      unsigned long readCmdEndTime = micros();

      //  here you measure the time to put the strings
      //  in the serial output buffer. not the print time.
      unsigned long readRegStartTime = micros();
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" C");
      unsigned long readRegEndTime = micros();

      Serial.print("Wait for Bus Release Time: ");
      Serial.print(waitEndTime - waitStartTime);
      Serial.println(" us");

      Serial.print("Trigger Conversion Time: ");
      Serial.print(convEndTime - convStartTime);
      Serial.println(" us");

      Serial.print("Send Read Command Time: ");
      Serial.print(readCmdEndTime - readCmdStartTime);
      Serial.println(" us");

      Serial.print("Read Register Value Time: ");
      Serial.print(readRegEndTime - readRegStartTime);
      Serial.println(" us");
    } else {
      Serial.println("Unknown command.");
    }
  }
  delay(1000); // wait for all output to be done 
}
mayjack0312 commented 2 weeks ago

According to the datasheet, their units should be in microseconds (us), but my actual measurements are in milliseconds (ms). How should I modify my measurement method?

Your code does measure in microseconds.

I tried both methods, but neither seems to work for me.

What is wrong with the numbers? Are they different than you expect? If so, what numbers do you expect?

Think you should read the datasheet carefully as it does mentions variation on the numbers. E.g. the conversion time for 12 bit is max 750 ms which is based upon the worst case conversion (and maybe even a bit extra).

I slightly modified your code, as you do not take into account that printing variables and strings takes time and these affect your measurements. The code below is a bit more stable as it adds delays to wait until the serial output buffer is empty.

Note that there are always variations per call, so you might need to execute your tests 100 times and take the average.

Furthermore you need to know that micro() has a resolution of 4 us. So it will never return 550. (and it will add the overhead of the function call).

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

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

DeviceAddress DS18B20_ID;

void setup() 
{
  Serial.begin(9600);
  while(!Serial);  //  wait until Serial device is ready.
  Serial.println(__FILE__);
  delay(100);  //  wait until output buffer of Serial is empty.

  unsigned long initStartTime = micros();

  sensors.begin();
  sensors.setResolution(12);  //  force an explicit resolution, 9..12

  unsigned long initEndTime = micros();

  Serial.print("Initialization Time: ");
  Serial.print(initEndTime - initStartTime);
  Serial.println(" us");
  delay(100);  //  wait until output buffer of Serial is empty.
}

void loop() 
{
  if (Serial.available() > 0) 
  {
    String command = Serial.readStringUntil('\n');
    command.trim();
    if (command == "GET") 
    {
      delay(100);  //  wait for Serial output empty.

      //  why measure this?
      unsigned long waitStartTime = micros();
      delayMicroseconds(550);
      unsigned long waitEndTime = micros();

      unsigned long convStartTime = micros();
      sensors.requestTemperatures();
      unsigned long convEndTime = micros();

      unsigned long readCmdStartTime = micros();
      float temperature = sensors.getTempCByIndex(0);
      unsigned long readCmdEndTime = micros();

      //  here you measure the time to put the strings
      //  in the serial output buffer. not the print time.
      unsigned long readRegStartTime = micros();
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" C");
      unsigned long readRegEndTime = micros();

      Serial.print("Wait for Bus Release Time: ");
      Serial.print(waitEndTime - waitStartTime);
      Serial.println(" us");

      Serial.print("Trigger Conversion Time: ");
      Serial.print(convEndTime - convStartTime);
      Serial.println(" us");

      Serial.print("Send Read Command Time: ");
      Serial.print(readCmdEndTime - readCmdStartTime);
      Serial.println(" us");

      Serial.print("Read Register Value Time: ");
      Serial.print(readRegEndTime - readRegStartTime);
      Serial.println(" us");
    } else {
      Serial.println("Unknown command.");
    }
  }
  delay(1000); // wait for all output to be done 
}

Oh, thank you so much! After reading your reply, I realized that my consideration was indeed not very comprehensive. Below is the table representing the results I expect to achieve:

data time (us)
The time to initialize the DS18B20 and monitor the online information 610
The time to wait for the DS18B20 to release the bus 550
The time to trigger the temperature conversion 887
The time to send the read data command 886
The time to read the register value and obtain the temperature value 560