Need help using multiple ds18b20's, need to grab addresses to define sensor pos.

Hello all, so I'm a little stuck on this one, possibly due to lack of sleep, but I'm working on something that basically needs to know the sensor position to work properly.

Basically in the setup loop I have it run a search for the sensor address of what is connected, that's fine and dandy and it prints to serial just fine, however I can't get the sensor address to print to the LCD, granted that's not critical, but when I change serial.print to lcd.print it prints out zeros instead.

The main issue is that I want to grab the first sensor address, and set it as "sensor 1", then prompt to plug in the second sensor and set it's address as "sensor 2", that way I can have the separate readings and if the sensors get mixed up, or I have to replace one, it will go through the routine of plugging them in order when it boots.

Here's the code I have so far though doubt it will be much help, mostly looking for someone who has done this before to share their method.

I'm thinking I'll need bytes for addr1, addr2 etc, but the implementation is eluding me at the moment.

#include <Wire.h>
#include <OneWire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>  // F Malpartida's NewLiquidCrystal library
#include <Servo.h>

//------------------------------------------------------------------------------------ HW Info
//Pin 2 = Relay 1 (right), blue wire
//Pin 3 = Relay 2 (left), green wire
//pin 4 =  servo motor, yellow wire
//pin 5 = onewire bus, orang wire
//pin 6= NC, brown wire
//------------------------------------------------------------------------------------ End HW Info

//------------------------------------------------------------------------------------ LCD Setup
#define I2C_ADDR    0x20  // Define I2C Address for the PCF8574A
#define BACKLIGHT_PIN  7
#define En_pin  4
#define Rw_pin  5
#define Rs_pin  6
#define D4_pin  0
#define D5_pin  1
#define D6_pin  2
#define D7_pin  3

#define  LED_OFF  0
#define  LED_ON  1

LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
//------------------------------------------------------------------------------------ End Of LCD Setup

//------------------------------------------------------------------------------------ One Wire Setup

OneWire  ds(5);   
byte i;  
byte present = 0;
byte type_s;
byte data[12];
byte data2[12];
byte addr[8];
byte addr2[8];
//------------------------------------------------------------------------------------ End Of One Wire Setup


Servo myservo;

int relay1 = 2;
int relay2 = 3;


void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  digitalWrite(relay1, HIGH);
  digitalWrite(relay2, HIGH);
  myservo.attach(4);
  myservo.write(0);

 lcd.begin (16,2);  // initialize the lcd
// Switch on the backlight
 lcd.clear();
 lcd.setBacklightPin(BACKLIGHT_PIN,NEGATIVE);
 lcd.setBacklight(LED_ON);
 lcd.setCursor(0,0);
 lcd.print("OneWire    Setup");
 lcd.setCursor(0,1);
 lcd.print("Connect EXT(10s)");
 delay(10000);
 ds.reset_search();
 delay(250);
 lcd.clear();
 lcd.setCursor(0,0);
 lcd.print("Sensor found");
 lcd.setCursor(0,1);
   for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
    lcd.print(addr[], HEX);
  }

lcd.print(addr[], HEX);You forgot the index "i".

Arduino 1-Wire Tutorial Includes an address sniffer. You then find a pen and some sticky labels and write the address and location on the labels and wrap the cable. You can write on heatshrink but I just use it to group sensors by colour. Some DS18B20s come with the address provided on a sleeve.

jremington:
lcd.print(addr[], HEX);You forgot the index "i".

Ah, I just quickly added that line as I had removed it, I had it correct when I was trying to output it before.

Nick_Pyner:
Arduino 1-Wire Tutorial Includes an address sniffer. You then find a pen and some sticky labels and write the address and location on the labels and wrap the cable. You can write on heatshrink but I just use it to group sensors by colour. Some DS18B20s come with the address provided on a sleeve.

I am aware of that and if I wanted to label the sensors I could just do that using the serial output I have now, but the way I want to do it is insert the sensors one at a time and have the program set each one as sensor 1, sensor 2, etc, that way it doesn't matter.

For this project it's not critical but for another one where I might want to have 10 or so sensors, it would be nice to just toss them in a bag and plug them in sequence without having to worry about labeling them.

Looking at the serial output the address is in a format that's more than 16 characters so that's probably why I can't print it on the lcd, and it just gives a single zero, unless I had a way to remove all of the spaces from it, anyway that's not really the important thing I'm trying to do.

I've googled more and the most I can find is a page that shows code for showing multiple sensor readings using commands I don't see in the examples, perhaps for an old version, but I still don't see how I can insert them, do a scan and set the newest address as a certain sensor number so that I can know which reading is from which later on, I thought I got close but it didn't work.

This is super frustrating since it's the only thing I don't know how to do and the rest of the coding should be easy and quick.

I'm thinking you're going to have to do a complete scan of the OneWire bus every time a new sensor is added that you want to identify. Your difficulty will be that the scan algorithm finds devices in a fixed order based on their OneWire ROM address. Since you want to add devices to the bus in random order, you don't know where in the previous sequence the address of the new device will fall.

So, you'll need to keep track of all the addresses already found and only declare a "new" one when it doesn't match any of the previous ones. You should also check that it's a valid address (based on CRC) and that it's actually a DS18B20 device (LSB of ROM address is 0x28).

Here's the thing, it only searches for the sensors when you first power on, (basically no hot plugging while monitoring) not as you randomly add them, so I can scan, find the address, and just change a variable to hold that address, then scan again and find the new one, and do the same, this device only needs two sensors so I only have to do it twice but once I figure it out it will be easy to expand.

If I search for addresses like so twice, it will show one after the other, it tends to favor one of the sensors to show first.

 lcd.setCursor(0,0);
 lcd.print("ONEWIRE    SETUP");
 lcd.setCursor(0,1);
 lcd.print("CONNECT EXT (5s)");
 delay(1000);
 lcd.setCursor(0,1);
 lcd.print("CONNECT EXT (4s)");
 delay(1000);
 lcd.setCursor(0,1);
 lcd.print("CONNECT EXT (3s)");
 delay(1000);
 lcd.setCursor(0,1);
 lcd.print("CONNECT EXT (2s)");
 delay(1000);
 lcd.setCursor(0,1);
 lcd.print("CONNECT EXT (1s)");
 delay(1000);
 
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }

  delay(250);

  lcd.setCursor(0,1);
  lcd.print("CONNECT INT (5s)");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("CONNECT INT (4s)");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("CONNECT INT (3s)");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("CONNECT INT (2s)");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("CONNECT INT (1s)");
  delay(1000);

  if ( !ds.search(addr2)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr2[i], HEX);
  }

  if (OneWire::crc8(addr2, 7) != addr2[7]) {
      Serial.println("CRC is not valid!");
      return;
  }

The problem with this is that if I do it as I want, where I plug in the first sensor, then the second sensor, it gives "no more addresses".

I've tried adding ds.reset();, ds.select(addr2); and a combination of both between the two times it should search for sensors but it just refuses to work when you add the second one in, however the example script they provide will show sensors as you plug them in, while running, at any point.

This has to be doable, but there aren't are really comprehensive/super detailed guides on the library from what I can find, I don't know if the commands I see in some other libraries are an old version or not as they are from 2014 and I don't see them listed, they seem to be using more straightforward commands like gettemp(address);.

I just don't get why it's displaying the addresses one at a time if I plug them both in at once, but if I do it one after another, even after ds.reset(); it's unable to see the second one.

A line by line list of all the commands and what they actually do would be immensely helpful to this I imagine, but I can't see anything like that on the onewire github.

I'm thinking the onewire library is to simplistic or just a proof of concept, I've found this library which appears to be more complex, specifically made for the temperature sensors and the example code looks similar in structure to some other ones I've seen, as I mentioned having commands that don't appear in the onewire library.

I think this is the library I need to use for this project, not the basic onewire one.

I'm a little burnt out right now from trying to figure out how to do it with the onewire library so can't see any method immediately jumping out but I probably just need a break, maybe some more sleep and then have another look at it to put it in the right order. I am seeing it able to give results if a new address is found, so there must be a way to just update the address and do it as I want.

Hmm, so I'm unable to get the temperature reading from this new library to display on the lcd, says that the function is overloaded, uhg. Maybe I should just switch to 10k thermistors and give up on trying for higher accuracy.

I've found this library

I thought you were already using that library, it's the one everybody else uses, and is referred to in the link I posted.
I don't understand what you are trying to do, or see the point of it but, I do understand that you already have the DS18B20s so I might point out that you are not obliged to use the library or even the one-wire system. You can put the sensors on individual pins, using One or more DS18B20 temperature sensors on Arduino- ar3ne1tt2.htm method, which might at least get you going and spare you from wasting your time with thermistors. Indeed, that way, you can revert to one-wire when reality prevails by a simple change of software.

Nick_Pyner:
I thought you were already using that library, it's the one everybody else uses, and is referred to in the link I posted.
I don't understand what you are trying to do, or see the point of it but, I do understand that you already have the DS18B20s so I might point out that you are not obliged to use the library or even the one-wire system. You can put the sensors on individual pins, using One or more DS18B20 temperature sensors on Arduino- ar3ne1tt2.htm method, which might at least get you going and spare you from wasting your time with thermistors. Indeed, that way, you can revert to one-wire when reality prevails by a simple change of software.

I don't see how I can explain it any simpler but I guess I'll try again.

Arduino starts.
Arduino prompts you to insert sensor 1 with a timeout
you insert sensor 1
arduino sees the address, and sets it as sensor 1
arduino prompts you to insert sensor 2 with a timeout
you insert sensor 2
arduino sees the newest addresss and sets it as sensor 2

etc, for however many sensors you need, that way they don't need to be labelled. Apparently this just isn't a thing though so you either have to do by pre-assigning the sensor serial numbers, or just use the onewire library alone with a single sensor as I did in another project.

I guess if I want to quickly be able to swap out sensors thermistors are the way it has to be done on individual pins.

Don't know what you were doing wrong because you never posted a complete code that actually compiles. But, this worked for me:

#include <Arduino.h>
#include <OneWire.h>
typedef uint8_t DeviceAddress[8];

#define DS18S20MODEL 0x10
#define DS18B20MODEL 0x28
#define DS1822MODEL  0x22
#define DS1825MODEL  0x3B
#define DS28EA00MODEL 0x42

void printAddress(DeviceAddress);
bool validAddress(const uint8_t*);
bool validFamily(const uint8_t*);
bool findNewSensor(DeviceAddress *, uint8_t);
bool addressMatch(DeviceAddress, DeviceAddress);

const uint8_t busPin = 5;

OneWire oneWire(busPin);

void setup(void) {
  const uint8_t numSensors = 2;
  uint8_t foundCount = 0;
  DeviceAddress addressList[numSensors];
  Serial.begin(115200);
  delay(2000);
  Serial.println("Starting");

  for (uint8_t index = 0; index < numSensors; index++) {
    Serial.print("Connect Sensor #");
    Serial.print(index);
    Serial.println(" and Hit Enter");
    while (!Serial.available()) {
    }
    while (Serial.available()) {
      Serial.read();
    }
    if (findNewSensor(addressList, foundCount)) {
      foundCount++;
      Serial.print("Found Device at Address: ");
      printAddress(addressList[index]);
      Serial.println();
    } else {
      Serial.println("No Device Found, Aborting");
      while (1) {
      }
    }
  }
  Serial.println();
  Serial.println("Found All Sensors:");
  for (uint8_t index = 0; index < numSensors; index++) {
    printAddress(addressList[index]);
    Serial.println();
  }
}

void loop(void) {
}

bool findNewSensor(DeviceAddress currentAddressList[], uint8_t currentCount) {
  DeviceAddress deviceAddress;
  bool alreadyFound;

  oneWire.reset_search();
  while (oneWire.search(deviceAddress)) {
    if (validAddress(deviceAddress)) {
      alreadyFound = false;
      if (validFamily(deviceAddress)) {
        for (uint8_t index = 0; index < currentCount; index++) {
          if (addressMatch(deviceAddress, currentAddressList[index])) {
            alreadyFound = true;
            break;
          }
        }
        if (!alreadyFound) {
          memcpy(currentAddressList[currentCount], deviceAddress, sizeof(DeviceAddress));
          return true;
        }

      }
    }
  }
  return false;
}

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

bool validAddress(const uint8_t* deviceAddress) {
  return (oneWire.crc8(deviceAddress, 7) == deviceAddress[7]);
}

bool addressMatch(DeviceAddress addr1, DeviceAddress addr2) {
  for (uint8_t index = 0; index < sizeof(DeviceAddress); index++) {
    if (addr1[index] != addr2[index]) {
      return false;
    }
  }
  return true;
}

bool validFamily(const uint8_t* deviceAddress) {
  switch (deviceAddress[0]) {
    case DS18S20MODEL:
      case DS18B20MODEL:
      case DS1822MODEL:
      case DS1825MODEL:
      case DS28EA00MODEL:
      return true;
    default:
      return false;
  }
}

A lot of this is just modifications of code I lifted directly from: GitHub - milesburton/Arduino-Temperature-Control-Library: Arduino Temperature Library

I only have two DS18B20 sensors handy for testing, you can set 'numSensors' to the number you have.

BTW, this code is exactly what I told you to do way back in Reply #6.

EDIT:
I would avoid using parasite power mode at least until you get things going. It's an extra complication you don't need at this point. Supply each device with a proper VCC.

Also, be sure and use a resistor to pull up the OneWire bus data line to VCC.