DS18B20 - latest include files - cleanest way to implement with Argon / Xenon

xenon
argon
Tags: #<Tag:0x00007fe21f2e5e60> #<Tag:0x00007fe21f2e5460>

#1

I’m developing an application that utilizes multiple DS18B20 digital temp sensors on Argon / Xenon chips and am not sure which #include library is best (or even works). All I need to do is poll these chips periodically and publish the results… I’d like to code to be as clean as possible. For simplicity’s sake each chip will be on a different pin. Thanks in advance!


#2

I use the DS18 library in a similar application with multiple sensors on different GPIO pins. It works okay, but is not always reliable. I retry readings up to 25 times(!) to make sure I get a good one. I’ve looked at the DS18B20 library but haven’t implemented it yet. Not sure if it’s more reliable. Note that both of these libraries default to 12 bit precision and have a hard coded 750ms conversion time. If you don’t need 12 bits of precision you can modify the library and reduce the conversion delay according to the DS18B20 datasheet.


#3

I’ve been using the DS18B20 library. It works, and it is maintained. It is also well suited for a “single drop” configuration like you describe.


#4

@Bear Does the DS18B20 library suffer from the reliability problem that DS18 does?


#5

I have not experienced any reliability problems that I can attribute to the library. To date, I have only worked with the DS18B20 running at 3.3v in parasitic mode. Whether that mode is reliable is up to interpretation.

I run one weather proof sensor outdoors. My original goal was to read that sensor every 30 seconds. To achieve something close to that, my firmware has to read the sensor every 20 seconds and then retry every 2 seconds when errors are detected. About 50% of my reads are successful on the first try. Another 30% are successful within two or three retries. Most of the remaining reads are accomplished within the 30 second window, but I have seen some cases where it takes up to ~20 retries to successfully read the sensor. That makes my worst case somewhere around 60 seconds. I can live with that for this application, but I had hoped for something better.

The errors come in spurts. The sensor will operate optimally for a while, then I’ll some errors, then things will return to optimal. Once in a while, an error cycle will be severe. That makes me suspect an external power or EMF influence may be at play.

I have tested a second DS18B20 indoors. It produced slightly better, but similar results in parasitic mode at 3.3volts. I plan to retest that sensor, powering it with 5v from the USB, and reading the data line at 3.3v through a voltage divider. Perhaps that will be “more reliable”.

By the way, I have worked with both the OneWire/DS18 and DS18B20 librarys. I’d guide you to the DS18 if you were going to string multiple sensors on one pin, and I’d guide you to the DS18B20 sensor for single-drop (one sensor per pin). I think the DS18B20 is somewhat easier to use.

Here is some sample code that I clipped from a demo that I created a while back. The TEMPERATURE VARIABLES were declared as global and temperatureMonitor() was called from Particle loop().

    // TEMPERATURE VARIABLES
    const uint8_t CELSIUS = 1, FAHRENHEIT = 2;
    uint8_t tempScale = FAHRENHEIT;               // <-- select the desired temperature scale here
    DS18B20  ds18b20(DALLAS_ONE_WIRE_PIN, true);





/* --------------------------------------------------------------------------------------------------------------------------------------------------

                                      ##### ##### #   # ####  ##### ####   ###  ##### #   # ####  #####
                                        #   #     ## ## #   # #     #   # #   #   #   #   # #   # #    
                                        #   ###   # # # ####  ###   ####  #####   #   #   # ####  ###
                                        #   #     #   # #     #     # #   #   #   #   #   # # #   #
                                        #   ##### #   # #     ##### #   # #   #   #    ###  #   # #####

 * --------------------------------------------------------------------------------------------------------------------------------------------------
 * --------------------------------------------------------------------------------------------------------------------------------------------------
 *      - Publishes MQTT Messages (JSON strings) under the edison/temp topic
 *          - Message Frequency:    Governed by READ_INTERVAL and RETRY_INTERVAL
 *                                  Messages are only sent when valid data is available
 *          - Message Format:   JSON
 *          - Message contents:
 *              - time: Time.now() 
 *              - fah:  fahrenheit
 * ------------------------------------------------------------------------------------------------------------------------------------------------*/    

 void temperatureMonitor() {
	//static uint8_t outdoor_sensor[8] = {0x28, 0xff, 0x7b, 0x67, 0x70, 0x16, 0x04, 0x8b};  // sensor ID
	static const uint16_t READ_INTERVAL = 30;                      // normal message frequency (in seconds)
	static const uint16_t RETRY_INTERVAL = 5;                      // interval between retries (in seconds)
	static time_t nextReadTime = Time.now() + (RETRY_INTERVAL);    // initial setting schedules the first temperature reading
    static char mqttMessage[64]; 
    static bool mqttMessageReadyToSend = false;     // when true, a mqttMessage is ready to publish
    static float lastValidTemperature;

	if (Time.now() >= (nextReadTime)) {
    	float currentReading = ds18b20.getTemperature();
    	if (ds18b20.crcCheck()) { 
    	    // sensor was read successfully ...
    	    if (tempScale == FAHRENHEIT) {
                lastValidTemperature = ds18b20.convertToFahrenheit(currentReading);
    	    } else { 
    	        lastValidTemperature = currentReading;
    	    }
            // format the temperature message
        	snprintf(mqttMessage, sizeof(mqttMessage),
        	    "{\"time\":%lu, \"fah\":%0.2f}", Time.now(), lastValidTemperature);
            mqttMessageReadyToSend = true;
            // schedule the next reading
        	nextReadTime = (Time.now() + READ_INTERVAL);       
    	} else {    // CRC error ... invalid data
    	    // schedule the next retry
    	    nextReadTime = (Time.now() + RETRY_INTERVAL);
    	}
	}
	
    /*  The following code block is designed to run in each loop() cycle. 
        If a message can not be sent immediatly after it is created, this block will
        keep trying to send it until the message is either sent or overwritten
    */
	if (mqttMessageReadyToSend) { 
        if (mqttSessionActive && mqtt->isConnected()) {
	        bool retain = false;
            mqtt->publish("edison/temp", (const uint8_t*) mqttMessage, strlen(mqttMessage), retain, MQTT::QOS2, NULL);
			Particle.publish("temp", mqttMessage, PRIVATE);
            mqttMessageReadyToSend = false;
        }
	}
	return;
}


/* --------------------------------------------------------------------------------------------------------------------------------------------------

#6

picsil said: “I use the DS18 library in a similar application with multiple sensors on different GPIO pins. It works okay, but is not always reliable. I retry readings up to 25 times(!) to make sure I get a good one. I’ve looked at the DS18B20 library but haven’t implemented it yet. Not sure if it’s more reliable. Note that both of these libraries default to 12 bit precision and have a hard coded 750ms conversion time. If you don’t need 12 bits of precision you can modify the library and reduce the conversion delay according to the DS18B20 datasheet.”

I have been working on a project with the DS18B20 in this thread:

Here are some comments about the libraries.

The DS18 library doesn’t expose a “setResolution” function to change DS18B20 resolution. The DS18B20 library exposes that function, but it might have been taken from a different chip and doesn’t work. As per data sheet, writing a new resolution requires a “Write Scratchpad” command along with 3 bytes which include the new resolution…not what is in that library. Initially, on my project, I thought I wanted to change the resolution. I have since decided against that so this would not have been a show-stopper for me. Because of that, and as you mention, those libraries are currently stuck with a 750ms minimum execution time which is implemented with a delay() function. It really can’t be reduced because there is no way to change the resolution of the DS18B20.

The other two libraries available in the particle.io database are ds18x20 and DS18B20Minimal. I have perused those and my first impression is that they do correctly support changing the resolution. In addition, both of those libraries also separate the “start conversion” function from the “read conversion” function which allows a user to do the conversions in parallel to other operations and not use a delay() function. The user can start a conversion, do other things (waiting at least 750ms for 12-bit resolution), and then read the conversion. I personally like that. On the flip side, however, there no corresponding function to “start and read” a conversion in one swoop as the DS18B20 and DS18 libraries do…and why they require the delay(750ms) function. However, I didn’t use these libraries and there may be other issues associated with them.

I started out my project trying to use the DS18B20 and DS18 libraries but had issues and so ended up simplifying and extracting the two functions I really needed from them: 1) start conversion, 2) read conversion. I also extracted a 3) setResolution function but ending up dropping that from my code because there was no need to do faster conversion in my application…but it did work.