• Non ci sono risultati.

Università degli Studi di Padova Facoltà di Ingegneria Corso di Laurea in Ingegneria Elettronica Registratore di dati per dispositivi di accumulo energetico

N/A
N/A
Protected

Academic year: 2021

Condividi "Università degli Studi di Padova Facoltà di Ingegneria Corso di Laurea in Ingegneria Elettronica Registratore di dati per dispositivi di accumulo energetico"

Copied!
63
0
0

Testo completo

(1)

Università degli Studi di Padova

Facoltà di Ingegneria

Corso di Laurea in Ingegneria Elettronica

Registratore di dati per dispositivi di

accumulo energetico

Laureando Relatore

Dario Marchetto

Prof. Simone Buso

Correlatore

Ing. Marco Stellini

(2)
(3)

Indice

1 Obiettivo del progetto 1

1.1 Il sistema di accumulo energetico . . . 1

2 Sezione Hardware 3 2.1 Alimentazione . . . 4

2.2 La scheda Arduino Uno . . . 4

2.3 La scheda Arduino Ethernet Shield . . . 6

2.4 I trasduttori di tensione e corrente . . . 7

2.5 Il sensore di temperatura . . . 11 2.6 Il bus I2C . . . 12 2.6.1 Il modulo RTC . . . 13 2.6.2 Il convertitore A/D MCP3221 . . . 14 3 Sezione Software 15 3.1 Il rmware . . . 15 3.1.1 La memoria microSD . . . 15 3.1.2 La comunicazione Ethernet . . . 18 3.1.3 La comunicazione I2C . . . 21

3.1.4 L'interrupt temporizzato e l'acquisizione dei dati . . . . 25

3.1.5 Il Watch Dog Timer . . . 27

3.2 Le pagine Web . . . 28 3.2.1 La pagina index.htm . . . 29 3.2.2 La pagina tabella.htm . . . 29 3.2.3 La pagina graco.htm . . . 29 3.2.4 La pagina RTC.htm . . . 31 3.2.5 La pagina le.htm . . . 32

4 La stima dello Stato di Carica 35 4.1 Il comportamento delle batterie . . . 35

4.2 Lo stato di carica . . . 36

(4)

iv INDICE

5 Conclusioni 43

5.1 Possibili sviluppi futuri . . . 44

6 Sorgente completo in C 47

(5)

Capitolo 1

Obiettivo del progetto

Questa tesi riguarda la realizzazione di un dispositivo per l'acquisizione dei dati ed il monitoraggio di un sistema di accumulo energetico presente nel Dipartimento di Ingegneria dell'Informazione.

Il suddetto sistema di accumulo si basa su un gruppo di batterie che pos-sono venire caricate e scaricate, simulando il comportamento di un generico utilizzatore.

Il sistema di acquisizione ha il compito di acquisire periodicamente e registrare su un supporto di memoria FLASH (scheda microSD) i dati salienti che caratterizzano lo stato di accumulo energetico, e di fornire una stima dello stato di carica delle batterie.

Inoltre il sistema assume anche la funzione di Web Server, fornendo all'utente nale (Client) la possibilità di accedere ai dati acquisiti tramite una connessione Internet, usando un browser Web.

Da qui in poi si farà riferimento ad un `record' per indicare l'insieme dei dati acquisiti dal sistema in un certo istante: ogni record è costituito dalla tensione, dalla corrente, dalla temperatura e dallo stato di carica delle batterie, oltre che ad una `etichetta temporale' che associa univocamente il record al preciso istante in cui viene salvato.

1.1 Il sistema di accumulo energetico

L'energia elettrica viene accumulata in 21 batterie al piombo da 12 Volt connesse in serie, modello 12HX135 prodotto dalla EnerSys. Ogni singola batteria è costituita da 6 celle ed ha una capacità nominale pari a 28 Ah.

(6)

disposizio-2 CAPITOLO 1. OBIETTIVO DEL PROGETTO ne una riserva di energia da fornire ad apparecchi elettrici di emergenza, nel caso l'ente fornitore dell'energia elettrica ne sospendesse temporaneamente l'erogazione (questo è proprio quello che fanno i gruppi di continuità, o UPS). Le batterie al piombo (singole o connesse in gruppo) sono tuttora il mez-zo più diuso che viene utilizzato per questi scopi, nonostante la relativa-mente bassa potenza per unità di volume che riescono ad erogare; un loro fondamentale pregio è il basso costo e la potenza che possono erogare.

(7)

Capitolo 2

Sezione Hardware

Il sistema di acquisizione progettato deve acquisire la tensione, la corrente e la temperatura istantanee del banco di batterie in esame, e fornire i dati di misura agli utenti che ne fanno richiesta: lo schema di principio su cui si basa è mostrato in gura 2.1.

(8)

Vengono ora descritte separatamente le varie parti hardware che compon-gono il sistema.

2.1 Alimentazione

Si è deciso di alimentare il sistema connettendolo alle batterie stesse, le quali sono connesse in serie senza la possibilità di accedere ai loro morsetti, ad eccezione che per i due alle estremità della serie: con le batterie a piena carica ai loro capi si trova una tensione intorno ai 280 Volt.

Adottando un convertitore di tensione switching isolato (per motivi di sicurezza), che supporti questo valore di tensione di ingresso, la tensione totale viene ridotta a quella richiesta dal sistema di misura.

La scelta del tipo switching è stata obbligata dal vincolo di ottenere un basso assorbimento di potenza per alimentare il sistema; l'alta ecenza dei convertitori a commutazione consente infatti di raggiungere basse perdite.

La scelta è ricaduta sul modello TMP10212, prodotto dalla TracoPo-wer: consente di avere all'ingresso una tensione continua (nel range 120 ÷ 370 V) oppute alternata (nel range 85 ÷ 264 V ), risultando adatto sia come convertitore AC/DC che DC/DC.

Fornisce in uscita i +12 V ed i −12 V riferiti alla stessa massa; inoltre pre-senta una basso valore di ondulazione di tensione (ripple) dichiarato, pari all' 1% della tensione di uscita. Alle sue uscite non vengono perciò aggiunti dei condensatori antidisturbo per stabilizzare meglio la tensione di alimentazione al sistema di acquisizione.

2.2 La scheda Arduino Uno

La scheda Arduino Uno fornisce agli sviluppatori di semplici sistemi embed-ded un veloce strumento di prototipazione, grazie alla discreta potenza di calcolo ed alla possibilità di essere interfacciata con altre schede o sensori (presenta infatti ingressi e uscite analogici e digitali), consentendo la rapida creazione di sistemi relativamente complessi.

Può venire alimentata:

ˆ attraverso la connessione USB;

ˆ fornendo una tensione compresa nel range +7 ÷ +12 V al connettore jack apposito;

(9)

2.2. LA SCHEDA ARDUINO UNO 5 Negli ultimi due casi la tensione di alimentazione (+5 V ) richiesta dal chip ATmega328 viene ricavata attraverso il regolatore di tensione lineare N CP 1117già presente sulla scheda.

In questo progetto viene adottata l'ultima delle tre opzioni; è stato neces-sario interporre tra il convertitore DC/DC e l'ingresso VIN dell'Arduino un

regolatore di tensione lineare L7808 che abbassi la tensione +12 V a +8 V , per evitare i problemi di surriscaldamento del regolatore NCP 1117.

Si ricorda che i regolatori lineari si comportano come dei resistori variabili posti in serie tra una tensione di ingresso ed una di uscita: variando il loro valore di resistenza equivalente, varia anche la caduta di tensione ai loro capi.

Ne risulta che devono dissipare, in calore, una potenza pari a: P = (VIN − VOU T) · IOU T ;

quindi, diminuendo la tensione d'ingresso VIN da +12V a +8V , il

regola-tore NCP 1117 a bordo dell'Arduino deve dissipare circa metà della potenza iniziale, a parità di corrente di uscita.

L'altra metà di potenza viene invece dissipata dal regolatore L7808, ai cui capi si trova una caduta di tensione di 12 V − 8 V = 4 V .

Il cuore dell'Arduino Uno è l'ATmega328, un microcontrollore che lavora alla frequenza di 16 MHz; è un microcontrollore di tipo RISC (Reduced Instruction Set Computer) a 8 bit e si basa sull'architettura Harvard, la quale prevede che la memoria in cui risiede il programma sia sicamente separata dalla memoria di elaborazione (o memoria dati).

Questo implica la coesistenza di due bus, ovvero uno per l'accesso alla memoria dati ed uno per quella programma; il core del microcontrollore può accedere in contemporanea ad entrambe, raggiungendo così prestazioni più spinte rispetto all'architettura Von Neumann (dove esiste un unico bus per l'accesso al programma ed alla memoria dati). Su quest'ultima architettura si basano invece vari microprocessori.

Il microcontrollore esegue quindi il programma salvato sulla propria me-moria interna (di tipo FLASH e ampia 32 kbyte), mentre utilizza per le elaborazioni una memoria SRAM (che ammonta a 2 kbyte); dispone anche di una memoria EEPROM non volatile di 1 kbyte.

Come la quasi totalità dei microcontrollori in commercio, dispone inter-namente di varie periferiche, che consentono di realizzare sistemi completi senza un uso eccessivo di componenti esterni; tra le più importanti ci sono:

ˆ due timer da 8 bit ed uno da 16 bit, ognuno con relativo prescaler; ˆ un convertitore Analogico-Digitale (ADC) single-ended a 10 bit, che

(10)

6 CAPITOLO 2. SEZIONE HARDWARE riferimento di tensione per la conversione può essere impostato sui +5 V (prodotti dal regolatore di tensione con un tolleranza dichiarata dell' 1%), sul riferimento di tensione interno di +1.1 V , o su una tensione di riferimento fornita esternamente sul pin AREF ;

ˆ un modulo per la comunicazione su bus Serial Peripheal Interface (SP I) ed uno per il bus Inter Integrated Circuit (I2C);

ˆ no a sei uscite congurabili in modalità PWM.

L'utilizzo di ogni periferica è reso molto semplice grazie alle svariate librerie di funzioni disponibili.

La programmazione del chip ATmega328 presente sull'Arduino Uno av-viene tramite una connessione seriale; a questo scopo sulla scheda è presente un piccolo microcontrollore (ATmega8U2), programmato in modo da conver-tire la comunicazione USB in una seriale compatibile con i livelli sici dello standard TTL (supportata dall'ATmega328).

Durante il caricamento di un nuovo programma, il chip ATmega8U2 fa la-vorare l'ATmega328 in modalità bootloader, ovvero viene eseguito una parte di rmware speciale (che risiede in una parte di memoria programma dell'AT-mega328 disabilitata alla scrittura) che provvede a ricevere il nuovo program-ma (tramite comunicazione seriale) e a salvarlo in memoria sovrascrivendo quello presente.

Tutto il procedimento di caricamento di un nuovo programma richiede pochi secondi, e viene reso molto semplice dall'interfaccia utente, eseguibile su sistemi operativi Windows, Linux o Mac. La stessa interfaccia utente provvede anche a compilare il codice scritto in linguaggio C.

2.3 La scheda Arduino Ethernet Shield

La scheda Arduino Ethernet Shield è una scheda di espansione che si innesta sui connettori dell'Arduino Uno; consente al microcontrollore dell'Arduino di interfacciarsi con la rete Internet, collegandole un comune cavo Ethernet, e di comunicare con una scheda di memoria microSD, la quale viene inserita nell'apposito slot.

Nella memoria SD risiedono le pagine HTML che costituiscono l'interfac-cia utente del sistema; la scelta di dislocarle sulla memoria di SD, piuttosto che codicarle all'interno del rmware dell'ATmega328, è stata obbligata dalla limitata quantità di memoria dello stesso chip.

(11)

2.4. I TRASDUTTORI DI TENSIONE E CORRENTE 7 Per quanto riguarda la parte relativa alla comunicazione con la rete, la scheda Ethernet Shield monta il controller Ethernet Wiznet W5100, il quale comunica con il microcontrollore dell'Arduino Uno attraverso il bus seriale SP I. Anche la comunicazione con la scheda di memoria microSD viene gestita con il bus SP I, e quindi le due comunicazioni non possono avere luogo contemporaneamente.

La tensione di alimentazione per il chip W5100 viene ricavata dai +5 V dell'Arduino Uno, dopo essere ridotta a +3.3 V da un regolatore di lineare. Il numero di connessioni contemporanee socket massimo supportato è limitato a 4; un socket rappresenta un canale di comunicazione tra un dispo-sitivo Client ed un Server.

2.4 I trasduttori di tensione e corrente

Per acquisire i valori di tensione e corrente sono stati utilizzati due trasdut-tori isolati prodotti dalla LEM. L'isolamento consente di eseguire misure senza entrare in contatto sico con potenziali pericolosi; infatti in questi tra-sduttori il circuito primario di ingresso (collegato al circuito di potenza, sul quale si eettua la misura) ed il circuito secondario di uscita (che fornisce un certo segnale in uscita proporzionale a quello in ingresso a primario) sono elettricamente isolati.

Entrambi i trasduttori usano la tecnologia con sensore ad eetto Hall, che consente di eettuare misure di correnti a partire da quelle di campo magnetico.

Con questo metodo di misura è possibile misurare in modo diretto valori di corrente (e in modo indiretto anche valori di tensione) senza inuenzare minimamente il circuito sotto misura: infatti se è noto il campo magnetico H prodotto dalla corrente I, che scorre in un lo posto ad una distanza r dal punto di misura, è possibile ricavare il valore stesso di corrente secondo la legge di Biot-Savart:

B = µ · H = µ 2π

I

r (2.1)

dove µ = µ0 · µr è la permeabilità magnetica del mezzo in cui viene

misurato il campo magnetico e B è l'induzione elettromagnetica.

(12)

8 CAPITOLO 2. SEZIONE HARDWARE le potenze in gioco in questa applicazione avrebbero portato a perdite e problemi di dissipazione non trascurabili.

Nella pratica della misura, i sensori ad eetto Hall che si possono trovare in commercio, lavorano in modalità ad `anello aperto' o ad `anello chiuso'.

Per eettuare una misura di corrente incognita Ix, che scorre nel

circui-to primario, con la prima modalità si pone una sottile lastra di materiale semiconduttore di spessore d (elemento di Hall) nel traferro di un circuito magnetico; questa lastra viene percorsa longitudinalmente da una corrente di controllo Ic, fornita da un apposito circuito.

La corrente Ix, percorrendo un conduttore avvolto con un certo numero

di spire attorno al circuito magnetico, genera un usso che viene concentrato nel circuito magnetico stesso (grazie alla sua elevata permeabilità) e rilevato dall'elemento di Hall; ai suoi capi si genera una dierenza di potenziale VH

dovuta alla diversa distribuzione dei portatori di carica per colpa del cam-po magnetico H (la forza di Lorentz risulta diretta perpendicolarmente alla direzione dei portatori di carica che compongono la corrente Ic).

La VH, detta `tensione di Hall' in onore del sico statunitense Edwin

Herbert Hall che nel 1879 scopri l'eetto Hall, risulta essere proporzionale alla corrente di controllo Ic e all'induzione elettromagnetica B, ed inversamente

proporzionale allo spessore d, secondo una costante KH che tiene conto delle

proprietà del materiale utilizzato per la lastra: VH = KH

Ic· B

d . (2.2)

Da qui è possibile ricavare il valore di induzione elettromagnetica B, e ricavare successivamente dall'equazione 2.1 il valore della corrente incognita. La modalità ad anello chiuso, invece, si basa sulla compensazione del usso magnetico prodotto dal circuito primario.

Il circuito di partenza di un trasduttore di corrente che lavora ad anello chiuso è lo stesso di quello ad anello aperto, al quale però viene aggiunto un controllo in retroazione.

L' elemento di Hall, inserito nel traferro, risente del usso magnetico ge-nerato dalla corrente IP nel circuito primario e ai suoi capi si genera una

tensione ad essa proporzionale; questa tensione viene convertita in una cor-rente IS, da un circuito di controllo, e viene fornita ad una bobina avvolta

sul circuito magnetico. Si fa in modo che il usso generato dalla IS annulli

quello generato dalla IP.

In questo modo l'andamento della corrente IS insegue quello della IP, a

(13)

2.4. I TRASDUTTORI DI TENSIONE E CORRENTE 9 tra circuito primario e secondario, e dal condizionamento del segnale svolto dal circuito di controllo.

Solitamente i trasduttori di corrente ad anello chiuso orono prestazioni migliori a livello di accuratezza: risultano anche meno inuenzati dalle va-riazioni di temperatura (sono compensati).

Figura 2.2: Trasduttore di corrente ad eetto Hall a catena chiusa Il trasduttore di corrente utilizzato è il circuito integrato LEM FHS 40-P, montato sulla scheda di valutazione KIT 9 (gura 2.4).

Viene alimentato a +5V e fornisce in uscita una tensione nel range +0.5÷ +4.5V, a seconda della corrente in ingresso: la sua uscita assume il valore di 2.5V (pari alla tensione di riferimento Vref interna) quando la corrente è

nulla.

In alternativa, la tensione di riferimento interno può essere impostata dall'esterno, applicando al pin Vref una tensione compresa nell'intervallo 2 ÷

2.8 V.

È possibile porre in modalità standby il LEM FHS 40-P, portando a +5 V il suo pin Standby, per ridurre il consumo di corrente (che in condizioni operative non dovrebbe superare i 19 mA).

È del tipo a `catena aperta' e consente la misura di correnti no a cir-ca ±78A con una sensibilità di 25.8 mV/A (valori dettati dalla geometria costruttiva del KIT 9).

(14)

10 CAPITOLO 2. SEZIONE HARDWARE

Figura 2.3: Struttura interna LEM FHS 40-P

Il trasduttore di tensione utilizzato è il LEM LV 25-P (gura 2.5); è del tipo a `catena chiusa'. Viene alimentato con una tensione duale di ±12 V e consente la misura di tensioni da ±10 no a ±500 V .

Misura indirettamente la tensione grazie ad una resistenza R1 montata

esternamente in serie all'avvolgimento primario, la quale crea la corrente IP

proporzionale alla tensione da misurare VIN; trascurando quindi la resistenza

dell'avvolgimento primario si ottiene: IP =

VIN

R1

Nell'avvolgimento secondario di uscita viene generata una corrente IS ad

essa proporzionale, che dipende dal rapporto di conversione KN = IIS

P =

2500 1000;

una resistenza esterna di misura RM fornisce la tensione di uscita VOU T che

viene poi misurata:

VOU T = RM · IS = RM · KN · IP = RM · KN ·

VIN

R1 (2.3)

Invertendo la 2.3 si ottiene la 2.4, che permette di conoscere il valore di tensione applicata in ingresso a partire dalla misura di quella di uscita:

VIN =

R1

RM · KN

(15)

2.5. IL SENSORE DI TEMPERATURA 11

Figura 2.4: LEM FHS 40-P su

scheda KIT 9 Figura 2.5: LEM LV 25-P

Come specica il datasheet, il valore di R1 deve essere calcolato in modo

da produrre una corrente nominale a primario IPN = 10mA, alla tensione

nominale da misurare. Viene scelto perciò: R1 =

300

0.01 = 30 kΩ.

Per la scelta del valore di RM il datasheet specica che, con una corrente a

primario massima di ±10 mA e alimentazione a ±12 V , non si può andare oltre i 190 Ω: viene scelto il resistore di valore commerciale più prossimo con una tolleranza del 1% , cioè 187 Ω.

2.5 Il sensore di temperatura

È stato necessario collegare all'Arduino anche un sensore di temperatura. Essa produce un eetto diretto di variazione della capacità delle batterie, secondo la tabella riportata dal costruttore (gura 2.6).

(16)

12 CAPITOLO 2. SEZIONE HARDWARE

Figura 2.6: Fattore di correzione della capacità in base alla temperatura

Figura 2.7: Sensore di temperatura LM35

2.6 Il bus I

2

C

Il bus I2C è un bus seriale che consente la comunicazione tra almeno un

dispositivo che viene chiamato MASTER (che gestisce il bus) ed uno SLAVE. Richiede la presenza di due sole linee collegate in comune tra i dispositi-vi che comunicano (chiamate SDA ed SCL), oltre al riferimento comune di massa.

Alla linea di alimentazione, che può essere condivisa da tutti i disposi-tivi, si collegano le due resistenze di pull-up, che in stato di riposo (nessun dispositivo che trasmette) mantengono a livello alto le linee SDA ed SCL.

Ogni dispositivo deve avere un indirizzo univoco che lo identica nel bus. Solo un dispositivo alla volta può comunicare, ed è sempre uno di tipo MASTER che inizia la trasmissione.

Esso fornisce il segnale di clock agli altri dispositivi sulla linea SCL: si tratta quindi di un bus sincrono.

(17)

2.6. IL BUS I2C 13

ˆ lo start è costituito da una transizione da alto a basso della linea SDA mentre SCL è alto;

ˆ lo stop è rappresentato da una transizione da basso ad alto di SDA mentre SCL è alto.

La comunicazione su questo bus può avvenire a diverse velocità, dipenden-temente dalle velocità di trasmissione supportate dai dispositivi: esistono le modalità standard mode (velocità di trasmissione di 100 kbit/s), fast mode (no a 400 kbit/s) e high speed (per collegamenti veloci no a 3, 4 Mbit/s). Il numero massimo di dispositivi che possono essere presenti sullo stesso bus è limitato dai 7 bit riservati all'indirizzo: sono perciò supportati no a 27 = 128 dispositivi connessi contemporaneamente, ognuno con un indirizzo identicativo diverso.

Nella pratica, però, è raro trovare così tanti dispositivi connessi ad un bus I2C perchè un ulteriore limite è costituito dalla capacità massima sopportata

dal bus: 400 pF .

Bisogna quindi dimensionare correttamente le resistenze di pull-up per garantire la corretta propagazione del segnale da un dispositivo all'altro.

2.6.1 Il modulo RTC

Il modulo Real Time Clock (gura 2.8) consente all'Arduino di avere a di-sposizione un riferimento temporale da assegnare ai vari campioni analogici acquisiti. Consiste in una piccola schedina che monta l'integrato DS1307, un orologio/calendario a basso consumo che dialoga con la scheda Arduino sul bus seriale I2C, al quale accede in modalità SLAVE.

Figura 2.8: Modulo RTC con DS1307

(18)

14 CAPITOLO 2. SEZIONE HARDWARE Per poter comunicare con il circuito esterno, l'integrato DS1307 deve essere alimentato da una sorgente di tensione primaria Vcc di +5 Volt, ma

consente di mantenere il conteggio del tempo anche con una sola batteria di backup da 3 Volt (Vbat).

L'integrato DS1307 sceglie automaticamente la sua sorgente di alimenta-zione: seleziona quella primaria se Vcc > Vbat+0.2 V; in questo caso permette

la comunicazione I2C solo se V

cc > 1.25 · Vbatt. Invece, se Vcc < Vbat+ 0.2 V

seleziona la batteria di backup, la quale gli consente di lavorare per svaria-ti anni senza però poter comunicare con il circuito esterno (modalità basso consumo).

2.6.2 Il convertitore A/D MCP3221

Si tratta di un convertitore A/D a 12 bit a basso consumo che comunica in digitale sul bus I2C.

Supporta le modalità di comunicazione standard e fast; nel modo fast, lavorando in acquisizione continua, riesce ad arrivare ad una frequenza di campionamento di 22.3 ksps.

Figura 2.9: Modalità acquisizione singola MCP3221

Come per la comunicazione con il modulo RTC, per iniziare la comuni-cazione con il chip MCP3221 bisogna che il MASTER invii il bit di START seguito dall'indirizzo identicativo 0x4d.

L'acquisizione e la conversione del segnale in ingresso iniziano con il fron-te di discesa del bit R/W ; a questo punto il clock infron-terno inizia la gestio-ne del campionamento e della conversiogestio-ne, indipendentemente dal clock di trasmissione usato sul bus.

(19)

Capitolo 3

Sezione Software

Il software del sistema di acquisizione consiste in una parte di rmware scrit-to in linguaggio C, eseguiscrit-to dall'Arduino, e da una parte composta da pagi-ne Web scritte in linguaggio HTML, che risiedono pagi-nella scheda di memoria inserita nello slot dell'Ethernet Shield.

Le due parti dialogano tra loro scambiandosi dati e/o comandi.

3.1 Il rmware

Un tipico programma Arduino (o sketch) prevede di essere diviso in due funzioni principali: setup() e loop().

La prima contiene tutte le istruzioni che hanno lo scopo di inizializzare il microcontrollore, e per questo viene eseguita una sola volta subito dopo l'accesione (o dopo un evento di RESET hardware o software).

La seconda contiene le istruzioni del vero e proprio programma che l'Ar-duino esegue ciclicamente dopo aver eseguito setup().

Il usso di esecuzione semplicato del rmware dell'Arduino viene rias-sunto nella gura 3.1.

Vengono ora analizzate separatamente le varie funzionalità del rmware, facendo riferimento alle librerie utilizzate.

3.1.1 La memoria microSD

A causa della limitata quantità di RAM del chip ATmega328, la presenza della scheda SD risulta di fondamentale importanza per questo progetto; in mancanza della stessa infatti non sarebbe possibile salvare i risultati delle acquisizioni, ed il rmware si limiterebbe a fornire al Client solamente l'ultimo record presente in memoria.

(20)

16 CAPITOLO 3. SEZIONE SOFTWARE

Figura 3.1: Diagramma di usso del rmware

Come già detto, sia la comunicazione con la scheda di memoria SD che quella con il controller Ethernet avvengono sul bus SP I. Viene perciò usata la relativa libreria SP I.h che ne implementa il protocollo.

La libreria SD.h invece consente di eettuare operazioni di lettura/scrit-tura su schede di memoria con lesystem FAT, con la limitazione di usare nomi dei le compatibili con la convenzione 8.3: si possono cioè gestire so-lamente le il cui nome sia composto al massimo da 8 caratteri di nome ed ulteriori 3 per l'estensione.

Di questa libreria vengono usate le funzioni:

ˆ SD.begin(): provvede ad inizializzare la comunicazione con la scheda e restituisce un valore di tipo boolean pari a true se la scheda è stata rilevata ed inizializzata correttamente, false in caso contrario. Riceve come argomento il numero del pin dell'ATmega328 (pin 4) connesso alla linea Chip Select della scheda;

(21)

3.1. IL FIRMWARE 17 ˆ SD.open(filepath, mode): apre un le presente su scheda in modalità lettura o scrittura e posiziona il puntatore all'inizio del le. Restituisce un oggetto di tipo F ile su cui possono essere eseguite le funzioni di lettura e scrittura;

ˆ SD.close(filepath), chiude un le precedentemente aperto;

ˆ file.read(), restituisce il prossimo carattere letto dal le ed avanza il puntatore di lettura;

ˆ file.write(char), scrive il carattere passato come argomento nel le ed avanza il puntatore di scrittura.

A causa di una limitazione della libreria SD.h, nel caso la scheda venisse inserita solamente in un momento successivo all'accensione del sistema, si dovrebbe procedere al RESET del sistema stesso, al ne di rilevare corretta-mente la presenza della scheda ed abilitare il salvataggio dei dati.

Il metodo di salvataggio dei dati acquisiti prevede la creazione giornaliera di un le in cui vengono salvati tutti i record relativi al giorno stesso: il nome del le corrisponde alla data a cui si riferisce.

Ogni le viene scritto in formato testo rispettando la struttura del for-mato Comma Separated Values (CSV), per renderne agevole l'apertura con programmi di calcolo, ed è composto di tante righe quanti sono i record salvati in esso, oltre che da una riga iniziale che ne costituisce l'intestazione. Come già detto, ogni record è a sua volta composto, nell'ordine, dal rife-rimento temporale della singola acquisizione, dalla tensione, dalla corrente, dalla temperatura e dallo stato di carica stimato; all'interno del singolo le ogni campo viene separato con un delimitatore (;).

È possibile calcolare lo spazio occupato dai le di log se è nota la frequenza di salvataggio del singolo record, fnuovo record, e la sua dimensione in byte,

Nbyte record.

Considerando che viene salvato un nuovo record ogni 5 secondi (fnuovo record= 1

5 = 0.2Hz) dopo un certo tempo t dall'avvio del sistema sulla memoria

verranno salvati:

Nbyte(t) = (facquisizione· Nbyte record) · t (3.1)

nuovi byte.

Quindi sapendo che Nbyte record può valere al massimo 38 byte (8 byte

(22)

18 CAPITOLO 3. SEZIONE SOFTWARE i separatori), si ottiene che viene prodotto un le di circa 0.63 Mbyte ogni giorno.

In questo modo, considerando una registrazione senza interruzioni, ver-rebbero memorizzati circa 230 Mbyte in un anno; dato che la scheda di memoria utilizzata ha una capacità di 2 Gbyte il sistema di registrazione ha un'autonomia maggiore di 8 anni.

3.1.2 La comunicazione Ethernet

Grazie alla scheda Arduino Ethernet Shield, l'Arduino Uno riesce a connet-tersi alla rete Internet come Client o come Server; in questa applicazione viene congurato come Server, che invia dati ai Client che ne fanno richiesta. Per abilitare l'Arduino alla comunicazione con il protocollo TCP, biso-gna denire nel rmware il valore dell'indirizzo MAC (Media Access Con-trol) e l'indirizzo IP (Internet Protocol) che l'Arduino utilizzerà durante la comunicazione.

La libreria che si occupa di gestire la comunicazione Ethernet è la Ether-net.h; in questo progetto l'Arduino lavora come Server su un IP statico, ma la libreria supporta anche la funzionalità DHCP, che consente di assegnare automaticamente al Server Arduino un IP tra quelli disponibili.

Ovviamente è possibile variare i parametri funzionali per la connessione, quali MAC, indirizzo IP e porta di comunicazione (listato 3.1).

byte mac [ ] = { 0xDE , 0xAD , 0xBE , 0xEF , 0xFE , 0xED } ; // i n d i r i z z o MAC

IPAddress i p (147 , 162 , 11 , 104) ; // i n d i r i z z o IP E t h e r n e t S e r v e r s e r v e r (80) ; // p o r t a d i comunicazione

Listing 3.1: Parametri per la connessione Ethernet

Dopo aver abilitato la comunicazione con l'Ethernet Shield, portando a livello alto la corrispondente linea Chip Select del bus SPI (connessa al pin 10 dell'ATmega328), viene eseguita la funzione Ethernet.begin(mac, ip), che abilita la comunicazione con i valori di MAC e IP specicati, seguita da server.begin(), che attiva l'ascolto delle connessioni in entrata.

(23)

3.1. IL FIRMWARE 19 Viene sempre assunto che la richiesta che il Client rivolge al Server sia di tipo GET (per semplicità il rmware non considera l'eventualità di ricevere una richieste di altro tipo, come il POST).

Per rispondere al Client, il Server usa la funzione client.print(char ∗) (o

la client.println(char ∗)) che serve a inviare una stringa di risposta.

Normalmente le stringhe passate come argomento alla funzione client.print(char∗)

vengono memorizzate nella memoria RAM, ma con la macro F (char ∗

) è possibile indicare al compilatore di salvarle direttamente nella memoria programma FLASH, liberando così preziosa memoria RAM richiesta per le elaborazioni.

Una tipica richiesta di tipo GET, sul protocollo HTTP, può essere la seguente:

GET / pagina . htm? parametro1=a&parametro2=b HTTP/1.0 Listing 3.2: Esempio di richiesta GET In essa vengono specicati:

ˆ il tipo di richiesta (GET );

ˆ il nome completo del le che il Client richiede (/pagina.htm) seguito da parametri opzionali (che nell'esempio sono parametro1=a e parame-tro2=b);

ˆ la versione del protocollo HTTP utilizzato dal Client (HTTP/1.0 ). Ogni campo viene separato da uno spazio; possono seguire anche altre informazioni facoltative, ma che non vengono prese in considerazione dal rmware.

Il rmware dell'Arduino analizza quindi la richiesta HTTP ricevuta con il metodo richiestaGET (char ∗), visibile nel listato 3.3, individuando il nome

del le richiesto e gli eventuali parametri.

Poi controlla che il nome del le richiesto corrisponda ad un le presente nella scheda di memoria: in caso aermativo lo invia al Client, ma non prima di aver inviato la tipica intestazione delle risposte HTTP, che segnala al Client lo stato della richiesta. Il testo contenuto nell'intestazione viene mandato direttamente con le istruzioni viste sopra (consiste in più stringhe salvate nella memoria programma dell'Arduino, come mostra il listato 3.4); ad esso segue il contenuto vero e proprio della pagina HTML.

(24)

20 CAPITOLO 3. SEZIONE SOFTWARE // E s t r a e i l nome d e l f i l e r i c h i e s t o ed i p a r a m e t r i d a l l a s t r i n g a p a s s a t a come argomento boolean r i c h i e s t a G E T ( char * b u f f e r ) { boolean p a r a m e t r i P r e s e n t i=f a l s e ; u ns igned char c u r s o r e =5; n o m e F i l e R i c h i e s t o = &b u f f e r [ 5 ] ; w h i l e ( ( b u f f e r [ c u r s o r e ] != ' ' ) && ( c u r s o r e < BYTE_BUFFER_HTTP) ) { i f ( ( ( b u f f e r [ c u r s o r e ] == '& ') | | ( b u f f e r [ c u r s o r e ] == ' ? ' ) ) && ( c u r s o r e < BYTE_BUFFER_HTTP−1) ) { b u f f e r [ c u r s o r e ]=NULL ; // t e r m i n a t o r e i f ( ! p a r a m e t r i P r e s e n t i ) { p a r a m e t r i R i c h i e s t a G E T = &b u f f e r [ c u r s o r e +1]; p a r a m e t r i P r e s e n t i=t r u e ; } } c u r s o r e ++; } b u f f e r [ c u r s o r e ]=NULL ; // t e r m i n a t o r e i f ( ! p a r a m e t r i P r e s e n t i ) p a r a m e t r i R i c h i e s t a G E T = &b u f f e r [ c u r s o r e ] ; i f ( n o m e F i l e R i c h i e s t o [ 0 ] == NULL) r e t u r n f a l s e ; r e t u r n t r u e ; }

Listing 3.3: Funzione per l'analisi della richiesta GET

Se invece il nome del le che il Client richiede con il metodo GET non rappresenta un le presente in memoria, il rmware verica se corrisponde a un comando per cui è stata prevista una risposta specica, confrontando la stringa ricevuta con l'insieme dei comandi deniti mediante il metodo comandoGET (char ∗) (listato 3.6).

In questo caso, i comandi che prevedono una risposta da parte del rm-ware sono i seguenti:

ˆ nuovoDato: il Server invia al Client solamente l'ultimo record acquisito usando il metodo invioUltimoRecord(client) (listato 3.7);

ˆ cercaFile: il Server verica la presenza del le passato come parametro sulla scheda di memoria e risponde al Client con un `1' se la verica ha ha esito positivo, oppure con uno `0' altrimenti;

(25)

3.1. IL FIRMWARE 21 c l i e n t . p r i n t l n (F( "HTTP/1.1 200 OK" ) ) ;

c l i e n t . p r i n t l n (F( " Content−Type : t e x t / html " ) ) ; c l i e n t . p r i n t l n (F( " Connnection : keep−a l i v e " ) ) ; c l i e n t . p r i n t l n ( ) ;

Listing 3.4: Istruzioni per l'invio dell'intestazione HTTP

al parametro della richiesta): il Server risponde con un `1' se riesce ad eliminare il le, con uno `0' altrimenti;

ˆ data: il Server manda al client la data del le su cui sta attualmente salvando i record: corrisponde ad una stringa nel formato dd-MM-yy; ˆ RTC : il Client fa richiesta di aggiornare la data/ora del Real Time

Clock, passandone per parametri i nuovi valori, la cui validità è stata già vericata dal Client mediante le funzione Javascript dataValida() e oraValida() discusse più avanti;

ˆ reset: il Client richiede il reset della scheda Arduino tramite WDT (vedi sezione 3.1.5).

Per fare un esempio, nel caso il Client inviasse una richiesta di tipo cer-caFile al ne di vericare la presenza del le log_le.txt, allora la parte di richiesta GET analizzata dall'Arduino sarà costituita dalla stringa:

GET / c e r c a F i l e ? l o g _ f i l e . t x t HTTP/1.0

Listing 3.8: Esempio di comando attraverso richiesta GET

3.1.3 La comunicazione I

2

C

La libreria Wire.h viene inclusa per poter comunicare, sul bus I2C, con

l'integrato DS1307 e col convertitore A/D MCP3221 addetto alla misura della corrente.

All'interno della libreria, le funzioni Wire.beginTransmission() e

Wire.endTransmission() si occupano di inizializzare e terminare una trasmis-sione, gestendo le tempistiche e le modalità di trasmissione del bus, mentre le funzioni Wire.read() e Wire.write(char) servono a ricevere e inviare un byte ad un dispositivo connesso al bus.

(26)

22 CAPITOLO 3. SEZIONE SOFTWARE // I n v i a a l c l i e n t i l f i l e f i l e R i c h i e s t o

boolean i n v i o F i l e ( char * nomeFile , E t h e r n e t C l i e n t c l i e n t ) { i f ( ! s c h e d a P r e s e n t e )

r e t u r n f a l s e ;

F i l e f i l e =SD . open ( nomeFile , FILE_READ) ; i f ( f i l e ) {

boolean c o n t i n u a=t r u e ; w h i l e ( c o n t i n u a ) {

char b l o c c o [BYTE_BLOCCO ] ;

f o r ( uns igned char i =0; i<BYTE_BLOCCO; i ++) { i f ( f i l e . a v a i l a b l e ( ) ) b l o c c o [ i ]=( char ) f i l e . read ( ) ; e l s e { c o n t i n u a=f a l s e ; b l o c c o [ i ]=NULL ; } } b l o c c o [BYTE_BLOCCO]=NULL ; c l i e n t . p r i n t ( b l o c c o ) ; } f i l e . c l o s e ( ) ; r e t u r n t r u e ; } e l s e r e t u r n f a l s e ; }

Listing 3.5: Funzione per l'invio dei le presenti su scheda di memoria. Questa funzione ha permesso di aumentare di 4 volte la velocità di invio dei dati rispetto all'invio di un singolo carattere: si è passati da circa 4 kbyte/s no a circa 16 kbyte/s.

riservati al Real Time Clock, mentre i seguenti 56 (indirizzi 08h-FFh) non sono utilizzati e possono essere sfruttati come RAM non volatile. La lettu-ra/scrittura dei registri viene gestita internamente usando un puntatore al registro in uso (REGISTER POINTER).

Alla prima accensione dell'integrato DS1307 è necessario che il dispositivo che accede in modalità MASTER al bus (l'Arduino) gli imposti la data e l'ora, seguendo la procedura di scrittura su bus I2C indicata nel datasheet:

ˆ il dispositivo MASTER invia una condizione di START seguita dall'in-dirizzo dello SLAVE (0x68 per il DS1307) e dal bit di direzione R/W (impostato a 0 per un'operazione di scrittura)

(27)

3.1. IL FIRMWARE 23 // Confronta l a s t r i n g a p a s s a t a per parametro e r e s t i t u i s c e " t r u e

" se c o r r i s p o n d e a l contenuto d i n o m e F i l e R i c h i e s t o boolean comandoGET ( char * s t r i n g a 1 ) {

unsign ed char lunghezza1 =0; unsign ed char lunghezza2 =0;

w h i l e ( ( s t r i n g a 1 [ lunghezza1 ] != NULL) && ( lunghezza1 < BYTE_BUFFER_HTTP) )

lunghezza1++;

w h i l e ( ( n o m e F i l e R i c h i e s t o [ lunghezza2 ] != NULL) && ( lunghezza2 < BYTE_BUFFER_HTTP) ) lunghezza2++; i f ( lunghezza1 != lunghezza2 ) r e t u r n f a l s e ; // s t r i n g h e d i l u n g h e z z a d i v e r s a sono d i v e r s e unsign ed char i =0; w h i l e ( ( s t r i n g a 1 [ i ] == n o m e F i l e R i c h i e s t o [ i ] ) && ( i < lunghezza1 ) ) i ++; i f ( i == lunghezza1 ) r e t u r n t r u e ; r e t u r n f a l s e ; }

Listing 3.6: Funzione che identica il comando ricevuto

ˆ il MASTER invia un primo byte di dati, contenente l'indirizzo del registro interno dal quale iniziare la scrittura

ˆ lo SLAVE salva l'indirizzo ricevuto nel REGISTER POINTER e ri-sponde al MASTER con un bit di ACKNOWLEDGE

ˆ il MASTER invia in sequenza i byte di dati da scrivere nei registri dello SLAVE

ˆ lo SLAVE risponde al MASTER con un bit di ACKNOWLEDGE ad ogni byte ricevuto ed incrementa il valore del REGISTER POINTER; termina la comunicazione quando riceve una condizione di STOP dal MASTER

Ovviamente questa procedura viene seguita anche nel caso in cui venisse a mancare l'alimentazione e si dovesse reimpostare la data/ora del RTC.

(28)

24 CAPITOLO 3. SEZIONE SOFTWARE // I n v i a a l c l i e n t l ' u l t i m o r e c o r d p r e s e n t e i n memoria v o i d i n v i o U l t i m o R e c o r d ( E t h e r n e t C l i e n t c l i e n t ) { c l i e n t . p r i n t ( ora ) ; c l i e n t . p r i n t ( ' ; ' ) ; c l i e n t . p r i n t ( t e n s i o n e M e d i a ) ; c l i e n t . p r i n t ( ' ; ' ) ; c l i e n t . p r i n t ( c o r r e n t e M e d i a ) ; c l i e n t . p r i n t ( ' ; ' ) ; c l i e n t . p r i n t ( temperaturaMedia ) ; c l i e n t . p r i n t ( ' ; ' ) ; c l i e n t . p r i n t ( SoC ) ; }

Listing 3.7: Funzione per l'invio dell'ultimo record memorizzato

Figura 3.2: Registri interni DS1307

che serve ad impostare la data/ora del RTC, passando come parametri i nuovi valori, in formato esadecimale.

Per leggere, invece, il contenuto dei registri interni al ne di ottenere la da-ta/ora attuali bisogna preliminarmente eettuare un'operazione di scrittura nella quale il MASTER si limita a mandare allo SLAVE l'indirizzo del regi-stro interno di partenza per l'inizio della lettura, e seguire poi la procedura di lettura da bus I2C:

ˆ il dispositivo MASTER invia una condizione di START seguita dal-l'indirizzo dello SLAVE (col quale intende comunicare) e dal bit di di direzione R/W (impostato a 1 per un'operazione di lettura);

ˆ lo SLAVE risponde al MASTER con un bit di ACKNOWLEDGE; ˆ lo SLAVE inizia a trasmettere il contenuto dei registri interni a partire

(29)

3.1. IL FIRMWARE 25 ˆ il MASTER risponde allo SLAVE con un bit di ACKNOWLEDGE, se intende ricevere altri dati; altrimenti manda un bit di NOT ACKNO-WLEDGE se intende terminare il trasferimento.

Per la procedura di lettura, l'Arduino esegue la funzione void leggiRT C(char ∗ data, char∗ ora)

che acquisisce i valori attuali di data ed ora dal DS1307, e li restituisce come stringhe salvandoli nelle variabili passate per argomento.

3.1.4 L'interrupt temporizzato e l'acquisizione dei dati

La libreria MsTimer2.h permette di eseguire una funzione periodicamente, appoggiandosi all'evento di interrupt generato dal TIMER2 dell' ATmega328. Viene usata per temporizzare le acquisizioni A/D con le due istruzioni inserite nella parte di inizializzazione dell'Arduino:

MsTimer2 : : s e t (PERIODO_ACQUISIZIONE , n u o v a A c q u i s i z i o n e ) ; // eseguo l a f u n z i o n e n u o v a A c q u i s i z i o n e ( ) ogni 50 ms

MsTimer2 : : s t a r t ( ) ; // a b i l i t o i l t i m e r

Listing 3.9: Assegnazione della funzione nuovaAcquisizione al TIMER2 Grazie all'interrupt l'esecuzione del programma principale si interrompe e viene eseguito il metodo nuovaAcquisizione() (listato 3.10), che acquisisce i nuovi valori di tensione e di temperatura (con una conversione eseguita dal convertitore A/D interno all'Arduino).

v o i d n u o v a A c q u i s i z i o n e ( ) { // a c q u i s i z i o n e d i t e n s i o n e e temperatura t r a m i t e ADC ed aggiornamento d e l l o SoC

double t e n s i o n e = ( ( Vref * analogRead ( 0 ) ) /1024) / G t e n s i o n e ; // a c q u i s i s c o l a t e n s i o n e

r i c h i e s t a A D C=t r u e ; // a t t i v o i l f l a g per a c q u i s i z i o n e d i c o r r e n t e

analogRead ( 1 ) ; // i s t r u z i o n i n e c e s s a r i a per s e n s o r e ad a l t a impedenza

(30)

26 CAPITOLO 3. SEZIONE SOFTWARE p u n t i =0;

t e n s i o n e M e d i a P r e c e d e n t e=t e n s i o n e M e d i a ;

t e n s i o n e M e d i a = accumulatoreTensione /PUNTI_MEDIA ; c o r r e n t e M e d i a = a c c u m u l a t o r e C o r r e n t e /PUNTI_MEDIA ;

temperaturaMedia = accumulatoreTemperatura /PUNTI_MEDIA ; accumulatoreTensione =0; a c c u m u l a t o r e C o r r e n t e =0; accumulatoreTemperatura =0; } capacitaMassima=CAPACITA_NOMINALE* c o e f f i c e n t e T e m p e r a t u r a ( temperaturaMedia ) ; // a g g i o r n o i l v a l o r e d i c a p a c i t a massima i n base a l l a temperatura

// a g g i o r n o l o SoC i f ( ( s t a t o S i s t e m a==INIZIALE ) | | ( s t a t o S i s t e m a==EQUILIBRIO ) ) SoC=SoC_from_OCV( t e n s i o n e ) ; e l s e { double c o n t a t o r e C a r i c a = ( c o r r e n t e *PERIODO_ACQUISIZIONE) /3600000.0; // i l p e r i o d o d i a c q u i s i z i o n e v i e n e c o n v e r t i t o i n ore SoC += 100*( c o n t a t o r e C a r i c a / capacitaMassima ) ; } i f ( SoC <= 0) SoC=0; i f ( SoC >= 100) SoC=100; // a g g i o r n o l o s t a t o d e l s i s t e m a i f ( c o r r e n t e > CORRENTE_LIMITE) s t a t o S i s t e m a = CARICA ; e l s e i f ( c o r r e n t e < (−CORRENTE_LIMITE) ) s t a t o S i s t e m a = SCARICA ; e l s e i f ( ( ( tensioneMedia −t e n s i o n e M e d i a P r e c e d e n t e )< DERIVATA_LIMITE) && ( ( tensioneMedia −

t e n s i o n e M e d i a P r e c e d e n t e )>−DERIVATA_LIMITE) ) s t a t o S i s t e m a=EQUILIBRIO ;

e l s e

s t a t o S i s t e m a=TRANSIZIONE ; }

Listing 3.10: Funzione nuovaAcquisizione()

Il valore di corrente viene invece richiesto al convertitore A/D MCP3221, che opera a anco del trasduttore di corrente, in seguito al controllo del ag richiestaADC (listato 3.11): questa operazione risulta necessaria perchè non è possibile eseguire una lettura dal bus I2C all'interno della routine di

(31)

3.1. IL FIRMWARE 27 double leggiADC ( ) {

unsign ed char msbyte ; // byte p i u s i g n i f i c a t i v o unsign ed char l s b y t e ; // byte meno s i g n i f i c a t i v o

Wire . requestFrom (INDIRIZZO_ADC , 2) ; // r i c h i e d o i 2 byte d e l l a c o n v e r s i o n e ADC

msbyte=Wire . read ( ) ; l s b y t e=Wire . read ( ) ;

unsign ed i n t correnteADC=l s b y t e +(256* msbyte ) ; r i c h i e s t a A D C=f a l s e ;

r e t u r n ( ( ( Vref * correnteADC ) / 4092 ) − Vref_LEM_I ) / G c o r r e n t e ;

}

Listing 3.11: Funzione leggiADC()

I valori istantanei vengono utilizzati per calcolare i rispettivi valori medi su un certo periodo; questi ultimi sono i valori che vengono scritti nei le di log.

Il valore istantaneo di corrente è utile per ottenere una miglior precisione nel conteggio della carica entrante/uscente delle batterie (di cui si parla nel capitolo 4).

Per quanto riguarda la temperatura, la sua misura consente di deter-minare il coecente moltiplicativo, che indica la variazione della capacità delle batterie, interpolando i dati forniti dal costruttore (tabella 2.6) con la funzione coecenteTemperatura() (listato 3.12).

3.1.5 Il Watch Dog Timer

Il WDT è una funzionalità del chip ATmega328: si tratta di un particolare timer che lavora con una sorgente di clock indipendente dal clock di sistema. Genera un interrupt o un reset di sistema quando si verica un overow.

Risulta utile in quei programmi in cui il usso di esecuzione può incontrare qualche condizione imprevista e far bloccare l'intero sistema: in questi casi lo si imposta per generare un reset di sistema dopo un certo periodo, se il timer non viene azzerato nel frattempo.

In questo progetto viene usato come sorgente di reset di tipo software e viene abilitato solo nel momento in cui il Client eettua una richiesta di reset al Server, per eettuare il reset del sistema di acquisizione da remoto, senza accedere sicamente alla scheda.

(32)

28 CAPITOLO 3. SEZIONE SOFTWARE c o n s t u ns i gned char arrayTemperatura [PUNTI_TEMPERATURA]={ 0 , 5 ,

10 , 15 , 20 , 25 , 30 , 35 , 40 } ;

c o n s t u ns i gned char a r r a y C o e f f i c e n t e T e m p e r a t u r a [PUNTI_TEMPERATURA ]={ 0 , 84 , 88 , 93 , 97 , 100 , 103 , 105 , 107 } ; // R e s t i t u i s c e i l c o e f f i c e n t e m o l t i p l i c a t i v o per c u i va m o l t i p l i c a t a l a c a p a c i t a ' , i n base a l l a temperatura double c o e f f i c e n t e T e m p e r a t u r a ( double t e m p e r a t u r a M i s u r a t a ) { u ns ig n ed char i n d i c e ; f o r ( i n d i c e =0; i n d i c e < PUNTI_TEMPERATURA−1; i n d i c e ++) i f ( ( t e m p e r a t u r a M i s u r a t a < arrayTemperatura [ i n d i c e +1]) && ( t e m p e r a t u r a M i s u r a t a > arrayTemperatura [ i n d i c e ] ) ) break ; double c o e f f i c e n t e A n g o l a r e = ( ( a r r a y C o e f f i c e n t e T e m p e r a t u r a [ i n d i c e +1] − a r r a y C o e f f i c e n t e T e m p e r a t u r a [ i n d i c e ] ) / 100.0 ) / ( arrayTemperatura [ i n d i c e +1] − arrayTemperatura [ i n d i c e ] ) ; r e t u r n ( ( a r r a y C o e f f i c e n t e T e m p e r a t u r a [ i n d i c e ] ) + ( c o e f f i c e n t e A n g o l a r e * t e m p e r a t u r a M i s u r a t a ) ) / 1 0 0 . 0 ; }

Listing 3.12: Funzione coefficenteT emperatura()

3.2 Le pagine Web

Le pagine Web permettono di visualizzare rapidamente su una nestra di un browser Web i dati analogici che il rmware acquisisce, e di eettuare dei controlli sul sistema di acquisizione; al loro interno contengono anche delle parti in linguaggio JavaScript: queste linee di codice vengono interpretate ed eseguite dal browser che le riceve.

Per questo si dice che Javascript è un linguaggio interpretato (non deve essere compilato) e di tipo Client-side (cioè viene proprio eseguito dal Client e non dal Server).

È stato predisposto un piccolo menù di navigazione per rendere semplice l'accesso alle funzioni del rmware; è composto da poche pagine HTML (i nomi delle pagine rispettano la convenzione 8.3 sul nome dei le, come già detto).

Per aggiornare parti del contenuto di una pagina (senza doverla ricaricare interamente) o per permettere all'utente di interagire con la stessa, tramite semplici controlli, viene sfruttata la tecnica di trasferimento dati AJAX che permette al Server di mandare al Client solo una piccola quantità di dati.

(33)

3.2. LE PAGINE WEB 29

3.2.1 La pagina index.htm

Da questa si accede alle altre: contiene solamente una lista di collegamenti ipertestuali.

Viene visualizzata in modo predenito come pagina principale del Web Server.

3.2.2 La pagina tabella.htm

Mostra una tabella (gura 3.3) con le ultime acquisizioni; il suo contenuto viene aggiornato automaticamente ad intervalli regolari, tramite una richiesta GET di tipo nuovoDato (sezione 3.1.2) all'Arduino.

È possibile variare il numero di righe che vengono visualizzate ed è pre-sente un bottone per l'aggiornamento manuale nel caso il browser usato non supportasse la tecnologia AJAX (come per i dispositivi mobili).

Figura 3.3: Pagina tabella.htm

3.2.3 La pagina graco.htm

Mostra un graco con i dati delle ultime acquisizioni.

Il graco viene tracciato grazie all'uso delle librerie JavaScript open-source jQuery e Flot.

(34)

30 CAPITOLO 3. SEZIONE SOFTWARE più gradevoli i contenuti delle pagine; la libreria Flot si appoggia invece al-la libreria jQuery consentendo di eettuare operazioni di disegno, come al-la creazione di svariati tipi di graci.

Per poter usare le suddette librerie, vengono inclusi nel le graco.htm i riferimenti ai le di script necessari, memorizzati sulla scheda di memoria: verranno richiesti dal browser del Client in sequenza non appena termina l'invio del le graco.htm:

<s c r i p t language=" j a v a s c r i p t " type=" t e x t / j a v a s c r i p t " sr c=" j q u e r y . j s "></ s c r i p t>

<s c r i p t language=" j a v a s c r i p t " type=" t e x t / j a v a s c r i p t " sr c=" f l o t . j s "></ s c r i p t>

<s c r i p t language=" j a v a s c r i p t " type=" t e x t / j a v a s c r i p t " sr c=" time . j s "></ s c r i p t>

Listing 3.13: Inserimento dei plugin nella pagina HTML con i TAG script In questo caso viene usato un graco a linee che visualizza gli andamenti nel tempo delle grandezze siche misurate.

Praticamente lo script presente nella pagina si occupa di aggiornare perio-dicamente ed in modo automatico il contenuto del graco con i dati richiesti all'Arduino tramite una richiesta di tipo nuovoDato (come per il caso della tabella): i dati ricevuti vengono memorizzati in più array, di lunghezza pari al massimo numero di punti presenti nel graco.

Dopo aver acquisito un nuovo record, lo script controlla che abbia un'e-tichetta temporale diversa dal precedente: in caso aermativo lo riconosce come un nuovo record da inserire nel graco e lo divide in più parti (corri-spondenti ai campi del record), ognuna delle quali viene accodata al rispettivo array.

È stata inserita la possibilità di impostare, tramite due caselle di te-sto, il numero massimo di punti che vengono interpolati e l'intervallo di aggiornamento; questi valori sono limitati a rimanere entro i limiti indicati.

Cambiando il numero di punti del graco, gli array contenenti i campi dei record vengono ridimensionati.

Inne il graco è impostato per adattarsi automaticamente alle dimen-sioni della nestra del browser.

(35)

3.2. LE PAGINE WEB 31

Figura 3.4: Pagina graco.htm

3.2.4 La pagina RTC.htm

Permette di reimpostare il Real Time Clock inserendo data e ora. I nuovi dati devono essere inseriti in apposite caselle di testo (gura 3.5).

Viene eettuato un controllo sulla correttezza dei dati inseriti: ogni pa-rametro deve essere composto di due caratteri altrimenti non viene inviata all'Arduino la richiesta di aggiornamento del Real Time Clock.

Tale controllo viene implementato con una funzione JavaScript (riportata nel listato 3.14) eseguita quando l'utente clicca il bottone per impostare i nuovi valori di data/ora; il controllo viene quindi eseguito dal browser del Client, liberando risorse di calcolo dell'Arduino che si deve limitare ad inviare i nuovi dati al chip DS1307, sapendo già che quelli inseriti sono validi.

Si nota l'uso della funzione JavaScript Date(anno, mese, giorno), la quale crea un oggetto di tipo Date che include un riferimento temporale UTC corrispondente al numero di millisecondi passati dal 1 gennaio 1970 no alla data specicata come argomento.

(36)

32 CAPITOLO 3. SEZIONE SOFTWARE

Figura 3.5: Pagina RTC.htm

al successivo giorno veramente esistente (nell'esempio sarà 1 marzo 2013); quindi confrontando i parametri inseriti nella caselle di testo, da parte del-l'utente, con quelli del riferimento temporale UTC, creato con la funzione Date(), si determina se la data inserita risulta valida.

3.2.5 La pagina le.htm

Permette di accedere ad un singolo le di log inserendone la relativa data, di eliminarlo dalla scheda, oppure di eliminare tutti i le relativi ad uno specico anno (gura 3.6).

(37)

3.2. LE PAGINE WEB 33 f u n c t i o n d a t a V a l i d a ( s t r i n g a G i o r n o , stringaMese , s t r i n g a A n n o ) { i f ( ( s t r i n g a G i o r n o . l e n g t h == 2) && ( s t r i n g a M e s e . l e n g t h == 2) && ( s t r i n g a A n n o . l e n g t h == 2) ) { var g i o r n o=p a r s e I n t ( s t r i n g a G i o r n o ) ; var mese=p a r s e I n t ( s t r i n g a M e s e ) ; var anno=p a r s e I n t ( s t r i n g a A n n o ) ;

var d a t a R e a l e=new Date ( anno +2000 , mese −1, g i o r n o ) ;

i f ( ( g i o r n o == d a t a R ea l e . getDate ( ) ) && ( mese == ( d a t a R e a le . getMonth ( ) + 1) ) && ( anno == ( d at a Re a le . g e t F u l l Y e a r ( ) − 2000) ) ) r e t u r n t r u e ; // data v a l i d a e l s e r e t u r n f a l s e ; // data NON v a l i d a } e l s e r e t u r n f a l s e ; // data NON v a l i d a } f u n c t i o n o r a V a l i d a ( s t r i n g a O r e , s t r i n g a M i n u t i ) { i f ( ( s t r i n g a O r e . l e n g t h == 2) && ( s t r i n g a M i n u t i . l e n g t h == 2) && ( p a r s e I n t ( s t r i n g a O r e ) <= 23) && ( p a r s e I n t ( s t r i n g a M i n u t i ) <= 59) ) r e t u r n t r u e ; // ora v a l i d a e l s e r e t u r n f a l s e ; // ora NON v a l i d a }

(38)

34 CAPITOLO 3. SEZIONE SOFTWARE

(39)

Capitolo 4

La stima dello Stato di Carica

4.1 Il comportamento delle batterie

Una batteria ricaricabile si può modellizzare con il modello equivalente mo-strato in gura 4.1: in esso è presente un generatore di forza elettromotrice EM F con una resistenza in serie RS (che non è altro che la resistenza

in-terna propria della batteria), più varie celle R-C che servono a tener conto del comportamento delle reazioni chimiche che avvengono all'interno della batteria.

Questo, noto come modello Randle, approssima il comportamento reale delle batterie in modo sempre migliore all'aumentare del numero di celle R-C considerato.

La tensione che si può prelevare ai morsetti della batteria, senza connet-terla ad alcun carico, viene indicata con OCV (Open Circuit Voltage).

Figura 4.1: Schema equivalente delle batterie

Applicando una corrente costante uscente o entrante ai morsetti delle batterie, si può notare un comportamento simile a quello mostrato nelle gure 4.2 e 4.3: durante la fase di carica/scarica si nota la presenza di un divario

(40)

36 CAPITOLO 4. LA STIMA DELLO STATO DI CARICA

Figura 4.2: Curve di tensione

durante la scarica Figura 4.3: Curve di tensionedurante la carica tra i valori di EMF e OCV , docuto alle cadute di tensione sulla resistenza Rs e sulle celle R-C.

Al termine di questa fase i valori di EMF ed OCV tornano a coincidere, ma non prima che sia passato un certo periodo (periodo di rilassamento).

La leggera pendenza delle curve di EMF e OCV visibile nello stato di equilibrio è dovuta all'eetto dell'auto-scarica, dovuta alle perdite interne della batteria.

4.2 Lo stato di carica

Lo stato di carica, o SoC (acronimo di State of Charge), al tempo t di una batteria è denito come la carica residua Q(t) (espressa in Coulomb) che la batteria può ancora erogare al carico in rapporto alla sua capacità nominale (intesa come quantità massima di carica), e solitamente viene indicata in percentuale:

SoC(t) [%] = Q(t) Qnominale

× 100 (4.1)

La capacità nominale non è un parametro facile da denire, perchè di-pende da molti fattori (per esempio la temperatura o l'invecchiamento delle singole celle). Per questo, si è deciso che per denire il valore di capacità nominale di un accumulatore si faccia riferimento ad un tempo di scarica e ad una temperatura ambiente (alla quale avviene la scarica) pressati.

Le normative europee stabiliscono così che la capacità di una batteria al piombo, indicata con C10, si debba riferire ad un periodo di scarica di 10 ore

(41)

4.2. LO STATO DI CARICA 37 la tensione di soglia la batteria riduce rapidamente la corrente che riesce a fornire al carico.

Inoltre solitamente i costruttori di batterie esprimono la capacità nomina-le in Ampere-ora (1 Ah=3600 Coulomb), quindi se si considerano nomina-le speciche delle batterie in esame:

C10= 28 Ah, Vsoglia,singola cella= 1.80 V, T = 25°C

si può prevedere approssimativamente che una singola batteria risulterà scarica se da essa viene prelevata una corrente costante di 2.8A per un tempo di 10 ore; dopo questo periodo la singola batteria presenterà una tensione di:

1.80 V × 6 = 10.8 V.

Gli standard stabiliti per la denizione della capacità nominale di una batteria variano a seconda del tipo di batteria (ad esempio per le batterie Ni-Cd viene stabilito un periodo di scarica di 5 ore, quindi nei loro datasheet i costruttori specicano il valore di C5) o a seconda delle normative del paese

di produzione (per esempio la normativa USA denisce un periodo di scarica di 20 ore per le batterie al piombo, e indica quindi la capacità nominale delle stesse con C20).

Esistono vari metodi per la stima dello SoC di un accumulatore, tra i quali si ricordano:

ˆ la misura della densità dell'elettrolita: è un metodo abbastanza preciso ma la gran parte delle volte risulta scomodo da mettere in pratica, in quanto necessita di avere accesso alle batterie. A batteria carica la densità dell'elettrolita (che è l'acido solforico per le batterie al piombo) risulta maggiore;

ˆ la misura della EMF: come già detto, sapendo che in condizioni di equilibrio i valori di EMF e OCV sono uguali, attraverso le tabelle che mettono in relazione OCV e SoC (rilasciate solitamente dai costruttori) è possibile risalire allo SoC con una semplice misura di tensione. Que-sto metodo risulta molto rapido, ma presenta dei punti deboli: bisogna scollegare qualsiasi carico dalle batterie in esame (cosa non sempre pra-tica e/o fattibile) e attendere che le batterie siano state a riposo (anche per varie ore) prima di considerare la misura di tensione adabile per la stima dello SoC.

(42)

38 CAPITOLO 4. LA STIMA DELLO STATO DI CARICA ˆ il `conteggio di carica' (o Coulomb counting): questo metodo preve-de di conoscere lo stato iniziale di carica preve-dell'accumulatore in esame (SoCiniziale , o equivalentemente la sua carica iniziale Qiniziale ) e che

si misuri la quantità di carica entrante/uscente dallo stesso. Per fare ciò è possibile misurare costantemente la corrente i(t) entrante/uscente dalla batteria, e ricavare la carica residua Q(t), al tempo t, scambiata con il circuito esterno calcolando l'integrale della corrente nel tempo:

Q(t) = Qiniziale+

Z t

0

i(t)dt (4.2)

Dividendo ogni membro dell'equazione 4.2 per Qnominale si ottiene

l'e-quazione 4.3, con la quale si può stimare lo SoC.

SoC(t) = SoCiniziale+

Rt

0 i(t)dt

Qnominale (4.3)

Risulta essere un valido metodo per stimare lo SoC nel caso la corrente richiesta vari rapidamente e risulti impossibile l'utilizzo del metodo precedente; presenta però dei problemi non trascurabili che ne limitano l'accuratezza: gli inevitabili errori che si accumulano nell'operazione di integrazione, la dicoltà di avere a disposizione un valore abbastanza adabile dello stato di carica per inizializzare il sistema di integrazione e il rendimento di carica delle batterie non unitario.

Il rendimento di carica, denito come il rapporto tra l'energia fornita in un ciclo completo di carica e l'energia disponibile per il successivo ciclo completo di scarica, risulta sempre minore del 100% a causa delle perdite interne (che si manifestano nel surriscaldamento della batteria stessa) perciò il conteggio di carica entrante nella batteria durante la fase di carica produce inevitabilmente un risultato maggiore della carica eettivamente erogabile in seguito.

Per questi motivi il conteggio di carica deve essere ricalibrato ad inter-valli regolari, ed in condizioni ben denite.

(43)

4.3. IL METODO UTILIZZATO 39

4.3 Il metodo utilizzato

Per riuscire a realizzare un algoritmo ecace per la stima dello SoC, da implementare su un sistema a microcontrollore, vengono uniti i pregi del metodo di misura di tensione a circuito aperto e del conteggio di carica.

L'algoritmo descritto nel seguito è riportato in vari libri e pubblicazioni riguardanti i sistemi di gestione delle batterie.

In particolare, all'accensione del sistema (STATO INIZIALE) si assume che il gruppo di batterie sia stato a riposo no a quell'istante, e che la misura diretta di tensione si possa considerare attendibile per la stima dello SoC iniziale, il quale viene determinato interpolando i dati forniti dal costruttore (tabella 4.4).

Figura 4.4: Relazione SoC-OCV delle batterie 12HX135; i dati si riferiscono alla singola cella, rimasta a riposo per 24 ore a 25‰

Poi l'algoritmo transita verso uno di tre stati, come mostra il diagram-ma di gura 4.5, in base al valore misurato della corrente; la decisione per eettuare le transizione di stato viene presa in riferimento a un certo valore limite Ilimite di corrente, abbastanza piccolo.

Si può quindi transitare verso:

ˆ lo STATO DI EQUILIBRIO se la corrente è, in modulo, minore del valore limite denito e la tensione rimane pressochè costante; qui lo SoC viene determinato tramite la relazione SoC − OCV , come è avvenuto per lo STATO INIZIALE;

ˆ lo STATO DI CARICA se la corrente risulta maggiore del valore limite; qui lo SoC viene calcolato con il metodo `conteggio di carica', partendo dal valore precedente la transizione di stato;

(44)

40 CAPITOLO 4. LA STIMA DELLO STATO DI CARICA

Figura 4.5: Diagramma a stati dell'algoritmo

Vi è un ultimo stato, al quale si può accedere dallo STATO DI CARICA o di SCARICA: lo STATO DI TRANSIZIONE. In esso si giunge se la cor-rente torna a calare, no a rientrare in una fascia di valori tali da poterla considerare trascurabile (cioè se |i(t)| < Ilimite).

In questo stato il valore di SoC stimato viene aggiornato tramite il con-teggio di carica, e si deve attendere nchè la tensione misurata risulti stabile (cioè che le batterie si possano considerare `a riposo') oppure che la corrente torni a crescere, superando (in modulo) il valore Ilimite.

Nel primo caso il sistema transita nello stato di EQUILIBRIO, mentre nel secondo in quello di SCARICA o CARICA.

Per quanto riguarda l'implementazione di questo metodo sulla scheda Arduino, non ci sono problemi per la misura di tensione a circuito aperto, mentre per il conteggio di carica bisogna adottare un sistema per il calcolo dell'integrale in ambito digitale.

Sapendo che il microcontrollore acquisisce i valori di corrente (e ten-sione) con una frequenza nota facquisizione, corrispondente ad un periodo

Tacquisizione = facquisizione1 = 50 ms ssato nel rmware, è possibile

(45)

4.3. IL METODO UTILIZZATO 41

SoC(n + 1) = SoC(n) + I(n) · Tacquisizione Qnominale

(4.4) dove con n viene indicato l'istante n-esimo, a cui corrisponde la corrente I(n). Questa equazione viene usata dal rmware per aggiornare la stima dello SoC dopo ogni nuova acquisizione.

Praticamente la condizione di `tensione stabile', che si deve vericare per transitare nello STATO DI EQUILIBRIO, si ottiene quando la derivata della tensione è nulla, o ha lente variazioni dovute all'auto-scarica.

Per questo viene scelto un valore limite derivatalimite, abbastanza piccolo,

usato come soglia di decisione.

Siccome i dati su cui opera l'algorimtmo sono discretizzati nel tempo, allora la derivata della tensione si può esprimere come dierenza tra il valore assunto in un istante, V (n), e quello precedente, V (n − 1).

Per cui se V (n) − V (n − 1) ≤ derivatalimite allora la tensione di batteria

(46)
(47)

Capitolo 5

Conclusioni

Il sistema descritto e sviluppato in questa attività di tesi verrà installato al ne di monitorare l'andamento energetico delle batterie.

Il sistema è già registrato presso le infrastrutture informatiche del dipar-timento con i seguenti parametri di connessione:

ˆ indirizzo IP statico: 147.162.11.104 ˆ Net Mask: 255.255.255.255.0 ˆ Gateway: 147.162.11.254 ˆ DNS: 147.162.2.100 e per accedergli basta digitare:

logbatterie

nella barra indirizzi di un browser collegato alla rete dipartimentale. La realizzazione nale è visibile in gura 5.1.

Il sistema realizzato si può adattare benissimo anche ad altre congura-zioni di batterie riprogrammando l'Arduino Uno con i parametri caratteristici delle batterie sotto misura, i quali sono deniti nel codice sorgente attraverso le macro e gli array riportati nel listato 5.1; in particolare gli array che ven-gono deniti costituiscono le tabelle delle speciche tecniche delle batterie (riportate nelle gure 4.4 e 2.6).

Anche i valori di soglia Ilimite e derivatalimite, che servono a regolare

l'algoritmo di stima dello SoC, possono essere impostati tramite riprogram-mazione dell'Arduino, variando il valore assegnato loro dalle apposite macro (listato 5.2).

(48)

44 CAPITOLO 5. CONCLUSIONI

Figura 5.1: Realizzazione nale del sistema: a sinistra si vede la piccola scheda che comprende il LEM FHS 40-P ed il convertitore A/D MCP3221, mentre a destra è visibile la scheda che monta il convertitore DC/DC, il LEM LV 25-P ed il trasduttore di temperatura. Su quest'ultima viene innestato l'Arduino Uno, grazie agli appositi connettori.

5.1 Possibili sviluppi futuri

L'impiego del controller Ethernet W5100 comporta un consumo non trascu-rabile, pari a circa 180 mA, anche in standby; ciò comporta una lenta, ma costante, scarica delle batterie.

Un possibile miglioramento a questo aspetto del progetto consiste nel sostituire il modulo Arduino Ethernet Shield in uso con la nuova versione, che monta il controller W5200.

(49)

5.1. POSSIBILI SVILUPPI FUTURI 45 Un ulteriore aspetto riguarda la possibilità di monitorare lo stato di salute (State of Health) delle batterie. Infatti, a seguito di numerosi cicli di carica e scarica le batterie tendono a diminuire la loro capacità e conseguentemente falsare la stima dello stato di carica.

(50)

46 CAPITOLO 5. CONCLUSIONI // PARAMETRI DELLE BATTERIE

#d e f i n e CELLE_PER_BATTERIA 6 // numero d i c e l l e per b a t t e r i a #d e f i n e NUMERO_BATTERIE_SERIE 21 // numero d i b a t t e r i e c o l l e g a t e

i n s e r i e

#d e f i n e CAPACITA_NOMINALE 28 // Capacita nominale d e l l a s e r i e , e s p r e s s a i n Ah

// TABELLA PER IL CALCOLO DELLO SoC IN FUNZIONE DELLA TENSIONE A CIRCUITO APERTO (A RIPOSO)

#d e f i n e PUNTI_OCV_SoC 7

c o n s t u ns i gned char arraySoC [PUNTI_OCV_SoC]={ 0 , 0 , 20 , 40 , 60 , 80 , 100 } ;

c o n s t double arrayOCV [PUNTI_OCV_SoC]={0 ,

1.800 * CELLE_PER_BATTERIA * NUMERO_BATTERIE_SERIE, 1.985 * CELLE_PER_BATTERIA * NUMERO_BATTERIE_SERIE, 2.025 * CELLE_PER_BATTERIA * NUMERO_BATTERIE_SERIE, 2.065 * CELLE_PER_BATTERIA * NUMERO_BATTERIE_SERIE, 2.100 * CELLE_PER_BATTERIA * NUMERO_BATTERIE_SERIE, 2.130 * CELLE_PER_BATTERIA * NUMERO_BATTERIE_SERIE } ;

// TABELLA PER IL CALCOLO DEL COEFFICENTE DI CORREZIONE PER LA CAPACITA IN FUNZIONE DELLA TEMPERATURA

#d e f i n e PUNTI_TEMPERATURA 9

c o n s t u ns i gned char arrayTemperatura [PUNTI_TEMPERATURA]={ 0 , 5 , 10 , 15 , 20 , 25 , 30 , 35 , 40 } ;

c o n s t u ns i gned char a r r a y C o e f f i c e n t e T e m p e r a t u r a [PUNTI_TEMPERATURA ]={ 0 , 84 , 88 , 93 , 97 , 100 , 103 , 105 , 107 } ;

Listing 5.1: Macro e array di congurazione delle batterie

// PARAMETRI PER LA STIMA DELLO STATO DI CARICA

#d e f i n e CORRENTE_LIMITE 1 . 0 // c o r r e n t e l i m i t e i n Ampere per d e c i d e r e l a s o g l i a d e l l o STATO TRANSIZIONE

#d e f i n e DERIVATA_LIMITE 1 .0 // d e r i v a t a l i m i t e i n Volt per d e c i d e r e l a s o g l i a d e l l o STATO EQUILIBRIO

(51)

Capitolo 6

Sorgente completo in C

/*

Web S e r v e r + SD Card Logger + Real Time Clock C i r c u i t o :

* E t h e r n e t s h i e l d connesso a i p i n 10 , 11 , 12 , 13

* RTC DS1307 e ADC MCP3221 : SDA connesso ad AN4 , SCL connesso ad AN5

* Sensore d i t e n s i o n e connesso ad AN0 * Sensore d i temperatura connesso ad AN1 c r e a t o i l 19 marzo 2013

u l t i m a m o d i f i c a 10 l u g l i o 2013 da Dario Marchetto

*/

#i n c l u d e <SPI . h> // l i b r e r i a per l a comunicazione su bus SPI ( r i c h i e s t a d a l l a scheda d i memoria SD e d a l modulo E t h e r n e t ) #i n c l u d e <E t h e r n e t . h> // l i b r e r i a per l a g e s t i o n e d e l modulo

E t h e r n e t

#i n c l u d e <SD . h> // l i b r e r i a per l a g e s t i o n e d e l l a scheda d i memoria Secure D i g i t a l

#i n c l u d e <MsTimer2 . h> // l i b r e r i a per g e s t i r e l a t e m p o r i z z a z i o n e d e l l ' a c q u i s i z i o n e a t t r a v e r s o i l Timer2

#i n c l u d e <Wire . h> // l i b r e r i a per l a comunicazione I2C

#i n c l u d e <avr /wdt . h> // l i b r e r i a per l ' uso d e l Watch Dog Timer // PARAMETRI DELLE BATTERIE

#d e f i n e CELLE_PER_BATTERIA 6 // numero d i c e l l e per b a t t e r i a #d e f i n e NUMERO_BATTERIE_SERIE 21 // numero d i b a t t e r i e c o l l e g a t e

i n s e r i e

#d e f i n e CAPACITA_NOMINALE 28 // Capacita nominale d e l l a s e r i e , e s p r e s s a i n Ah

Riferimenti

Documenti correlati

A volte queste realtà sono più o meno legate ad associazioni di produttori, progettisti e realizzatori di impianti fotovoltaici che per motivi vari, anche di immagine, si

Si tratta ora di calcolare la derivata della coppia a partire dalla conoscenza delle grandezze che interessano la macchina e su cui possiamo intervenire, quali:

A tal proposito sarà necessario che vi siano efficienti sistemi di comunicazione tra rete, sorgenti di produzione e carichi, in modo che si possa individuare rapidamente

I piccoli pori formati in seguito all'assorbimento dell'acqua o all'erosione crescono e si uniscono a quelli circostanti, formandone di più grandi: questo fenomeno è collegato

Per il trasferimento del codice nella memoria del processore è stato impiegato lo strumento di programmazione e debug MPLAB ICD2 (illustrato in Fig. 3.13b), che dispone

Per- tanto, effettuando il burn-in, i guasti del sistema nella fase ini- ziale dell’utilizzo possono essere anticipati, ovviamente questo comporta che il tempo di

Electric vehicle mode: The engine is off, and the battery provides electrical energy to power the motor or the reverse when regenerative braking is engaged.. Used for idling as

Con diafonia si intende il passaggio di energia da una linea ad un'altra (più precisamente da un circuito ad un altro). Il fenomeno è legato ad un accoppiamento magnetico di