ESP32 (24) – I2C un esempio pratico con sensore HTU21D

luca 13/10/2017 0

Nel precedente tutorial vi ho mostrato l’utilizzo del driver I2C incluso nel framework esp-idf per far comunicare il chip esp32 con dispositivi I2C. Oggi vedremo un esempio pratico: l’utilizzo di un sensore temperatura/umidità.

Il sensore

Per questo tutorial ho scelto di utilizzare il sensore HTU21D di Te Connectivity. Questo sensore offre una buona accuratezza ed è disponibile già saldato su una breakout board ad un costo di pochi euro:

htu21d-00a htu21d-00b

htu21d-00c

Sparkfun è stato il primo produttore ad offrire una board basata su tale sensore… sebbene ora il prodotto sia retired, board simili si trovano in vendita su diversi siti (es. Banggood).

Per collegarlo alla scheda di sviluppo esp32 dobbiamo per prima cosa scegliere quali pin del chip esp32 utilizzare per i segnali SDA e SCL. Oltre a tali segnali, dobbiamo collegare VDD (3.3V) e GND:

htu21d-00d htu21d-00e

htu21d-00f htu21d-00g

Datasheet e comandi

Una volta realizzati i collegamenti fisici tra la scheda di sviluppo esp32 e il sensore, dobbiamo capire come scrivere un programma che interagisce con esso. La prima cosa da fare è sicuramente leggere il datasheet del sensore (qui il documento in PDF). Non spaventatevi se aprendo il documento vedete 21 pagine di specifiche tecniche, nei prossimi paragrafi vi spiegherò quali sono le informazioni fondamentali che ci servono!

A pagina 10 inizia il capitolo relativo al protocollo di comunicazione (COMMUNICATION PROTOCOL WITH HTU21D(F) SENSOR). Subito leggiamo che il sensore offre una interfaccia I2C slave con indirizzo 0x40; appena sotto è riportata anche la tabella con i comandi disponibili:

htu21d-001

Vi sono due diverse modalità per misurare temperatura e umidità:

  • hold master
  • no hold master

Nella prima modalità, il sensore blocca il segnale di clock (SCK) durante la misurazione: in questo modo il master può inviare il comando di lettura solo quando la misurazione è effettivamente terminata. Nella seconda modalità invece il master può effettuare altre operazioni sul bus (es. interrogare un altro sensore) durante la fase di misurazione.

In modalità no hold il master, dopo aver inviato il comando di “trigger maesurement”, deve attendere che il sensore termini la misurazione prima di leggere il valore. E’ possibile verificare se la misurazione è completata inviando al sensore un comando di read e attendendo l’ACK: se questo viene ricevuto, significa che il dato è disponibile.

Il sensore restituisce il dato in forma grezza (raw) come valore a 16bit (= 2 bytes). In aggiunta al dato, viene anche restituito un valore (1 byte) di checksum; tale valore consente al master di verificare che non vi siano stati errori di trasmissione.

Nel precedente articolo abbiamo già imparato come interrogare un dispositivo slave; per leggere la temperatura dal sensore HTU21D in modalità no hold le istruzioni da utilizzare sono quindi:

// constants
#define HTU21D_ADDR			0x40
#define TRIGGER_TEMP_MEASURE_NOHOLD  	0xF3
 
// send the command
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, TRIGGER_TEMP_MEASURE_NOHOLD, true);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
 
// wait for the sensor (50ms)
vTaskDelay(50 / portTICK_RATE_MS);
 
// receive the answer
uint8_t msb, lsb, crc;
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &msb, 0x00);
i2c_master_read_byte(cmd, &lsb, 0x00);
i2c_master_read_byte(cmd, &crc, 0x01);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);

Il codice di esempio attende 50ms prima di leggere il dato: dal datasheet si legge infatti che il tempo massimo di misurazione è proprio 50ms per il valore di temperatura alla massima risoluzione:

htu21d-002

Per convertire il valore raw nel valore reale di temperatura (in °C) o di umidità (in %) è possibile utilizzare le formule presenti nel datasheet:

uint16_t raw_value = ((uint16_t) msb << 8) | (uint16_t) lsb;
float temperature = (raw_value * 175.72 / 65536.0) - 46.85;
float humidity = (raw_value * 125.0 / 65536.0) - 6.0;

Risoluzione

Il sensore offre 4 diverse combinazioni di risoluzione per temperatura e umidità:

  • umidità 12bit, temperatura 14bit
  • umidità 8bit, temperatura 12bit
  • umidità 10bit, temperatura 13bit
  • umidità 11bit, temperatura 11bit

E’ possibile cambiare la risoluzione modificando il valore di un registro di configurazione, con il comando write user register. In particolare i bit del registro da modificare sono il bit 0 e il bit 7:

htu21d-003

CRC

L’algoritmo per la verifica del valore di CRC è illustrato nel datasheet.

Il polinomio utilizzato è x^8 + x^5 + x^4 + 1 che in binario diventa:

htu21d-004

A tale polinomio vanno aggiunti degli zeri in base al numero di bit del CRC:

htu21d-005

Il valore ottenuto, in esadecimale, è 0x98800.

Al dato da verificare, viene aggiunto in coda il valore di CRC ricevuto come terzo byte dal sensore:

uint32_t row = (uint32_t)value << 8;
row |= crc;

Quindi si verifica il valore del bit che corrisponde alla posizione più a sinistra del polinomio divisore: se tale bit è uguale a 1, il dato da verificare viene XORato con il divisore. Infine il divisore è spostato a destra di una posizione:

for (int i = 0 ; i < 16 ; i++) {
 if (row & (uint32_t)1 << (23 - i)) row ^= divisor;  divisor >>= 1;
}

Se il valore residuo di row è uguale a zero, il CRC è validato.

Componente

Ho sviluppato un componente per il framework esp-idf che implementa quando spiegato in questo articolo. Il componente è disponibile su Github e la documentazione sul suo utilizzo è pubblicata in una pagina ad esso dedicata.

Ecco un filmato che mostra il suo funzionamento (sono disponibili i sottotitoli in italiano):

Leave A Response »

Questo sito usa i cookie per poterti offrire una migliore esperienza di navigazione maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi