logo elektroda
logo elektroda
X
logo elektroda

Extending DS18(B)20 driver - multiple GPIOs and multiple sensors per GPIO

max4elektroda 117 1
ADVERTISEMENT
  • Screenshot of the DS18B20 driver configurator showing a list of detected temperature sensors and their settings.
    As proposed by @p.kaczmarek2 I'll try to share some ideas for my OpenBeken IoT firmware extensions and features here, starting, "as requested" ;-) with the extended DS18(B)20 driver.

    The code is in PR #1627

    I'll start with some information and screenshots, but I would be glad to get some feedback on more basic questions in the later part of this post.

    So, "only" getting the already present driver (/src/driver/ds18b20.c) working wasn't that hard, the most crucial part (timing of the OneWire protocol) was done and improved with many support from others for the "simple" driver. So there only was the driver layer missing, the protocol was working quite good now.

    So the first approach was:
    Move all basic functions into a separate file, so all the basic "one_wire" or "ds18b2" functions (up to read/write a byte) could be shared between the two drivers.

    A bit more challenging were some general decisions: How to handle the sensors?

    A brief excursion:

    All sensors have a unique address that allows them to be addressed on the bus, making it possible to distinguish multiple devices on this bus. The simple driver takes the easy route ;-) It exclusively uses the option, similar to a broadcast in a network, to address "all" devices.

    To read the temperature, the procedure here is: "All devices: Prepare for temperature reading" and then "All devices: Write temperature" – and "all devices" refer to the one sensor on that pin.

    This approach does not work with multiple sensors, at least for reading: If several sensors report their temperature simultaneously, it goes awry.

    Therefore, the addresses of the sensors must be queried individually: "All devices: Prepare for temperature reading" and then "Sensor A: Write temperature," "Sensor B: Write temperature," and so on.


    The driver must first know the addresses of the devices (the sensors). To achieve this, the driver has the ability to determine all sensor addresses using a clever algorithm (for those interested, you can check out https://www.analog.com/en/resources/app-notes/1wire-search-algorithm.html ).

    I have use the following data structure:

     typedef uint8_t DeviceAddress[8]; // wir müssen die Sensoren anhand ihrer Adresse unterscheiden
    
    typedef struct {
      DeviceAddress array[DS18B20MAX];      // unique address of the sensor
      uint8_t index;                        // an index ;-)
      char name[DS18B20MAX][DS18B20namel];  // a description/name for this sensor
      float lasttemp[DS18B20MAX];           // the last temperature read by this sensor
      unsigned short last_read[DS18B20MAX]; // keep track of when the sensor was last read successfully 
      short channel[DS18B20MAX];            // possibly set channel to this temperature value
      short GPIO[DS18B20MAX];               // on which pin is the sensor?
    
    } DS1820devices;
    


    This also clarifies which features the driver should have, in my opinion:
    - For a single sensor, it doesn't matter, but with multiple sensors, it's worth considering: The sensors should be able to have a "name" assigned, as it's easier for us humans to associate "Kitchen" or "Bedroom" than "28-FF-3C-01-12-34-56-78" or "28-7B-9C-01-23-45-67-89."
    - All information that I previously had only for the entire system is now needed per sensor:
    - On which pin should it be searched for?
     - When did this sensor last respond?
    - Which channel should be used for the temperature?


    So, how does it look like?

    This is the main page after starting the driver with 10 (not configured) DS18B20 clones:
    DS18B20 driver configuration screen showing a list of detected temperature sensors.

    Maybe you want an idea of how my setup looks like? I made a small "testing breadboard" that will provide two "buses" with 7 and 3 sensors, and one "single" sensor. The 7 and single sensors are meant to be used exclusively; they share the 4.7kΩ resistor (thanks to git user "rpv-tomsk" - see PR PR #1579 - using "HAL_PIN_Setup_Input_Pullup" it might also work without an external pullup).

    Screenshot of the DS18B20 driver configurator showing a list of detected temperature sensors and their settings.

    Now, to configure the sensors, you might use the commands of the driver:

    Obviously you start with

    startDriver DS1820 [seconds between temperature readings]
    start the driver, optional set the interval for reading the sensors, defaults to 15 seconds
    (also present in "simple mode")

    The driver will scan all pins configured as "DS1820_IO" to find the addresses of all sensors.
    You can then configure the sensors with the following commands:

    DS18B20_setsensor <address> <GPIO> <name> [channel]
    Configure sensor address, sensor name and (optional) a channel
    examlpes:
    
          DS18B20_setsensor "0x28 0x01 0x02 0x03 0x04 0x05 0x06 0x07" "5" "kitchen"
          DS18B20_setsensor "0x28 0x02 0x03 0x04 0x05 0x06 0x07 0x08" 5 "bedroom" 3
          DS18B20_setsensor "0x28 0x03 0x04 0x05 0x06 0x07 0x08 0x09" PB21 "my room" 3
    

    If sensor address is "known" (the sensor was found on (initial) scan) pin, name and channel are set/updated
    If sensor is not allready in the list, it will be added, along with pin, name and channel

    This means, we could use the driver even without the (complex) scaning of the bus - it's quite a large function and in best case only needed once: to identify the sensors on the first start.
    Later the addresses are known and could be set directly.


    DS1820_SetResolution <bits> [<sensor address>]
    set the temperature resolution of one / all sensors (if optional address is not present)
    (also present in "simple mode" - only argument is resolution there)
    examples:
     
         DS1820_SetResolution 9 "0x28 0x01 0x02 0x03 0x04 0x05 0x06 0x07"
         DS1820_SetResolution 9
    


    Important note: for the majority of my (clone) DS18B20 setting the resolution doesn't work, they will alway use 12 bit resolution!

    DS18B20_scansensors
    Clears all data and scans all busses for attached sensors.
    If you added a sensor or not all sensors have been detected, you can start over with a new scan.
    Drawback: you will lose all configured data - but thanks to "setsensor" you can easily add them later again.



    Since I like it easy, I also added a simple configuration page to do all the settings:

    Screenshot of the DS18B20 driver UI showing a list of detected temperature sensors with names, addresses, pins, and assigned channels.

    Screenshot of the graphical interface for configuring DS18B20 sensors, showing addresses, names, and assigned channels.

    It also allows to generate a "backlog command" of all the configuration. This way, you can easily copy and paste this to autoexec or as a startup command and preserve the settings over a reboot. In my case, the resulting command is:
    
    backlog startDriver DS1820 ; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xD5 0xB0 0x35 0x82"  10 "Kitchen door" 10; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xD5 0xB1 0xB1 0xAB"  10 "Kitchen window" 11; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xD5 0xC3 0xB2 0x6E"  10 "Master Bedroom" 12; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xFB 0xD1 0x06 0x20"  10 "Livingroom " 13; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xFB 0xBD 0x67 0x0C"  10 "Adams room" 14; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xFB 0xAF 0x75 0x50"  10 "Eves room" 15; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xFB 0xBF 0x27 0xDB"  10 "Garage" 16; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xD4 0x7D 0xC4 0x3E"  37 "Pool" 17; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xD4 0x1F 0x6D 0xC6"  37 "Cellar" 18; DS18B20_setsensor "0x28 0x61 0x64 0x35 0xD5 0xEF 0x00 0x6C"  37 "Garden" 19
    


    The main page will reflect the changes:

    Screenshot of the DS18B20 driver configuration page showing a list of 10 temperature sensors with names, addresses, and assigned channels.
    you can see the description per sensor and the channels are updated.


    So, I hope this gives a first idea on what I did and how to use the driver.

    You might have noted, the driver is called "DS1820", the commands "DS18B20_XXX" - this is due to the fact that I started with a alternate "full" driver addittionaly to the simple driver (moving some of the simple drivers code to a shared code file).
    rpv-tomsk proposed to use only one file, so I integrated all into one file where a "#define DS1820full 1" will select the full code.

    So, here is my first question to the other developers and supporters: What do you think is "better":

    Having only one code file with "#defines" to select the features?
    + changes made are always made for both versions
    + no need for a separate "ds1820 protocol" file for shared code
    - many "#defines" sometimes make it hard to read the code, might lead to mistakes

    Leaving/switching back to three files: simple, full and shared code?
    + much easier to read, no need to have several "#defines" inside the functions
    - if changes are made, we need to touch two files (if it's in some common code)
    (it's +/- if we also need to change it in two places in one file, if it's inside "#defines")

    Then the big question at the end - do we need this at all?
    Are there many users "waiting" to attach a number of sensors?

    Yes, I made all the afford for this, but there could also be a small solution: Multiple sensors, but with multiple GPIOs, one sensor per pin. No need to struggle with addresses, just looping through all pins with role "DS1820_IO". The channel is already set (together with the pin) and I know that sensor on pin 18 is in the kitchen and the one on pin 21 in the living room.


    So, feel free to give comments in every direction

    Added after 14 [minutes]:

    For a W800, the additional size (simple to full) is about 6k - we have the complex scanning but especially the "nice" configuration GUI will blow the image.

    Cool? Ranking DIY
    About Author
    max4elektroda
    Level 20  
    Offline 
    max4elektroda wrote 435 posts with rating 101, helped 19 times. Been with us since 2024 year.
  • ADVERTISEMENT
  • #2 21585831
    p.kaczmarek2
    Moderator Smart Home
    Thank you for this interesting presentation. The UI idea and naming is very nice, altough I would consider doing it in Web App. Still, since it's already ready...
    My suggestion is to merge it now as-is, but keep it enabled only in OBK-Sensors:
    Extending DS18(B)20 driver - multiple GPIOs and multiple sensors per GPIO

    I prefer single file with #ifdef , it's easier to read and maintain...

    The command generator is nice, but I think newer OBK does not require backlog, you can put each command in next line.
    Helpful post? Buy me a coffee.
ADVERTISEMENT