Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Arduino, scrivere il primo driver

Collegare un sensore e realizzare il "driver" da utilizzare in tutte le applicazioni per sfruttare i valori rilevati dal mondo esterno.
Collegare un sensore e realizzare il "driver" da utilizzare in tutte le applicazioni per sfruttare i valori rilevati dal mondo esterno.
Link copiato negli appunti

Per entrare a pieno titolo nell'Internet of Things, sfruttiamo il collegamento a Internet di Arduino (che abbiamo esaminato nelle lezioni precedenti) per realizzare una applicazione che ci permetta di trasmettere online il valore della temperatura rilevata nella nostra stanza.

Questo semplice sistema prevede una parte strettamente embedded che implementeremo subito e una parte di connessione al Cloud che affronteremo in seguito (nelle prossime lezioni).

Collegare il sensore di temperatura

Il primo passo è quello di procurarci un buon sensore di temperatura da poter collegare alla board. Esistono numerosi sensori di questo tipo, sia analogici che digitali, ma uno di quelli maggiormente utilizzati è il TMP102 della Texas Instruments. Questo componente fornisce un'interfaccia I2C (Inter Integrated Circuit) ossia una seriale sincrona caratterizzata dai soli due segnali:

Segnale Descrizione
SDA (Serial DAta) Per il trasferimento dati
SCL (Serial CLock) Per il clock

Non è possibile approfondire in questa sede le caratteristiche del protocollo I2C ma è necessario sapere che sullo stesso bus possono essere collegati più device e che il master decide con chi stabilire la comunicazione semplicemente trasmettendo il relativo indirizzo sulla linea SDA.

Ovviamente, nella nostra configurazione, Arduino assume il ruolo di master (che quindi genera anche il segnale di clock) ed il TMP102 funge da slave, ricevendo le richieste e fornendo le relative risposte.

Dal punto di vista hardware, inoltre, sono necessarie due resistenze di pull-up in corrispondenza delle due linee, necessarie per mantenere il segnale alto (1 logico) nello stato di idle; viceversa, il master o lo slave hanno il compito di abbassare il segnale per trasferire il valore logico 0.

Per semplificarci la vita, possiamo acquistare un breakout board sulla quale è disponibile il sensore e tutti gli altri componenti necessari al suo funzionamento; possiamo trovarla sul sito della Sparkfun).

Breakout board con il sensore TMP102

Breakout board con il sensore TMP102

La connessione alla board "Arduino Uno" è relativamente semplice: basta ricordare che il pin analogico 4 corrisponde all'SDA ed il pin analogico 5 all'SCL. Inoltre, l'alimentazione V+ della breakout board va collegata al pin che fornisce la tensione di 3.3 V e la massa al corrispondente pin di GND.

Infine, il sensore ha l'ulteriore pin ADD0 che serve a stabilire l'indirizzo del sensore stesso su un bus I2C (qualora volessimo collegarne più di uno). Colleghiamo il pin ADD0 alla massa (GND) dell'Arduino in modo che l'indirizzo diventi 0x48 (valore esadecimale). Tale informazione è disponibile sul datasheet del sensore stesso.

Utilizzando il tool Fritzing, già visto nelle lezioni precedenti, possiamo "disegnare" il circuito in modo da averlo a portata di mano nel momento della realizzazione:

Sensore TMP102 collegato alla board


Sensore TMP102 collegato alla board

Realizzare il "driver"

Dopo aver superato lo "scoglio" hardware, passiamo alla realizzazione di un semplice driver per utilizzare il sensore. Per driver intendiamo una libreria Arduino che contenga al suo interno tutta la logica necessaria per accedere al componente, definendo un livello di astrazione con l'applicazione che ne fa uso.

Il nostro obiettivo è quello di mettere a disposizione una semplicissima funzione getTemperature() che ritorni il valore di temperatura acquisito dal sensore, nascondendo tutte le azioni necessarie. In questo modo, nel realizzare le applicazioni, possiamo ignorare la modalità di accesso al sensore (che in questo caso usa il bus I2C) e riusare la libreria senza riscrivere codice.

Ci serviamo della programmazione a oggetti (OOP) e definiamo una classe Tmp102 che rappresenti il sensore ed esponga l'unico metodo getTemperature(). Creiamo quindi due file:

File Descrizione
Tmp102.h Il cosiddetto file "header", in cui dichiariamo la classe e la sua interfaccia verso l'esterno
Tmp102.cpp File che contiene la logica implementativa della classe

Nel nostro caso la classe è abbastanza semplice: contiene solo il costruttore e la dichiarazione del metodo per la lettura della temperatura. Inoltre, l'header file contiene la definizione dell'indirizzo per l'accesso al sensore (TMP_102_ADDRESS) e include l'header file "Arduino.h" con tutte le dichiarazioni standard dei tipi e delle costanti supportate dalla piattaforma Arduino. Infine, l'utilizzo della "guardia" TMP_102 serve per evitare inclusioni e dichiarazioni ricorsive all'interno di più file sorgenti.

/** File: Tmp102.h */
#ifndef TMP_102
#define TMP_102
#include <Arduino.h>
#define	TMP_102_ADDRESS	0x48 // indirizzo sensore (pin ADD0 a GND)
class Tmp102
{
public:
	Tmp102();
	float getTemperature();
};
#endif

L'implementazione della classe includerà sia l'header file corrispondente (Tmp102.h), sia l'header file "Wire.h" che ci permette di utilizzare tutte le funzioni della libreria Wire per l'accesso ai device I2C/TWI. Tale libreria espone una serie di funzioni che astraggono completamente l'utilizzo del bus I2C e che si preoccupano di eseguire tutte le operazioni di basso livello per poter leggere e scrivere da/verso un device.

La classe Tmp102 ha un costruttore praticamente vuoto in quando non sono necessarie particolari inizializzazioni per utilizzare il sensore ed ha il metodo getTemperature() che esegue nell'ordine le seguenti operazioni:

  • utilizza Wire.requestFrom(TMP_102_ADDRESS, 2) per fare una richiesta di ricezione dati sul bus I2C dal device il cui indirizzo è il primo parametro (nel nostro caso TMP_102_ADDRESS); il secondo parametro indica il numero di byte da leggere;
  • esegue due volte il metodo Wire.read() per leggere i byte richiesti dal bus;
  • dai due byte suddetti (MSB, Most Significative Byte e LSB, Last Significative Byte) ricava il valore intero a 12 bit che rappresenta il valore della temperatura secondo le specifiche del sensore TMP102 e che sono disponibili nel corrispondente datasheet;
  • converte il valore intero suddetto nella corrispondente temperatura in gradi centigradi (Celsius) e lo restituisce al chiamante;

// Metodo che ritorna la temperatura dal sensore
float Tmp102::getTemperature()
{
	// richiesta di lettura di 2 byte
	// dal device I2C con indirizzo TMP_102_ADDRESS
	Wire.requestFrom(TMP_102_ADDRESS, 2);
	// lettura dei due byte (più e meno significativo)
	byte MSB = Wire.read();
	byte LSB = Wire.read();
	// valore intero 12 bit ricavato dal sensore
	int tempValue = ((MSB << 8) | LSB) >> 4;
	// conversione in gradi centigradi
	float celsius = tempValue * 0.0625;
	return celsius;
}

Una volta completata la libreria non ci resta che utilizzarla in uno sketch di esempio!

Creiamo una sottocartella "Tmp102" nella cartella "libraries" dell'IDE di Arduino e copiamo al suo interno i due file che abbiamo creato. Rilanciando l'IDE, vedremo apparire la nostra libreria tra quelle di esempio in Sketch > Import Library ..." e, cliccando su di essa, l'ambiente aggiungerà per noi la direttiva di include del file "Tmp102.h" in testa al nostro sketch per poter utilizzare la libreria.

Libreria Tmp102 disponibile tra quelle di Arduino

Libreria Tmp102 disponibile tra quelle di Arduino

Il nostro sketch è relativamente semplice, in quanto non fa altro che utilizzare un'istanza della classe Tmp102 per poter leggere continuamente il valore di temperature ed inviarlo al PC attraverso il collegamento seriale che abbiamo già utilizzato nei capitoli precedenti.

Nella funzione setup() abbiamo l'inizializzazione della porta seriale ma soprattutto l'inizializzazione del bus I2C attraverso il metodo Wire.begin(): grazie a quest'ultimo la libreria Wire viene inizializzata in modo tale che l'Arduino assuma il ruolo di master sul bus.

È da sottolineare che questa operazione viene eseguita nello sketch e non nella libreria, in quanto tale azione va eseguita una ed una sola volta. Se utilizzassimo più librerie per device che fanno uso del bus I2C e ciascuna di queste librerie chiamasse al suo interno la Wire.begin(), avremmo un'invocazione multipla di quest'ultima.

#include <Wire.h>
#include "Tmp102.h"
// dichiarazione oggetto Tmp102
Tmp102 tmp102;
void setup(){
  Serial.begin(9600);
  Wire.begin();
}
void loop(){
  // lettura e trasmissione della temperatura
  float celsius = tmp102.getTemperature();
  Serial.print("Celsius : ");
  Serial.println(celsius);
  delay(1000);
}

Completato il nostro sketch possiamo verificarne la sintassi, compilarlo ed eseguirlo sulla nostra board Arduino. Lanciando il "Serial Monitor", possiamo visualizzare in tempo reale i valori ricevuti a seguito delle letture continue (ogni secondo) della temperatura nella nostra stanza.

Serial Monitor con i valori di temperatura ricevuti da Arduino


Serial Monitor coi valori di temperatura ricevuti da Arduino

Abbiamo posto le basi per la prossima parte in cui vediamo come inviare il valore della temperatura della nostra stanza nel Cloud, facendo rientrare di fatto il nostro sistema Arduino nel vasto mondo dell'Internet of Things!

Ti consigliamo anche