Risorse per il Lab. Elettronica
Home Page


CAD/CAE

LTspice

PSpice


Sistemi

Arduino

AVR

Raspberry Pi

National Instruments


Risorse

Datasheet

Link

Hardware e Software

Misc




Programmare il GPIO di Raspberry Pi in C (beta)







Licenza Creative Commons
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Italia. E' dunque escluso l'utilizzo per scopi di lucro . Autore: Francesco Parisi, fparisi AT gmail DOT com



Ultima modifica: 09/08/2021

Misura di una temperatura mediante ADC

Di seguito verrà descritta una semplice applicazione del Raspberry: la misura di una temperatura mediante un sensore analogico.

L'hardware



La Raspberry Pi non è dotata di un proprio convertitore A/D, quindi, per l'acquisizione di una tensione analogica occorre usarne uno esterno e interfacciarlo al GPIO. Per lo scopo viene usato un convertitore molto diffuso, l'ADC0831 prodotto dalla National Semiconductor (Texas Instruments). Le caratteristiche tecniche salienti di questo dispositivo sono:
  • Alimentazione: 5V
  • Tecnologia: SAR
  • Risoluzione: 8-bit
  • Interfaccia di uscita: seriale
  • Velocità di conversione: 31,25 KSPS (con fck=250 kHz)
  • TUE, Total unadjusted error: +/- 1LSB


L'ingresso Vin- può essere utilizzato per definire l'estremo inferiore del range di ingresso e quindi ridurre la dinamica del convertitore, applicando una tensione maggiore di 0V. Il dato convertito viene prelevato serialmente dall'uscita DO. L'ingresso \CS (Chip Select) se portato a livello logico 0 (0V) abilita il convertitore dando inizio alla conversione; se posto a livello logico 1 (+5V), disabilita lo stesso riducendo così i consumi.
All'ingresso CLK va applicato il segnale di clock e a VREF, la tensione di riferimento desiderata che, come visto sopra, definisce la dinamica di ingresso del convertitore ovvero lo span. Il principio di funzionamento di questo convertitore A/D è molto semplice è può essere interpretato analizzando il diagramma temporale:


La conversione viene avviata mandando a livello 0 la linea di abilitazione del dispositivo (CS: chip select). Il primo impulso di clock produrrà in uscita un bit non significativo che viene quindi scartato. Al secondo impulso di clock, sull'uscita DO sarà presente il bit D7 del codice, quello più significativo (MSB); al terzo impulso di clock verrà inviato in uscita il bit D6 e così via fino al nono colpo di clock che metterà in uscita D0, il bit meno significativo (LSB) del dato. Terminata la conversione, l'ADC viene messo in stand-by, riponendo la linea CS a livello logico alto fino alla prossima conversione.


Per la misura della temperatura viene usato un LM35DZ. L'LM35DZ è un sensore analogico di temperatura che non richiede calibrazione. Esso fornisce una tensione di uscita di 0V a 0 °C e di 10mV per ogni grado Celsius rilevato, nel range 0...100°C ; la corrispondenza fra tensione e temperatura è lineare; la sua accuratezza tipica è di ± 0,4°C (garantita ± 1,5°C) in condizione di temperatura ambiente a 25°C. La tensione di riferimento è costituira da un riferimento di tensione da 1,2V (LM385-1.2) ; ciascun intervallo di quantizzazione (1LSB) avrà quindi un'ampiezza (teorica) di :


a cui corrisponderanno circa 0,5 °C:


Un possibile circuito per la misura di una tipica temperatura ambientale interna (che sia superiore ai 0°C) mediante un ADC è mostrato in figura:


L'ADC è stato collegato al GPIO sfruttando le tre linee della comunicazione SPI: MOSI, MISO, SCLK, rispettivamente per le linee CS, DO e CLK.
Il partitore resistivo serve ad abbassare il livello alto dell'ADC0831 (intorno ai 5V) a un valore prossimo ai 3,3V, che rappresenta la tensione interpretata dal Raspberry come un ingresso a livello logico 1.; diversamente si corre il rischio di danneggiare la porta.

Il software



Il software (file: mistemp.c, mistemp.h) è stato scritto in C con WiringPi. Esso si occupa di leggere il dato dell'ADC, di convertirlo in decimale (funzione leggiN()) e quindi interpretarne il risultato come temperatura, mediante la funzione leggiTemp(). La funzione leggiN() implementa la sequenza temporale di segnali di controllo e di clock (bit-banging), necessaria per la lettura del dato dall'ADC0831, mentre la funzione leggiTemp() esegue una lettura ripetuta della temperatura (tramite il valore specificato dall'etichetta simbolica NLETTURE) al fine di ottenere la migliore stima di questa.

MISTEMP.H
#define DO_PIN   13    // WPi13, MISO/GPIO9
#define CLK_PIN  14    // WPi14, SCLK/GPIO11
#define CS_PIN   12    // WPi12, MOSI/GPIO10
#define VREF     1.2   // Vref usata
#define NLETTURE 10    // Numero letture ripetute
#define TDELAY   0.002 // Semiperiodo in ms di Tclock

#include "wiringPi.h"
#include <stdio.h>

void init(void);
void ADC_clock(void);
unsigned char leggiN(void);
double leggiTemp(void);

MISTEMP.C
#include "mistemp.h"

/* Inizializza hw Raspberry */
void init(void){
   wiringPiSetup();
   pinMode(DO_PIN, INPUT);
   pinMode(CLK_PIN, OUTPUT);
   pinMode(CS_PIN, OUTPUT);
}

/* Invia un impulso di clock di periodo 2 x TDELAY */
void ADC_clock(void) {
   digitalWrite(CLK_PIN, 1); // Manda 3,3V su CLK_PIN
   delay(TDELAY);
   digitalWrite(CLK_PIN, 0); // Manda 0V su CLK_PIN
   delay(TDELAY);
}

/* Effettua la conversione A/D e ritorna il dato N */
unsigned char leggiN(void) {
   unsigned char dato=0;   /* Dato dell'ADC */
   int j;                  /* Contatore di ciclo */

   digitalWrite(CS_PIN, 0);     /* Abilita ADC */
   ADC_clock();                 /* Primo clock “a vuoto” */

   /* Legge il dato e lo converte in decimale */
   for (j=7; j>=0; j--) {
     ADC_clock();
     if (digitalRead(DO_PIN)==1)   /* Se DO=1 */
       dato |= (1<<j);             /* aggiungi relativo peso 2^j */
   }

   digitalWrite(CS_PIN, 1);        /* Disabilita ADC */
   return dato;
}

/* Interpreta il dato N come temperatura */
double leggiTemp(void){
   double temp = 0.0;        /* Lettura singola */
   unsigned char dato;       /* Dato letto dall'ADC */
   int j;                    /* Contatore di ciclo */
   
   /* Lettura ripetuta */
   for (j=0; j<NLETTURE; ++j) {
      dato = leggiN();
      temp += (dato * 100.0 * VREF) / 256.0;  
      delay(0.05);
   }
   return (temp/NLETTURE);  /* Ritorna il valore medio */
}

int main(void) {
   init();  /* Inizializza l'hw */
   printf ("%.1f\n", leggiTemp() );
   return 0;
}

Per la compilazione/esecuzione del programma si rimanda alla relativa pagina.

Una semplice applicazione



L'esempio appeno visto è stato usato per la misura periodica di una temperatura, con memorizzazione del dato su un database remoto. Un utente, quindi, visualizza le temperatura misurate, aggregate in un grafico di una pagina web, nell'arco temporale desiderato (ultima ora, ultime 24h ecc). La topologia è "on premises" ossia un computer gateway in loco (il Raspberry Pi collegato a internet mediante un modem/router ADSL) che raccoglie i dati provenienti da un nodo e li invia a un database remoto, a intervalli di tempo regolari. Le tecnologie web impiegate sono HTML , CSS, Javascript per il lato client (interfaccia utente) e PHP per il lato server, che cura l'interazione con il DBMS-R MySQL (interrogazione e inserimento di dati). L'applicazione web segue i principi REST, tranne quello dell'accesso alle risorse mediante URI: uso del metodo POST per l'inserimento di una nuova temperatura e del metodo GET per la lettura delle temperature già acquisite; stateless: tutte le informazioni necessarie al server vengono veicolate nelle richieste; uso del formato JSON per lo scambio dei dati. Di seguito alcuni schemi e immagini dell'applicazione.





Schema a blocchi dell'applicazione



Schema a blocchi dell'implementazione



La visualizzazione del grafico nel browswer web






Informativa estesa sui Cookie | Web Statistics

Clicky

| Realizzazione a cura di Francesco Parisi (2002 ÷ 2024) | Contatti