Usare più sonde DS18B20 (Risolto)

Salve innanzitutto vi ringrazio per la vostra attenzione.
Non sono molto esperto in questo campo, ma cerco di imparare.
Sto realizzando un progetto di termoregolazione con 3 sonde DS18B20. Il mio problema è che non riesco a capire come settare il codice usando 3 differenti ingressi per le sonde.
Il codice da cui ho preso spunti è il seguente:

#include <OneWire.h>
#include <LiquidCrystal.h>
 
#define BUTTON A0
 
int DS18B20_Pin = 2;
 
OneWire ds(DS18B20_Pin);
LiquidCrystal lcd(8,9,4,5,6,7);
 
void setup(void) {
  Serial.begin(9600);
 
  lcd.begin(16, 2);
 
  lcd.setCursor(0,0);
  lcd.print("  DS18B20 LCD  ");
  
  delay( 3000 );
}
 
void loop(void) {
  float temperature = getTemp();
  Serial.println(temperature);
 
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Temperatura:   ");
  lcd.setCursor(0,1);
  lcd.print(temperature);
 
  delay(1000); //just here to slow down the output so it is easier to read
 
}
 
float getTemp(){
  //returns the temperature from one DS18B20 in DEG Celsius
 
  byte data[12];
  byte addr[8];
 
  if ( !ds.search(addr)) {
      //no more sensors on chain, reset search
      ds.reset_search();
      return -1000;
  }
 
  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }
 
  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }
 
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end
 
  byte present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE); // Read Scratchpad
 
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
 
  ds.reset_search();
 
  byte MSB = data[1];
  byte LSB = data[0];
 
  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
 
  return TemperatureSum;
 
}

Vi ringrazio per il vostro aiuto.

Vi chiedo questo perchè non sono riuscito a capire come funziona quando le sonde sono collegate in BUS

Che vuol dire senza bus?
La sonda comunica con l'interfaccia OneWire, e ti serve la corrispondente libreria, che usa un pin per sonda. Puoi usare più sonde, collegate su più pin. Ogni sonda sarà gestita da una istanza diversa della libreria, che inizializzerai con il pin a cui è agganciata la sonda.

Nel tuo codice c'è questo:

int DS18B20_Pin = 2;
 
OneWire ds(DS18B20_Pin);

Ad esempio, per 2 sonde collegate sui pin 2 e 3, avrai:

const byte PIN_SONDA1 = 2;
const byte PIN_SONDA2 = 3;

OneWire ds1(PIN_SONDA1);
OneWire ds2(PIN_SONDA2);

Ti ringrazio. Ho capito. Quindi il codice dovrebbe essere usato in questo modo:

#include <OneWire.h>
#include <LiquidCrystal.h>
 

const byte PIN_SONDA1 = 2;
const byte PIN_SONDA2 = 3;
const byte PIN_SONDA3 = 4;
 
OneWire ds1(PIN_SONDA1);
OneWire ds2(PIN_SONDA2);
OneWire ds3(PIN_SONDA3);

LiquidCrystal lcd(8,9,4,5,6,7);
 
void setup(void) {
  Serial.begin(9600);
 
  lcd.begin(16, 2);
 
  lcd.setCursor(0,0);
  lcd.print("  DS18B20 LCD  ");

 
  delay( 3000 );
}
 
void loop(void) {
  float temperature = getTemp();
  Serial.println(temperature);
 
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Temperatura:   ");
  lcd.setCursor(0,1);
  lcd.print(temperature);
 
  delay(1000); //just here to slow down the output so it is easier to read
 
}
 
float getTemp(){
  //returns the temperature from one DS18B20 in DEG Celsius
 
  byte data[12];
  byte addr[8];
 
  if ( !ds1.search(addr)) {
      //no more sensors on chain, reset search
      ds1.reset_search();
      return -1000;
  }
 
  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }
 
  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }
 
  ds1.reset();
  ds1.select(addr);
  ds1.write(0x44,1); // start conversion, with parasite power on at the end
 
  byte present = ds1.reset();
  ds1.select(addr);    
  ds1.write(0xBE); // Read Scratchpad
 
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds1.read();
  }
 
  ds1.reset_search();
 
  byte MSB = data[1];
  byte LSB = data[0];
 
  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
 
  return TemperatureSum;
 
}

Una cosa però non ho capito. Come faccio ad avere 3 temperature, una per ogni sensore?
Dico questo dato che il codice riporta:

void loop(void) {
  float temperature = getTemp();
  Serial.println(temperature);
 
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Temperatura:   ");
  lcd.setCursor(0,1);
  lcd.print(temperature);

Come faccio ad esempio a leggere la temperatura del sensore 1 ?

Devi specificare quale sonda vuoi leggere.
Ti rimando a questa pagina:
http://playground.arduino.cc/Learning/OneWire
ed a questa:
http://www.pjrc.com/teensy/td_libs_OneWire.html

Devo dire la verità, non ho capito molto.
Se volessi usare il codice riportato prima, cosa dovrei fare per impostare 3 variabili di temperatura, ognuna associata ad un sensore?

#include <OneWire.h>
#include <LiquidCrystal.h>
 

const byte PIN_SONDA1 = 2;
const byte PIN_SONDA2 = 3;
const byte PIN_SONDA3 = 4;
 
OneWire ds1(PIN_SONDA1);
OneWire ds2(PIN_SONDA2);
OneWire ds3(PIN_SONDA3);

LiquidCrystal lcd(8,9,4,5,6,7);
 
void setup(void) {
  Serial.begin(9600);
 
  lcd.begin(16, 2);
 
  lcd.setCursor(0,0);
  lcd.print("  DS18B20 LCD  ");

 
  delay( 3000 );
}
 
void loop(void) {
  float temperature = getTemp();
  Serial.println(temperature);
 
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Temperatura:   ");
  lcd.setCursor(0,1);
  lcd.print(temperature);
 
  delay(1000); //just here to slow down the output so it is easier to read
 
}
 
float getTemp(){
  //returns the temperature from one DS18B20 in DEG Celsius
 
  byte data[12];
  byte addr[8];
 
  if ( !ds1.search(addr)) {
      //no more sensors on chain, reset search
      ds1.reset_search();
      return -1000;
  }
 
  if ( OneWire::crc8( addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return -1000;
  }
 
  if ( addr[0] != 0x10 && addr[0] != 0x28) {
      Serial.print("Device is not recognized");
      return -1000;
  }
 
  ds1.reset();
  ds1.select(addr);
  ds1.write(0x44,1); // start conversion, with parasite power on at the end
 
  byte present = ds1.reset();
  ds1.select(addr);    
  ds1.write(0xBE); // Read Scratchpad
 
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds1.read();
  }
 
  ds1.reset_search();
 
  byte MSB = data[1];
  byte LSB = data[0];
 
  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
 
  return TemperatureSum;
 
}

Esempio: ds1.read() o ds2.read().
Ma c'è tutto specificato nel 2° link che ti ho messo.

Quindi da quello che ho capito il programma scritto così dovrebbe funzionare:

#include <OneWire.h>
#include <LiquidCrystal.h>
 

const byte PIN_SONDA1 = 2;
const byte PIN_SONDA2 = 3;
const byte PIN_SONDA3 = 4;
 
OneWire ds1(PIN_SONDA1);
OneWire ds2(PIN_SONDA2);
OneWire ds3(PIN_SONDA3);

LiquidCrystal lcd(8,9,4,5,6,7);
 
void setup(void) {
  Serial.begin(9600);
 
  lcd.begin(16, 2);
 
  lcd.setCursor(0,0);
  lcd.print("  DS18B20 LCD  ");

 
  delay( 3000 );
}
 
void loop(void) {
  float 1temperature = ds1.read();
  float 2temperature = ds2.read();
  float 3temperature = ds3.read();
  
  Serial.println(1temperature);
  Serial.println(2temperature);
  Serial.println(3temperature);
 
  lcd.clear(); 
  lcd.setCursor(0,0);
  lcd.print("Temperatura:   ");
  lcd.setCursor(0,1);
  lcd.print(1temperature);
 
  delay(1000); //just here to slow down the output so it is easier to read
 
}

Mimmo, le sonde hanno un seriale interno unico. Il codice per più sonde scansiona il bus alla ricerca di sensori (i quali rispondono in base al tipo e al seriale) e poi li interroga tutti in base al seriale.

Ok, stavo facendo un pò di confusione.
Quindi ho compreso che questi sensori si possono usare solo connettendoli ad un' unica linea e non su ingressi digitali diversi.
Per trovare l' indirizzo delle mie sonde ho trovato questo:

#include 
 
// inizializza il bus onewire sulla porta n°10
OneWire ow(10);
 
void setup(void)
  {
  Serial.begin(9600); // inizializza la porta seriale a 9600
  lookUpSensors(); // avvia la ricerca delle sonde di temperatura
  }
 
void lookUpSensors()
  {
  byte address[8]; // questo array conterrà l'indirizzo delle sonde
  int i=0;
  byte ok = 0, tmp = 0;
 
  // avvia la ricerca
  Serial.println("--Ricerca avviata--");
 
  while (ow.search(address))
    {
    tmp = 0;
 
    // Se il primo byte dell'indirizzo è 0x10, si tratta di una sonda DS18S20
    if (address[0] == 0x10)
      {
      Serial.println("A questo indirizzo si trova una DS18S20 : ");
      tmp = 1; // ricerca andata a buon fine
      }
    else
      {
      // Se il primo byte dell'indirizzo è 0x28, si tratta di una sonda DS18B20
      if (address[0] == 0x28)
        {
        Serial.println("A questo indirizzo si trova una DS18B20 : ");
        tmp = 1; // ricerca andata a buon fine
        }
      }
 
    // Se il flag tmp si trova a 1, mostro l'indirizzo
    if (tmp == 1)
      {
      if (OneWire::crc8(address, 7) != address[7]) // faccio il controllo del CRC8
        {
        Serial.println(" (ma CRC8 non valido)");
        }
      else
        {
        // tutto ok, mostro l'indirizzo in formato esadecimale
        for (i=0;i<8;i++)
          {
          Serial.print("0x");
            if (address[i] < 9)
            {
            Serial.print("0");
            }
          Serial.print(address[i],HEX);
          if (i<7)
            {
            Serial.print(",");
            }
          }
          Serial.println("");
          ok = 1;
        }
      } //end if tmp
  }//end while
 
    if (ok == 0)
      {
      Serial.println("Non ho trovato sonde di temperatura");
      }
  Serial.println("--Ricerca terminata--");
  }
 
void loop(void)
  {
  // non faccio niente... ho fatto tutto nel setup!
  }

Poi con l'indirizzo che ho trovato carico quest'altro programma:

#include <OneWire.h>
 
int RHAnalogValue;  // Lettura in uscita dal sensore HIH-4030
float RH;  // Valore di Umidità Relativa espresso in percentuale
float T; // Valore di temperatura in °C dalla sonda DS18S20
 
#define RH_SENSOR 0 // Sensore umidità collegato su porta analogica n°0
OneWire  ONE_WIRE_BUS(10);  // Bus One-Wire (sonda DS18S20) sul pin 10
 
// Indirizzo della sonda DS18S20
// Nota: trova l'indirizzo della tua sonda col programma precedente e incollalo al posto di questo
byte T_SENSOR[8] = {0x10, 0xB5, 0x68, 0x01, 0x02, 0x08, 0x00, 0x8E};
 
void setup()
  {
  Serial.begin(9600); // Inizializzo la porta seriale
  }
 
void writeTimeToScratchpad(byte* address)
  {
  ONE_WIRE_BUS.reset(); // Resetto il bus
  ONE_WIRE_BUS.select(address);   // Seleziono la mia sonda DS18S20
  ONE_WIRE_BUS.write(0x44,1);   // Richiamo la funzione di conversione temperatura (44h)
  // che posiziona il valore di temperatura nello scratchpad (comando Convert T)
  delay(1000);   // Attendo un secondo che la scrittura sia completa
  }
 
void readTimeFromScratchpad(byte* address, byte* data)
  {
  ONE_WIRE_BUS.reset();   // Resetto il bus
  ONE_WIRE_BUS.select(address);   // Seleziono la mia sonda DS18S20
  ONE_WIRE_BUS.write(0xBE); // Comando di lettura dello scratchpad (comando Read Scratchpad)
  for (byte i=0;i<9;i++)
    {
    data[i] = ONE_WIRE_BUS.read(); // Leggo i 9 bytes che compongono lo scratchpad
    }
  }
 
float getTemperature(byte* address)
  {
  int tr;
  byte data[12];
  writeTimeToScratchpad(address); // Richiamo conversione temperatura
  readTimeFromScratchpad(address,data); // effettuo la lettura dello Scratchpad
  tr = data[0];   // Posiziono in TR il byte meno significativo
  // il valore di temperatura è contenuto nel byte 0 e nel byte 1
 
  // Il byte 1 contiene il segno
  if (data[1] > 0x80) // Se il valore è >128 allora la temperatura è negativa
    {
    tr = !tr + 1; // Correzione per complemento a due
    tr = tr * -1; // Ottengo il valore negativo
    }
 
  int cpc = data[7];   // Byte 7 dello scratchpad: COUNT PER °C (10h)
  int cr = data[6];   // Byte 6 dello scratchpad: COUNT REMAIN (0Ch)
  tr = tr >> 1;   // Rilascio il bit 0 come specificato dal datasheet per avere una risoluzione > di 9bit
 
  // Calcolo la temperatura secondo la formula fornita sul datasheet:
  // TEMPERATURA = LETTURA - 0.25 + (COUNT PER °C - COUNT REMAIN)/(COUNT PER °C)
 
  return tr - (float)0.25 + (cpc - cr)/(float)cpc;
  }
 
// Conversione da Fahrenheit a Celsius
float f2c(float val)
  {
  float aux = val - 32;
  return (aux * 5 / 9);
  }
 
// COnversione da Celsius a Fahrenheit
float c2f(float val)
  {
  float aux = (val * 9 / 5);
  return (aux + 32);
  }
 
void loop()
  {
   // Lettura temperatura (la DS18S20 fornisce il valore in °C)
  T = getTemperature(T_SENSOR);
 
  // Lettura del valore analogico dalla sonda di umidità
  RHAnalogValue = analogRead(RH_SENSOR);
 
  // La funzione analogRead restituisce un valore tra 0 e 1023
  // proporzionale alla tensione applicata sul pin
  // per cui il valore di tensione è dato da:
  // Vout=(analogRead/1023)*5
  // Il valore di umidità relativa è invece dato da:
  // RH = (Vout-0.8)/0.031
  // come già spiegato nell'articolo: http://www.settorezero.com/wordpress/sensore-di-umidita-honeywell-hih-4030/
  RH = ((((float)RHAnalogValue/1023)*5)-0.8)/0.031;
 
  // Dato che abbiamo anche il valore di temperatura, effettuiamo anche
  // la compensazione per avere un valore di umidità relativo preciso
  RH = RH/(1.0546-(0.00216*T));
 
  // Stampo i risultati su terminale seriale
  Serial.print("Umidita relativa: ");
  Serial.print(RH,1); // Scrivo il valore di umidità con un decimale
  Serial.println("%");
 
  Serial.print("Temperatura: ");
  Serial.print(T,1); // Scrivo il valore di temperatura con un decimale
  Serial.println(" C");
 
  // Attendo 10 secondi per ricominciare
  delay(10000);
  }

ripetendo i calcoli che effettua per ogni sensore che ho messo e per ogni indirizzo che ho trovato.
Ho solo un dubbio. L' idirizzo è sempre uguale?

mimmo1994:
Ok, stavo facendo un pò di confusione.
Quindi ho compreso che questi sensori si possono usare solo connettendoli ad un' unica linea e non su ingressi digitali diversi.

Premetto che non ho mai usato più sonde su pin differenti, nella pagina che ti ho linkato c'è scritto che si possono gestire più sonde ognuna su un pin, istanziando più classi della lib.

Il metodo che suggerisce zoomx si riferisce all'identificazione delle sonde messe su un unico bus, che però mi pareva non fosse il metodo che volevi tu. Comunque scegli quello che ti risulta più facile.

Si, in realtà preferivo un pin per ogni sensore. Comunque mi interessa la soluzione software più semplice e credo sia usare un indirizzo per ogni sensore.
Vi ringrazio per l'aiuto.

sto facendo un progetto simile al tuo per 3 pannelli solari termici qui a casa mia. Io ti consiglio, dopo aver capito per bene come funziona, di usare OneWire su un'unica linea settandoti gli indirizzi...è molto più semplice e poi devi effettuare meno collegamenti.
Alla fine su un display io visualizzo tutte le temperature che voglio :slight_smile:

mimmo1994:
Ho solo un dubbio. L' idirizzo è sempre uguale?

No, altrimenti non potresti "indirizzare" le richieste. Avevo dimenticato di dirti che il sistema permette anche l'identificazione dei sensori per tipo (tra l'S e il B cambia la risoluzione in bit) ma l'hai già trovato da solo.

Se sia più semplice usare più pin oppure tutto su uno stesso bus non lo so, dipende se gli altri pin ti servono, se è più comodo avere un unico cavo oppure no (come una topologia a stella).

Come ho scritto non ho mai provato con più sensori ma, come puoi vedere, trovi codice che già lo fa. Quello che uso io ne trova uno solo e mi mostra una sola temperatura. Però è un codice e libreria per un altro micro, l'MSP430, e non so se la libreria ha le stesse funzioni di quella Arduino OneWire che usi tu.

Io leggo tre sonde con un bus...mi sono ricavato(grazie all'aiuto del forum)tre indirizzi e da li mi tiro fuori le tre temperature.

Rs125:
Io ti consiglio, dopo aver capito per bene come funziona, di usare OneWire su un'unica linea settandoti gli indirizzi...è molto più semplice e poi devi effettuare meno collegamenti.

Il punto più importante è proprio l'ultimo: settando un solo bus, usi un unico pin per tutte le sonde. In un progetto in cui devi usare anche altri dispositivi (tipo display LCD o altro) questa è una cosa che più diventare di vitale importanza :wink:

Si, è vero mi conviene usare un unico pin dato che devo collegare più sensori e un display.