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;
}
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:
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;
}
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
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.
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