Scheda acquisizione dati - Parte Software

E dopo aver realizzato la scheda di acquisizione dati, bisogna scrivere qualche riga di codice; Il programma deve:

  • Leggere il dato convertito, un bit dopo l'altro (comunicazione tipo seriale)
  • Unire tutti i singoli bit formando una parola da 12bit
  • Convertire la parola in un numero decimale
  • Moltiplicare il numero per un opportuno fattore di scala

Comunicazione via SPI

La comunicazione tra l'ADS7816 ed il Raspberry, avviene tramite bus SPI. Sono disponibili acquisizione dati via SPIvarie librerie (anche in python) per gestire la comunicazione in questa modalità, come la py-spidev; purtroppo tutte hanno documentazione quasi nulla, gli esempi in giro per la rete sono pochi e sempre con le stesse periferiche (MCP3008 o 3002), rendendo laborioso anche un po' di sano reverse engineering. Così ho deciso di includere direttamente nel programma una funzione che si occupi di leggere i dati via SPI. La base di partenza è il diagramma temporale dell'ADS7816, reperibile sul datasheet, da cui si evince la sequenza che dovrà eseguire il Raspberry per ottenere la lettura:

  • Portare il pin CS a livello basso
  • Effettuare 2 cicli di clock a vuoto (durante i quali avviene l'acquisizione)
  • Leggere il bit (il primo è null, per indicare l'inizio dell'invio)
  • Effettuare un altro ciclo di clock per passare al bit successivo
  • Leggere il bit e proseguire così fino all'ultimo
  • Portare CS a livello alto per terminare la comunicazione

Listato python

Il programma è il seguente:

import time
import os
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)

#funzione che legge il dato dal bus SPI per l'ADS7816

def readadc(clock, miso, cs):
GPIO.output(cs, True) #pone CS a 1 per bloccare la partenza
GPIO.output(clock, False) #pone il clock a livello basso
GPIO.output(cs, False) #pone cs a livello basso: inizia la conversione

GPIO.output(clock, True)
GPIO.output(clock, False) #ciclo per effettuare la conversione ADC

adcres = 0 #inizializzazione variabile contenente valore

#si comincia la lettura vera e propria
for i in range(13): #un bit di null e 12bit per il dato
GPIO.output(clock, True)
GPIO.output(clock, False) #ciclo per passare al dato successivo
adcres <<= 1
if (GPIO.input(miso)):

adcres |= 0x1 #se il bit è positivo incrementa il valore
GPIO.output(cs, True) #alza cs per terminare l'invio
adcres /= 2 #taglia il bit null
return adcres

#inizializza i pin dell'SPI
GPIO.setup(21, GPIO.IN)  #miso
GPIO.setup(23, GPIO.OUT) #clock
GPIO.setup(24, GPIO.OUT) #cs 0

#fa partire la conversione vera e propria richiamando la funzione
while True:
adcacq = readadc(23, 21, 24)
voltage = adcacq * (5 / 4096)
print(voltage, 'V')
time.sleep(5)

Caricate le librerie necessarie, e definito il modo di assegnazione dei pin GPIO (board: i numeri nel programma si riferiscono direttamente alla posizione sul connettore GPIO) si definisce subito la funzione readadc, che pone a livello alto CS (per evitare partenze), a livello basso il clock e a livello basso CS (per cominciare la conversione). Un primo ciclo diacquisizione dati, risultati clock (visto che la conversione ne richiede 2) viene eseguito immediatamente, quindi si entra in un ciclo con 13 iterazioni: 1 dovuta al bit null e 12 per i restanti dati. Questo ciclo compone il dato bit per bit, controllando se il valore, assunto dall'uscita del convertitore, è 1 o 0. Al termine della lettura si esclude il primo bit (perché è quellodi null) e la funzione restituisce il valore della misura. Ora che è stata definita la funzione, si inizializzano anche le porte del Raspberry. Quindi si entra in un loop infinito che ogni 5 secondi richiama la funzione e moltiplica il valore risultante per 5/4096, il peso di ogni bit nel complesso. Quindi viene stampato il risultato (come in figura). Da ricordarsi che il programma, agendo sui GPIO, va eseguito con privilegi di root.

Il programma in python è disponibile anche qui (.zip)