Identifying DS18B20 thermometers and labelling them.

Dear Forum, ...edit...please jump to post number 4 before wading through this!

I'm continuing on with a project in which I am trying to get up to 10 temperature readings, and act upon them. The sensors are Maxim DS18B20, and I have copied some code to allow me to take measurements; and the code works really well. Of course this code doesn't do exactly what I want so, despite not knowing exactly what I'm doing, I'm trying to modify it!

This code uses two libraries, called OneWire.h and DallasTemperature.h, and the code is shown below:

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

// Data wire is plugged into digital pin 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire device
OneWire oneWire(ONE_WIRE_BUS);  

// Pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);

int deviceCount = 0;
float tempC;

void setup(void)
{
  sensors.begin();  // Start up the library
  
  //Set all sensors' resolution to 10 bits
  sensors.setResolution(10);
  
  Serial.begin(9600);
  
  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  deviceCount = sensors.getDeviceCount();
  Serial.print(deviceCount, DEC); //the DEC simply makes sure number is decimal
  Serial.println(" devices.");
  Serial.println("");
}

void loop(void)
{ 
  // Send command to all the sensors for temperature conversion
  sensors.requestTemperatures();  
  
  // Display temperature from each sensor
  for (int i = 0;  i < deviceCount;  i++)
  {
    Serial.print("Sensor ");
    Serial.print(i+1);
    Serial.print(" : ");
    tempC = sensors.getTempCByIndex(i);
    Serial.print(tempC);
    Serial.print((char)39);//shows nearest to degrees character I can find
    Serial.print("C  |  ");
    Serial.print(DallasTemperature::toFahrenheit(tempC));
    Serial.print((char)176);//shows degrees character
    //no, it doesn't! Not recognised on my serial monitor
    Serial.println("F");
  }
  
  Serial.println("");
  delay(1000);
}

There are a couple of niggly points, such as near to the end the author tries to print a degrees symbol
  Serial.print((char)176);//shows degrees character What appears when I look at my serial monitor is a horizontally inverted question mark (mirrored '?') which, as I can't find it in the ASCII character set, presumably means an unrecognisable unicode.
What could be the solution to this, ie so it prints the correct degrees symbol?

I managed to change the resolution for every sensor down from 12 bits to 10 bits in order to save temperature conversion time, using the line

  //Set all sensors' resolution to 10 bits
  sensors.setResolution(10);

but really I got lost in the header files of DallasTemperature and Onewire, so it was more luck than knowledge - ultimately I'd like to be able to set the resolution for each sensor individually (or at least KNOW how to do it, as this project will run fine by setting all sensors the same.

The main aim for me is to be able to read an individual sensor's 64 bit identification number so that I can give it a useful name such as ROOMTEMP or OUTSIDE TEMP, etc. At the moment the software decides which sensor is 'sensor 1' etc., based on the command tempC = sensors.getTempCByIndex(i); but that's not ideal as I can see that, should one sensor have to be replaced, this order may change.

My questions then:

  1. Does the "sensors.getTempCByIndex(i);" command always read the sensors in the same order? Lowest S/N to highest S/N?
    If this is the case then a sensor substitution could change the order, so simply assigning a name to 'sensor1....sensor2, etc, would be foolhardy.

  2. Looking at the datasheet for DS18B20 the S/N must be quoted over the databus to get that sensor to cough up its temperature reading, so presumably the number I want is there inside one of the libraries (I have looked, but don't really know what I'm looking for). Please would someone point me towards what I should look for, where it is, and how I grab it for use in my code.

Regards, and thanks to all who give up their time to try to educate old duffers like me!
GM

Apologies to all for jumping the gun, I've just seen what I think are the answers to my questions on a web page

Please ignore my request for help (for now). Perhaps I can answer those questions for myself, then post the answers for others to use.

GM

Glorymill:
My questions then:

  1. Does the "sensors.getTempCByIndex(i);" command always read the sensors in the same order? Lowest S/N to highest S/N?
    If this is the case then a sensor substitution could change the order, so simply assigning a name to 'sensor1....sensor2, etc, would be foolhardy.

Correct

  1. Looking at the datasheet for DS18B20 the S/N must be quoted over the databus to get that sensor to cough up its temperature reading, so presumably the number I want is there inside one of the libraries (I have looked, but don't really know what I'm looking for). Please would someone point me towards what I should look for, where it is, and how I grab it for use in my code.

I haven't looked at the link from your previous post. But, the examples that come with the DallasTemperature show how to read a device address. Then you just need to print it and mark the sensor. Would be easiest if you did this once device at a time.

Firstly, a big thank-you to those contributors who give pearls of wisdom, such as "before posting here have a look for yourself", and "so, what have YOU done so far". Very true, and very apt.

Yesterday I spent many hours trying to find such info, and found most, at least enough to get me over the latest hurdle in my project. At this stage, in short, I'm trying to read about 10 DS18B20 temperature sensors, and after initially tying myself up in knots, found the useful phrase 'read by address', rather than 'read by index'.

For some unknown reason I found myself on TerryKing's website (www.YourDuino.com), and there found much of what I needed and, with minor tweeks to his sample software, now have a working sketch that is suitable for this stage of my application. Thanks to Terry for that. More importantly I have learned some useful code, and learned to avoid some irritating and time consuming pitfalls (just not the one to which a question is asked at the end of this diatribe!).

I'm writing this not for my own benefit, but as an attempt to help other learners to grasp the fundamentals, read others' sketches, and learn for themselves. By all means ask questions when the need arises, but don't rush to the forum at the first hurdle - and where's the fun in simply copying and pasting others' code verbatim, without any understanding? There is none, so please don't expect the more learned on here to write your code for you.

For those who are more skilled, it's easy to slip into the use of jargon, but when dealing with beginners (I'm sure you can spot their skills level quite easily) may I respectfully suggest the occasional verbose phrase instead of the acronym. I'm still not sure if an ESP32 is a rival microcontroller, a wi-fi add-on, or something else!!!

So to the technical question, for those who are still awake!

I have the line of code

Serial.print((char)176);//shows degrees character

but my serial monitor prints:

09:09:50.789 -> Sensor 1: 20.25⸮C | 68.45⸮F
09:09:50.843 -> Sensor 2: 19.50⸮C | 67.10⸮F
09:09:50.889 -> Sensor 3: 20.25⸮C | 68.45⸮F
09:09:50.889 -> Sensor 4: 20.50⸮C | 68.90⸮F
09:09:50.943 -> Sensor 5: 19.00⸮C | 66.20⸮F
09:09:50.990 -> Sensor 6: 19.50⸮C | 67.10⸮F
09:09:50.990 -> Sensor 7: 20.25⸮C | 68.45⸮F

I have substituted (char)176 for (char)65 (the ASCII code for A) and it prints A. Other ASCII codes work too, but not the one for the degree symbol.
Any ideas what I'm doing wrong?

GM

There is no ASCII code for the degree symbol; ASCII is a seven bit code, so after 127, all bets are off.

Is this for Serial Monitor? In that case UTF-8 Unicode might work. Try 0xC2 followed by 0xBA to get a degree symbol.

20:	  ! " # $ % & ' ( ) * + , - . / 
30:	0 1 2 3 4 5 6 7 8 9 : ; < = > ? 
40:	@ A B C D E F G H I J K L M N O 
50:	P Q R S T U V W X Y Z [ \ ] ^ _ 
60:	` a b c d e f g h i j k l m n o 
70:	p q r s t u v w x y z { | } ~  


UTF_8 w/ C2 prefix
A0:	  ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ 
B0:	° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ 


UTF_8 w/ C3 prefix
80:	À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï 
90:	Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß 
A0:	à á â ã ä å æ ç è é ê ë ì í î ï 
B0:	ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ 


UTF_8 w/ C4 prefix
80:	Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď 
90:	Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ 
A0:	Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į 
B0:	İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ 


UTF_8 w/ C5 prefix
80:	ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ 
90:	Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş ş 
A0:	Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů 
B0:	Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž ſ 


UTF_8 w/ C6 prefix
80:	ƀ Ɓ Ƃ ƃ Ƅ ƅ Ɔ Ƈ ƈ Ɖ Ɗ Ƌ ƌ ƍ Ǝ Ə 
90:	Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ 
A0:	Ơ ơ Ƣ ƣ Ƥ ƥ Ʀ Ƨ ƨ Ʃ ƪ ƫ Ƭ ƭ Ʈ Ư 
B0:	ư Ʊ Ʋ Ƴ ƴ Ƶ ƶ Ʒ Ƹ ƹ ƺ ƻ Ƽ ƽ ƾ ƿ 


UTF_8 w/ C7 prefix
80:	ǀ ǁ ǂ ǃ DŽ Dž dž LJ Lj lj NJ Nj nj Ǎ ǎ Ǐ 
90:	ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ Ǘ ǘ Ǚ ǚ Ǜ ǜ ǝ Ǟ ǟ 
A0:	Ǡ ǡ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ 
B0:	ǰ DZ Dz dz Ǵ ǵ Ƕ Ƿ Ǹ ǹ Ǻ ǻ Ǽ ǽ Ǿ ǿ 


UTF_8 w/ C8 prefix
80:	Ȁ ȁ Ȃ ȃ Ȅ ȅ Ȇ ȇ Ȉ ȉ Ȋ ȋ Ȍ ȍ Ȏ ȏ 
90:	Ȑ ȑ Ȓ ȓ Ȕ ȕ Ȗ ȗ Ș ș Ț ț Ȝ ȝ Ȟ ȟ 
A0:	Ƞ ȡ Ȣ ȣ Ȥ ȥ Ȧ ȧ Ȩ ȩ Ȫ ȫ Ȭ ȭ Ȯ ȯ 
B0:	Ȱ ȱ Ȳ ȳ ȴ ȵ ȶ ȷ ȸ ȹ Ⱥ Ȼ ȼ Ƚ Ⱦ ȿ 


UTF_8 w/ C9 prefix
80:	ɀ Ɂ ɂ Ƀ Ʉ Ʌ Ɇ ɇ Ɉ ɉ Ɋ ɋ Ɍ ɍ Ɏ ɏ 
90:	ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ ɛ ɜ ɝ ɞ ɟ 
A0:	ɠ ɡ ɢ ɣ ɤ ɥ ɦ ɧ ɨ ɩ ɪ ɫ ɬ ɭ ɮ ɯ 
B0:	ɰ ɱ ɲ ɳ ɴ ɵ ɶ ɷ ɸ ɹ ɺ ɻ ɼ ɽ ɾ ɿ

Glorymill:
...Perhaps I can answer those questions for myself, then post the answers for others to use.

At this stage I am feeling a bit smug; I now have a system with up to 10 thermometers attached, and an LCD display attached over I2C. For the benefit of others trying to do similar, the code is attached below. The remaining problems, as far as my project is concerned, are minor. They are:

  1. I would like my LCD to truncate the displayed (float) values to 1 decimal place, presently it's to two.
  2. I'd like to add a pushbutton which, when pressed, will illuminate the display.
  3. I'd like to use the alarm features of the DS18B20 temperature sensor.
  4. I'd like to add a GSM module to allow text message reporting (not all places have wi-fi)

Items 2, 3, and 4 require me to put in a little work, but please may I have some guidance on item 1.
Thanks to JohnWasser for his help, but I'm afraid I don't understand how to implement it!
Are you saying to replace

Serial.print((char)176)

with

Serial.print((char)(0xC2, 0xBA))    ?

Clearly I haven't tried that yet, domestic duties have taken priority now that the bulk of the job is done.

My full code (thanks to Terry's YourDuino.com for a great write-up on LCDs):

/* YourDuino.com Example: Multiple DS18B20 Temperature Sensors
   Displayed on 4x20 character LCD display
   
   DS18B20 Pinout (Left to Right, pins down, flat side toward you)
  - Left   = Ground
  - Center = Signal (Pin 10):  (with 3.3K to 4.7K resistor to +5 or 3.3 )
  - Right  = +5 or +3.3 V
   
   terry@yourduino.com */

/*-----( Import needed libraries )-----*/
// Get 1-wire Library here: http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <OneWire.h>

//Get DallasTemperature Library here:  http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
#include <DallasTemperature.h>
// Wire (I2C) Library
#include <Wire.h>
// LCD Library
//#include <LCD.h>
#include <LiquidCrystal_I2C.h>  // F Malpartida's NewLiquidCrystal library
//Download: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move original LiquidCrystal library elsewhere, copy this in it's place


/*-----( Declare Constants and Pin Numbers )-----*/
// Data wire is plugged into port 10 on the Arduino (can be changed)
#define ONE_WIRE_BUS 10    // NOTE: No ";" on #define  

#define I2C_ADDR 0x3F  // Define I2C Address for the PCF8574A on the LCD Backpack board
//---(Following are the PCF8574 pin assignments to LCD connections )----
// This are different than earlier/different I2C LCD displays
#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

/*-----( Declare objects )-----*/
// Setup a oneWire instance to communicate with any OneWire devices 
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass address of our oneWire instance to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// Start the LCD display library
//LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin); ORIGINAL ORDER OF PINS
LiquidCrystal_I2C  lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //New pins order from LCD tester sketch

/*-----( Declare Variables )-----*/
// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// https://arduinoinfo.mywikis.net/wiki/Brick-Temperature-DS18B20#Read%20individual


 // Addresses of my DS18B20 sensors, from Notepad text file in Arduino folder
DeviceAddress Flow = { 0x28, 0xFF, 0x78, 0x93, 0x53, 0x19, 0x01, 0xED }; // sensor 1
DeviceAddress Rtn = { 0x28, 0xFF, 0xDA, 0x93, 0x53, 0x19, 0x01, 0x5D }; // sensor 2
DeviceAddress DHW = { 0x28, 0xFF, 0x96, 0x95, 0x53, 0x19, 0x01, 0x9C }; // sensor 3
DeviceAddress Lounge = { 0x28, 0xFF, 0xD6, 0x6C, 0x53, 0x19, 0x01, 0x97 }; // sensor 4



void setup()   /****** SETUP: RUNS ONCE ******/
{
//------- Initialize the Temperature measurement library--------------
  Serial.begin(9600);
  sensors.begin();
  // set the resolution to 10 bit (Can be 9 to 12 bits .. lower is faster)
  sensors.setResolution(Flow, 12);      //12 bits = 1/16th degree C resolution
  sensors.setResolution(Rtn, 12);
  sensors.setResolution(DHW, 9);        //9 bits = 1/2 degree C resolution
  sensors.setResolution(Lounge, 10);    //10 bits = 1/4 degree C resolution
  sensors.setResolution(Room2, 10);
  sensors.setResolution(Bedroom1, 10);
  sensors.setResolution(Bedroom2, 10);
  sensors.setResolution(Outside, 10);
  sensors.setResolution(Spare1, 10);
  sensors.setResolution(Spare2, 10);

//---------------- Initialize the lcd ------------------  
  lcd.begin (20,4);  // 20 characters, 4 lines
// Switch on the backlight
//  lcd.setBacklightPin(BACKLIGHT_PIN,NEGATIVE);   Original line
//  lcd.setBacklight(LED_ON);                      Original line
lcd.backlight();

}//--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  sensors.requestTemperatures(); // Send the command to get temperatures

     Serial.print("Boiler Flow: ");
  printTemperature(Flow);
     Serial.print("Boiler Rtn: ");
  printTemperature(Rtn);
     Serial.print("DHW temp: ");
  printTemperature(DHW);
     Serial.print("Lounge: ");
  printTemperature(Lounge);
     Serial.print("Room 1: ");
  printTemperature(Room2);
     Serial.print("Bedroom 1: ");
  printTemperature(Bedroom1);
     Serial.print("Bedroom 2: ");
  printTemperature(Bedroom2);
     Serial.print("Outside: ");
  printTemperature(Outside);
       Serial.print("Spare 1: ");
  printTemperature(Spare1);
       Serial.print("Spare 2: ");
  printTemperature(Spare2);

  
  lcd.clear();  // Reset the display  
  lcd.home();
  lcd.backlight();  //Backlight ON if under program control  

// Print our characters on the LCD
// NOTE: Line number and character number start at 0 not 1

  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("1:");
  (displayTemperature(Flow));

  lcd.setCursor(11,0); //Start at character 11 on line 0
  lcd.print("2:");
  displayTemperature(Rtn);

  lcd.setCursor(0,1); //Start at character 0 on line 1
  lcd.print("3:");
  displayTemperature(DHW);

  lcd.setCursor(11,1); //Start at character 11 on line 1
  lcd.print("4:");
  displayTemperature(Lounge);

  delay(2000);

}//--(end main loop )---

/*-----( Declare User-written Functions )-----*/
void displayTemperature(DeviceAddress deviceAddress)
{

float tempC = sensors.getTempC(deviceAddress);

   if (tempC == -127.00) // Measurement failed or no device found
   {
    lcd.print("Temperature Error");
   }
   else
   {
   //lcd.print("C=");
   lcd.print(tempC);
   lcd.print((char)0x2A);
   lcd.print("C");
   //lcd.print(DallasTemperature::toFahrenheit(tempC)); // Convert to F
   }
}// End printTemperature

//*********( THE END )***********

//the next bit is a function, and may be where 'printTemperature' comes from, because
//without it I get compiler errors. PJ
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(tempC);
  Serial.print((char)176);
  Serial.println("C  |  ");
  //Serial.print(DallasTemperature::toFahrenheit(tempC));
  //Serial.print((char)176);
  //Serial.println("F");
}

The way I have tried to have control over the readings is to produce a table of sensor addresses such that I can replace a broken sensor with a spare, adding its address to the table and removing that of the broken one. Again thanks to Terry for supplying a link to a DS18B20 address finder.

// Addresses of my DS18B20 sensors, from Notepad text file in Arduino folder
DeviceAddress Flow = { 0x28, 0xFF, 0x78, 0x93, 0x53, 0x19, 0x01, 0xED }; // sensor 1
DeviceAddress Rtn = { 0x28, 0xFF, 0xDA, 0x93, 0x53, 0x19, 0x01, 0x5D }; // sensor 2
DeviceAddress DHW = { 0x28, 0xFF, 0x96, 0x95, 0x53, 0x19, 0x01, 0x9C }; // sensor 3
DeviceAddress Lounge = { 0x28, 0xFF, 0xD6, 0x6C, 0x53, 0x19, 0x01, 0x97 }; // sensor 4

etc

All good here then, onwards and upwards. Thanks again.
GM

Glorymill:

  1. I would like my LCD to truncate the displayed (float) values to 1 decimal place, presently it's to two.

If you are using lcd.print(value); and 'value' is a float, then print() will default to two places after the decimal. To change it to one: lcd.print(value, 1);

Glorymill:
Thanks to JohnWasser for his help, but I'm afraid I don't understand how to implement it!
Are you saying to replace

Serial.print((char)176)

with
Serial.print((char)(0xC2, 0xBA))    ?

Not quite:

  Serial.write(0xC2);
  Serial.write(0xBA);

Note: .write() is similar to .print() but it just passes through the binary byte directly, without formatting.