/* Misura di una temperatura con Arduino Uno e sensore
* AD590 alimentato a 5V tramite una R=1kOhm,1% => 1mV/K
* Viene usato il valore della VREF interna memorizzato
* sulla EEPROM, precedentemente calcolato e salvato.
*/
#include <EEPROM.h>
#define STAMPAVS 1 // 1 stampa VS
#define STAMPATK 1 // 1 stampa T in gradi K
const int EEADD=0; // ind. EEPROM dove è stato memorizzato il fatt. correttivo
const int AD590 = A0; // pin analogico a cui è collegato l'AD590
const int R = 987; // Valore attuale della Resistenza in serie all'AD590
float VREF; // VREF: verrà letto dalla EEPROM
const int DELTA_T = 30000; // intervallo di misurazione in ms
int TC; // Temp misurata, in °C
int TK; // Temp misurata, in K
float Vs; // Tensione misurata (ai capi di R) da Arduino
float Is; // Corrente calcolata come Vs/R (in uA)
unsigned long counter=0; // progressivo misurazioni di temperatura
unsigned long prevMillis; // marcatore temporale per millis()
void setup() {
Serial.begin(9600); // Imposta rtx seriale a 9600bps (monitor seriale, PuTTY ecc)
analogReference(INTERNAL); // Vref interna =1,1V nominale
EEPROM.get(EEADD, VREF); // legge locazione EEADD e assegna valore a VREF
prevMillis=millis(); // marca istante iniziale
}
// Effettua una misura ripetuta di Vs:
float misuraVs() {
float somma=0; // somma delle letture singole di V
float vmedio=0; // media delle letture singole di V
float v; // lettura singola di V
int n; // numero restituito dall'ADC
int nlett=5; // quante letture effettive
for (int i=0; i<nlett+2; i++) {
n=analogRead(AD590);
v=VREF*n/1024;
if (i>1) // scarto prime due misure
somma=somma+v;
delay(50);
}
vmedio=somma/nlett; //calcola valore medio delle misure di tensione
return (vmedio); // ritorna la media della misure di I (in uA)
}
void loop() {
/* Misura e stampa periodica della temperatura ogni DELTA_T millisecondi: */
if(millis()-prevMillis >= DELTA_T) {
Vs=misuraVs(); //misura la Vs ai capi di R e l'assegna alla var. Vs
Is=1E6*Vs/R; //calcola Is, con la Legge di Ohm,e la converte in uA
TK = (int)Is ; //es. 298.00 diventa 298K
TC=TK-273; //es. 298K diventa 25°C
Serial.print(++counter);
#if STAMPAVS
Serial.print("\t");
Serial.print(Vs,3);
Serial.print("V");
#endif
#if STAMPATK
Serial.print("\t");
Serial.print(TK);
Serial.print("K");
#endif
Serial.print("\t");
Serial.print(TC);
Serial.println("°C");
prevMillis=millis();
}
/* altri compiti da eseguire: */
}PrettyPrint
domenica 17 dicembre 2023
Arduino UNO R3: termometro 0/100°C con AD590 e una sola resistenza.
Arduino UNO R3: misurare la tensione di riferimento interna
u.r. 17-FEB-2026
L'idea di questa procedura mi è nata quando ho dovuto effettuare la correzione software della tensione di riferimento generata dal bandgap entro contenuto nell'ATmega328P, per l'uso con il sensore AD590 senza stadi attivi di condizionamento.
La tensione di riferimento del bandgap interno è estremamente stabile, ottima per misurare range fra 0 e 1,1V, ma ha un'elevata tolleranza di produzione (tipicamente fra 1,0 e 1,2V) che può quindi introdurre errori non trascurabili nel calcolo della tensione misurata dall'ADC.
Il suo utilizzo corretto richiede, quindi, innanzitutto una stima del suo effettivo valore (mediante la procedura di seguito descritta) ma anche lo scarto della prima lettura (che sarebbe non accurato, così come è scritto nel datasheet).
DESCRIZIONE DELLA PROCEDURA
Il pin AREF, se non collegato a nessuna tensione esterna, fornisce in uscita il valore della tensione di riferimento attualmente configurata nel software in esecuzione su Arduino
Si misurerà, quindi, tale tensione con un voltmetro (es un multimetro digitale), che verrà memorizzato nella memoria EEPROM della scheda Arduino e richiamato, all'occorrenza, in ogni software che impieghi la stessa tensione di riferimento interna.
HARDWARE
#include <EEPROM.h>EEPROM.get(EEADD, VREF);domenica 29 ottobre 2023
Un altro debounce (non bloccante) per Arduino Uno
Questi continui rimbalzi, che avvengono in un tempo brevissimo (generalmente fra 0,1 e 5ms), vengono percepiti dal software in esecuzione come ripetute pressioni del pulsante e quindi erroneamente conteggiati. Il problema viene aggirato impiegando soluzioni cosiddette di anti-rimbalzo (debouncing) che possono essere circuitali o software. Una delle soluzioni software più semplici è quella di far eseguire un'istruzione di attesa, di un tempo pari, o leggermente superiore, a quello di rimbalzo, in modo che il programma ignori sicuramente queste innumerevoli commutazioni. Al termine di questo periodo, per sicurezza, si torna a leggere lo stato del pulsante: se è corrispondente a quello attivo (es. livello alto) il pulsante è stato dunque "de-rimbalzato" (debounced) e quindi può essere eseguito il codice previsto all'occorrenza della pressione del bottone.
HARDWARE
Il pulsante N.A. è collegato fra il pin di ingresso (2) e la massa; il resistore di pull-up è quello interno dell'ATmegax8: quindi la pressione del pulsante comporta, a regime, la lettura sul pin 2 di un livello logico LOW, mentre il rilascio comporta, a regime, la lettura di un livello logico HIGH. Sul pin 9 è collegato un LED (attraverso una resistenza da 220..330 Ohm), che, alla pressione del pulsante, commuterà il suo stato da acceso a spento e viceversa.
/* * Debounce con millis() sulla pressione e sul rilascio * del pulsante. * */ const int P1=2; // pulsante const int L1=9; // LED int statoP1=LOW; // stato P1 (premuto LOW / rilasciato HIGH) int statoP1prec=LOW; // stato precedente P1 int statoL1=LOW; // stato LED (spento LOW / acceso HIGH) int flag=0; // 1: pressione o rilascio int T=5; // tempo attesa bouncing (5ms) unsigned long t1; // marker temporale di millis() void setup() { pinMode(P1, INPUT_PULLUP); // attiva la R pull-up interna pinMode(L1, OUTPUT); digitalWrite(L1, statoL1); } void loop() { statoP1 = digitalRead(P1); // rilevata una pressione o un rilascio if (statoP1 != statoP1prec && !flag) { flag=1; // flag di avvenuta pressione/rilascio t1=millis(); // marca inizio conteggio tempo } // se si è esaurito il rimbalzo if ( millis()-t1 >= T && flag) { flag=0; // azzera flag (per successive pressioni/rilasci)
// se è una pressione if (statoP1==LOW) { // istruzioni da eseguire alla pressione di P1: statoL1=!statoL1; digitalWrite(L1, statoL1); } } // istruzioni da eseguire al di fuori della pressione di P1: statoP1prec = statoP1; }



