Problema sensore ZTPD 2210

ciao ragazzi, ho un problema con un sensore della amphenol di temperatura ztpd 2210(i2c).
Il sensore restituisce valori totalmente alterati(anche negativi e di molto), quindi credo ci sia un problema nella lettura dei byte relativi alla lettura dopo aver dato il comando. Ho provato anche utilizzando un raspberry attivando da software le R di pullup da 4.7k.
Non so più che pesci prendere ed è un progetto per un esame che ho tra 5 giorni.

Questo è il codice:

#include <Wire.h>

#define SENSOR_ADDR 0x38  // Indirizzo I²C del sensore

void setup() {
  Serial.begin(9600);
  Wire.begin();
}

void loop() {
  Wire.beginTransmission(SENSOR_ADDR);
  Wire.write(0xAA);  // Comando per leggere la temperatura
  Wire.endTransmission();
  delay(80);  // Attendi il completamento della misurazione

  Wire.requestFrom(SENSOR_ADDR, 3);
  if (Wire.available() == 3) {
    uint8_t byte0 = Wire.read();
    uint8_t byte1 = Wire.read();
    uint8_t byte2 = Wire.read();
    int32_t rawData = (byte0 << 16) | (byte1 << 8) | byte2;
    float temperature = (rawData / 16777216.0) * 130.0 - 20.0;
    Serial.print("Temperatura: ");
    Serial.print(temperature);
    Serial.println("°C");
  }
  delay(1000);  // Attendi un secondo prima della prossima lettura
}

Potete darmi una mano? Grazie <3

Stai invertendo l'ordine dei byte ricevuti. Il sensore segue la codifica "Little Endian" ovvero il byte LSB per primo, ma tu lo stai shiftando a sinistra di 16 bit trattandolo come se fosse il più significativo. Stessa cosa per il resto dei byte ovviamente.

mi puoi dire come risolvere a livello di codice? te ne sarei grado

devi semplicemente invertire l'ordine dei byte quando ricostruisci rawData tenendo conto che byte2 è il byte più significativo e byte0 quello meno significativo, ovvero:

int32_t rawData = (byte2 << 16) | (byte1 << 8) | byte0;

Ti dirò,ho appena provato ma restituisce lo stesso temperature negative :frowning:

Non avevo guardato con attenzione il tuo sketch, pardon.

Tu stai inviando indirizzo i2c e comando 0xAA, ma nel datasheet c'è scritto che il comando da usare dovrebbe essere 0xAF.
Inoltre secondo me il primo byte che ricevi a prescindere dal comando inviato è lo status byte
In effetti il datasheet non è molto chiaro in proposito...

L'ideale sarebbe avere un analizzatore logico di segnali e vedere effettivamente quanti byte restituisce il sensore.
In alternativa, metti da parte un attimo la ricostruzione del dato e invece che leggere solo 3 byte, prova a stampare tutto quello che arriva sul bus usando un ciclo while.
Una volta che hai chiarito quale byte si trova in quale posizione, puoi procedere con il resto.

while (Wire.available()) {
   Serial.print(Wire.read(), HEX);
}

anche provando ad escludere il primo byte(ex. status byte), mi restituisce gli stessi risultati(tutti vicini a -20 gradi)

Prova a stampare tutto come ti dicevo, lascia perdere la conversione per ora.
Se non capisci quali byte e come sono ordinati è inutile che provi a convertire.

Inoltre ribadisco che il datasheet è veramente incasinato...

Quello che chiama Byte (0) nella figura è in realtà il byte MSB perché piccolo piccolo c'è scritto SensorDat <23:16> ovvero i bit dal 17-simo fino al 24-simo di SensorDat quindi è giusto lo shift come l'hai fatto inizialmente :persevere: (ma con i byte corretti evidentemente).

allora, ho provato a fare una cosa, ovvero richiedere 7 byte(1 di status+gli altri 6) e gli ho chiesto di stamparmeli

0x60 0x5E 0x62 0xC4 0x72 0x95 0x62

e ora? Sono entrato nel pallone e non ci sto capendo niente

Ammesso che il primo sia lo status byte:

int32_t raw = 0x5E62C4  // che equivale a 6185668 decimale
float temp = (raw / 2^24)*130 - 20 //  (6185668 / 16777216)*130 - 20 = 27,930 °C

La temperatura misurata di SensorDat è plausibile? Se non hai oggetti caldi di fronte al PIR direi di si.

Sempre secondo il datasheet, TempData che dovrebbe essere la temperatura ambiente:

int32_t raw = 0x729562  // che equivale a 7509346 decimale
float temp = (raw / 2^24)*105 - 20 //  (7509346/ 16777216)*105 - 20 = 26,997 °C

si, ha senso allora, e ora come formulo RawData? c'è qualcosa che mi sfugge sicuramente lì

E' corretto come hai fatto inizialmente in teoria, ma devi scartare lo status byte ovviamente.
Inoltre ti conviene leggere tutti i byte anche se non li usi, altrimenti al loop successivo andrai a leggere quelli rimanenti incasinando tutto.

Prova a stampare il valore e poi verifica con la calcolatrice di windows (modalità programmatore).

    uint8_t status= Wire.read();
    uint8_t byte0 = Wire.read();
    uint8_t byte1 = Wire.read();
    uint8_t byte2 = Wire.read();
    int32_t rawData = (byte0 << 16) | (byte1 << 8) | byte2;
    Serial.println(byte0 , HEX);
    Serial.println(byte1 , HEX);
    Serial.println(byte2 , HEX);
    Serial.println(rawData);

ok fatto, allora il valore unendo gli esadecimali viene 6202623, ma rawdata 23297, non fa il giusto abbinamento

rawData è una variabile da 32 bit, ma tu ne stai leggendo solo 24.

Può darsi che lo spazio di memoria che viene riservato per la variabile da 32 contenga già dati vecchi e quindi ottieni un risultato non coerente.
Prova ad inizializzarla al valore zero prima di fare lo shift.

Se anche così ancora non va allora probabilmente è un problema di casting delle variabili int8_t.

Appena metto le mani su un PC prova a fare qualche test con il simulatore online

provato e continua a non andare, aspetto un tuo riscontro allora(continuo a fare prove nel frattempo)

#include <Wire.h>

#define SENSOR_ADDR 0x38  // Indirizzo I2C del sensore
#define COMMAND 0xAA      // Comando per leggere la temperatura

void setup() {
  Serial.begin(9600);
  Wire.begin();  // Inizializza il bus I2C
}

void loop() {
  float objectTemp, ambientTemp;

  // Legge i dati dal sensore
  readTemperature(objectTemp, ambientTemp);

  // Stampa i risultati
  Serial.print("Temperatura dell'oggetto: ");
  Serial.print(objectTemp);
  Serial.println(" °C");

  Serial.print("Temperatura ambiente: ");
  Serial.print(ambientTemp);
  Serial.println(" °C");

  delay(1000);  // Pausa di 1 secondo
}

void readTemperature(float &objectTemp, float &ambientTemp) {
  uint8_t data[7];  // Array per i 7 byte di dati

  // Invia il comando per leggere la temperatura
  Wire.beginTransmission(SENSOR_ADDR);
  Wire.write(COMMAND);
  Wire.endTransmission();

  delay(100);  // Attende la risposta del sensore

  // Legge i 7 byte dal sensore
  Wire.requestFrom(SENSOR_ADDR, 7);

  if (Wire.available() == 7) {
    // Legge i byte e li memorizza nell'array
    for (int i = 0; i < 7; i++) {
      data[i] = Wire.read();
    }

    // Calcola la temperatura dell'oggetto (Bytes 1-3)
    uint32_t objectTempRaw = ((uint32_t)data[1] << 16) | ((uint32_t)data[2] << 8) | data[3];
    objectTemp = (objectTempRaw / 16777216.0) * 130.0 - 20.0;

    // Calcola la temperatura ambiente (Bytes 4-6)
    uint32_t ambientTempRaw = ((uint32_t)data[4] << 16) | ((uint32_t)data[5] << 8) | data[6];
    ambientTemp = (ambientTempRaw / 16777216.0) * 105.0 - 20.0;
  }
}

Ho sistemato il codice così e sembra funzionare, appena puoi dagli un'occhiata e dimmi se mi sfugge qualcosa

Allora, come sospettavo, il problema è dovuto alla promozione implicita ad un tipo di dati più grande.
Nel dettaglio il risultato di (byte0 << 16) viene implicitamente promosso al tipo dati int, ma nella piattaforma Arduino il tipo dati int occupa solo 2 byte che sono ancora insufficienti per eseguire correttamente lo shift.

La soluzione è fare un casting esplicito promuovendo le variabili ad un tipo di dati corretto per l'operazione da eseguire.

Contro-verifica:

@cotestatnt:

... di nuovo a rispondere ad un utente che non si è presentato ??? :rage:

Vogliamo verificare nell'attività di OGNI utente prima di rispondere?

Grazie.

Guglielmo

@alby23mod

Benvenuto nella sezione Italiana del forum,

cortesemente, come prima cosa, leggi attentamente il REGOLAMENTO di detta sezione, (... e, per evitare future possibili discussioni/incomprensioni, prestando molta attenzione al punto 15), dopo di che, come da suddetto regolamento (punto 16.7), fai la tua presentazione NELL'APPOSITA DISCUSSIONE (... quello che vedi in blu è un link, fai click su di esso per raggiungere la discussione) spiegando bene quali esperienze hai in elettronica e programmazione, affinché noi possiamo conoscere la tua esperienza ed esprimerci con termini adeguati.

Grazie,

Guglielmo