protocollo 1-wire per sensore

ciao a tutti!!
vi pongo un problema che sto faticando davvero a risolvere!!
devo configurare con il mio arduino 2009 il sensore di temperatura DS1821, sul sito di arduino ho trovato questo codice di esempio:

#include <OneWire.h>

// DS18S20 Temperature chip i/o

OneWire ds(10);  // on pin 10

void setup(void) {
  // initialize inputs/outputs
  // start serial port
  Serial.begin(9600);
}

void loop(void) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];

  if ( !ds.search(addr)) {
      Serial.print("No more addresses.\n");
      ds.reset_search();
      return;
  }

  Serial.print("R=");
  for( i = 0; i < 8; i++) {
    Serial.print(addr[i], HEX);
    Serial.print(" ");
  }

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

  if ( addr[0] != 0x10) {
      Serial.print("Device is not a DS18S20 family device.\n");
      return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("P=");
  Serial.print(present,HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print( OneWire::crc8( data, 8), HEX);
  Serial.println();
}


//Converting HEX to something meaningful (Temperature)

//In order to convert the HEX code to a temperature value, first you need to identify if you are using a DS18S20, or DS18B20 series sensor. The code to read the temperature needs to be slightly different for the DS18B20 (and DS1822), because it returns a 12-bit temperature value (0.0625 deg precision), while the DS18S20 and DS1820 return 9-bit values (0.5 deg precision).

//First off, you need to define some variables, (put right under loop() above)

//int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;


//Then for a DS18B20 series you will add the following code below the Serial.println(); above

 LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;


  if (SignBit) // If its negative
  {
     Serial.print("-");
  }
  Serial.print(Whole);
  Serial.print(".");
  if (Fract < 10)
  {
     Serial.print("0");
  }
  Serial.print(Fract);

  Serial.print("\n");


//This block of code converts the temperature to deg C and prints it to the Serial output.

questo codice legge e stampa il valore letto dalla temperatura sulla seriale, io invece avevo bisogno di prendere questo valore come numero reale decimale per infilarlo in un algoritmo.

le domande sono 2:

grazie a tutti anticipatamente per il tempo che potrete dedicarmi!!
ciao! :slight_smile:

Il valore lo hai gia.
E’ diviso in 3 viariabili:

Signbit

se il valore e’ diverso da nullo la temperatura e’ negativa.

Whole

Il valore numerico prima del punto decimale.

Fract

Il valore numerico dopo il punto decimale.

La funzione di cui hai bisogno:

int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
LowByte = data[0];
HighByte = data[1];
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000; //Controlla il segno
if (SignBit) // se il valore e’ diverso da zero il segno e’ negativo
{
TReading = (TReading ^ 0xffff) + 1;
}
Tc_100 = (6 * TReading) + TReading / 4; // Moltiplica per (100 * 0.0625) oppure 6.25

Whole = Tc_100 / 100; // separa whole dalla parte dopo il punto
Fract = Tc_100 % 100; // memorizza in Fract il valore dopo il punto

//Possibile uso di Whole

if( Whole > 20)
{
Serial.print(“Fa caldo”)
}

if( Whole < 20)
{
Serial.print(“Fa freddo”)
}
if( Whole == 20)
{
Serial.print(“Perfetto”)
}

l'idea era un'altra, io avrei bisogno che mi vega sputato un valore reale del tipo per esempio 32.8 che, memorizzato in una variabile, possa essere inserito in un'altra parte di codice...il fatto che sia diviso in più parti è un handicap! :-[

Be una volta che hai i 2 valori e il segno te li ricostruisci.

Un esempio in C:

#include <string.h>

double valorenum;
char valore[20], str[10];

 SerialRead(str); //Legge Whole
 strcpy (valore, str); //Copia Whole in valore
 strcat (valore,"."); // Concacatena il punto a whole
 SerialRead(str) //Legge Fract
 strcat (valore, str); //concatena Fract a valore dopo il punto
 valorenum = atof(valore); //Trasforma la stringa in un float

Se tu usi altri linguaggi sul PC devi usare una routine diversa, ma il senso e’ lo stesso.

P.S.
SerialRead () non e’ una funzione standard del C ma la funzione che usi tu per leggere dalla seriale a cui e’ collegato Arduino e quindi potrebbe chiamarsi anche diversamente, era solo per farti capire la tecnica.

Ok capito!!a questo punto, sai pensavo, invece di usare "serialRead" (o similari) potrei convertire whole in una stringa, copiarlo in valore, concatenare il punto fare lo stesso barbatrucco per fract e convertire la stringa con atof...comunque l'idea è ottima!!grazie infinite!! :)

Nel datasheet leggo "1°C resolution", non vuol dire che e' preciso al grado? Come fa a dare un valore come 30.2 ?

credo tu abbia ragione...il problema è che sto approcciando adesso quindi per adesso brancolo un pò nel buio...devo controllare bene perchè io necessito di temperature precise al decimo quindi dovrei combiare sensore!!

Leggi il datashhet fino in fondo, hai anche i decimi di grado.

ora guardo!!grazie!! :)...comunque il mio dubbio permane leggermente!!posso usare quel codice oppure devo modificare gli indirizzi?mi sembrano abbastanza simili...magari la struttura di acquisizione è la stessa ma devo rivedere qualcosa..

Il punto dove parla dei decimi e' il seguente:

HIGH-RESOLUTION TEMPERATURE READINGS The user can calculate temperature values with higher than 8-bit resolution using the data remaining in the counter and slope accumulator when the temperature conversion is complete.

Pero ha delle limitazioni, non si puo usare nella lettura continua. E bisogna legere 2 registri e fare delle operazioni matematiche per avere i decimi.

Di quale codice parli ? Di quello che hai postato all' primo messaggio ?

esatto quello li!!anche se per quello che mi hai detto adesso che bisogna aprire due registri per avere i decimi, già cambia in maniera considerevole purtroppo... :-[

Cosa vuol dire aprire due registri? Sarebbe difficile?

Ok, scusate ma forse con la dicitura 2 registri ho confuso un po le idee.

Il DS ha diverse possibilita di funzionamento. da 9 a 12 bit di precisione.

Dato che lavora con un registro a 8 bit per leggere le temperature si fanno 2 letture separate di 2 byte che contengono ognuno una parte di lettura.
I 2 byte vanno uniti per poter avere la lettura che ci interessa.

LS Byte

Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
I3 I2 I1 I0 D-1 D-2 D-3 D-4

MSByte

Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
S S S S S I6 I5 I4

S= Segno
I=temperatura
D=decimali

Poi c’e’ il registro di configuraione.

CONFIGURATION REGISTER
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
0 R1 R0 1 1 1 1 1

R1 R0 Risoluzione Passi decimali Tempo conversione
0 0 9 0.5 93.75ms
0 1 10 0.25 187.5ms
1 0 11 0.125 375ms
1 1 12 (default) 0.0625 750ms

Spero adesso di essere stato chiaro, appena ho un po di tempo continuo. :slight_smile:
Buona pasqua.