Problema ingressi analogici

Ma si deve dividere per 1024, come vedo in giro, o per 1023? (che mi sembra più corretto)

PaoloP:
Ma si deve dividere per 1024, come vedo in giro, o per 1023? (che mi sembra più corretto)

Argomento già affrontato, la tensione presente su un pin analogico è pari a (COUNT ADC * Aref) / 1024, o se preferisci (Aref/1024) * COUNT ADC.
In pratica il numero di step di un ADC è pari alla relativa potenza di due della risoluzione + 1, p.e. 10 bit = 1024 step, perché conta anche lo 0 come step reale, da 0 a 1023 = 1024 step, da questo consegue che la reale massima tensione misurabile, prima dell’overflow, è pari ad Aref - 1 step o se preferisci è pari ad Aref/1024 * 1023 con un ADC da 10 bit.

Ringrazio per le benedizioni (@ Astro: è proprio Patrona :roll_eyes:?) @ Cyb: grazie, le varie info ovviamente mi sono già note, invece devo dedicare un po' di tempo a quello sketch finale, che non so interpretare, mi è parso di capire che riesce a leggere la tensione dell'ARef INTERNAL, anche se mi sembra stranissimo. @ Paolo: il concetto è semplice, come ha detto Astro, il range va da 0 a 1023, quindi sono 1024 step, per cui la tensione di riferimento la devi dividere per 1024, quando però vai a ricalcolare il valore dello step, esso è massimo 1023.

Ho fatto fare l'esercizio a mio figlio di 7 anni :) gli ho disegnato 10 omini con magliette numerate 0-1-2-3-4-5-6-7-8-9 e ho messo 10 caramelle ... Ora dimmi quante caramelle prende ogni bambino in uguale quantità... :D :D :D

Se vuoi comprendere il criterio non devi attribuire il numero come tale al bambino, prova ad usarlo come età, dove per 0 intendi uno che ancora non è nato :P

Io non riesco a comprenderlo come una cosa inesistente, mi appare più come oggetto (in questo caso) che si chiama 0 un semplice nome. nella matematica quotidiana applicata di tutti i giorni lo 0 rappresenta una linea neutra che divide il positivo dal negativo, significa il nulla... Siccome hanno iniziato le divisioni da 2 giorni e lo zero come cifra iniziale è ancora sconosciuto volevo vedere se il 9 finale lo ingannava considerando 9 bambini in totale, invece mi ha detto 1 col resto di 0 :). Ci sono quasi rimasto male eheheheh

Stessa cosa per i valori delle analog sono 1024 valori poichè lo 0 lo vedo più come nome-oggetto .... la prima cella si chiama zero, nell'array la prima cella si chiama 0, ma tradotto in matematica definiamola di tutti i giorni è la n°1

I bambini ad ogni generazione mostrano un'intelligenza superiore, è questa società di mrd che quando arrivano a 12-13 anni li rincoglionisce, li standardizza e li costipa in quello schifo che vedi per le strade e davanti alle scuole, per non parlare delle discoteche ]:D

Comunque mi sono un po' perso, cioè a te è chiara questa cosa del 1023/1024 oppure no? Ti faccio la domanda perché quando se ne parlò tempo fa io ci persi un po' di testa e di pazienza, solo quando ho cominciato a studiare e sperimentare mi è diventato tutto chiaro e inconfutabile. :sweat_smile:

sisi a me il concetto è chiaro, riesco bene a manipolare valori che partono da zero, a volte nelle formule mi dimentico di mettere -1, ma per il resto è ok :D . Mi è chiaro ciò che hai descritto sul tuo studio degli ADC, gran bel lavoro, una parte non ho capito

qui l'uovo deve valere la candela

:D :D e poi

Ho messo a punto una trentina di formule che serviranno ad uscire fuori da qualsiasi situazione iniziale ed a stabilire con esattezza assoluta (nei limiti della risoluzione dell'ADC) a cosa corrisponde una data lettura restituita dall'ADC.

ci puoi dare qualche indicazione, cioè cosa elabori in queste formule? cosa intendi?

ciao

Sempre a proposito della questione 1023-1024, ad ulteriore riprova vi rimando a questa mia spiegazione su come funziona l'ADC degli AVR. Se sommiamo i singoli pesi dei bit usati per la conversione otteniamo "512+256+128+64+32+16+8+4+2+1 = 1023", però dato che ogni bit agisce sul DAC come peso nominale, ovvero potenze di due del relativo bit (0-9), ne consegue che il bit più alto divide la tensione su Aref per due, p.e. 5V /2 = 2.5V e questo ci porta al peso del singolo step che per forza di cose deve essere pari a 5V / 1024, infatti se facciamo 5V/1024 * 512 = 2.5 Volt.

Io ho capito questo:
Se l’ADC divide l’intervallo di misurazione in 1024 step, ogni step è pari a 5/1024 = 4.882 mV
Se cerco di misurare una corrente di 3 mV mi restituisce 0 perché nell’intervallo 0-4.8, corretto?
Se voglio misurare 5V restituisce 1023 perché è tra 4.994 e 5, giusto?
Oppure arrotonda e salta sempre al successivo a meno che non si zero?

La saga del ADC continua :slight_smile:
Dato che spesso vedo scritte cose che stridono non poco con quanto scritto sul data sheet del 328, p.e. che tocca fare più letture a perdere quando si cambia il canale, stamattina mi sono divertito a fare alcune prove pratiche.
Il circuito di test è costituito da un semplicissimo partitore con tre uscite realizzato mettendo in serie queste resistenze: “150 ohm, 220 ohm, 380 ohm, 820 ohm”, GND è collegato alla r da 150 e il +3.3V è collegato alla r da 820 ohm e ad Aref, ho misurato con un multimetro le reali tensioni in modo da avere un riscontro preciso sulla misura e sono: “0.311V, 0.771V, 1.58V” mentre l’esatto valore del 3.3V è 3.302V.
Le tensioni sono collegate agli ingressi A0, A1, A3, gli ingressi A2, A4, A5 sono liberi.

Lo sketch di test è questo:

float ADC_l, ADC_2, ADC_3, ADC_4, ADC_5, ADC_6;
byte i;

void setup()
{
  analogReference(EXTERNAL);
  
  pinMode(A0,INPUT);  
  pinMode(A1,INPUT); 
  pinMode(A2,INPUT); 
  pinMode(A4,INPUT); 
  pinMode(A5,INPUT); 

  pinMode(13, OUTPUT);

  digitalWrite(13, HIGH);  
  Serial.begin(19200);
}

void loop() 
{
  for(i=0;i<20;i++) 
  {  
    ADC_l = analogRead(A0);    
    ADC_2 = analogRead(A1); 
    ADC_3 = analogRead(A2); 
    ADC_4 = analogRead(A3);
    ADC_5 = analogRead(A4); 
    ADC_6 = analogRead(A5); 

    Serial.print(ADC_l*0.00322);
    Serial.print(",");
    Serial.print(ADC_2*0.00322);
    Serial.print(",");
    Serial.print(ADC_3*0.00322);
    Serial.print(",");
    Serial.print(ADC_4*0.00322);
    Serial.print(",");
    Serial.print(ADC_5*0.00322);
    Serial.print(",");
    Serial.println(ADC_6*0.00322);
  }
  while(1);
}

La costante 0.00322 è data 3.302 / 1024, in pratica leggo tutti gli ingressi ADC, stampandone il valore, per 25 volte consecutive.

Il risultato è il seguente:

0.306,0.763,1.121,1.578,1.558,1.826
0.306,0.763,0.886,1.578,1.507,1.616
0.306,0.763,0.808,1.578,1.526,1.565
0.306,0.763,0.789,1.578,1.533,1.546
0.306,0.763,0.786,1.578,1.546,1.542
0.306,0.763,0.782,1.578,1.555,1.546
0.306,0.763,0.782,1.578,1.558,1.549
0.306,0.763,0.782,1.578,1.562,1.552
0.306,0.763,0.782,1.578,1.565,1.552
0.306,0.763,0.779,1.578,1.568,1.558
0.306,0.763,0.782,1.578,1.568,1.558
0.306,0.763,0.782,1.578,1.571,1.565
0.306,0.763,0.782,1.578,1.568,1.562
0.306,0.763,0.779,1.575,1.565,1.562
0.306,0.763,0.779,1.578,1.565,1.562
0.306,0.763,0.776,1.578,1.562,1.558
0.306,0.763,0.776,1.578,1.558,1.558
0.306,0.763,0.773,1.578,1.555,1.555
0.306,0.763,0.770,1.578,1.552,1.552
0.306,0.763,0.766,1.578,1.552,1.552

Come visibile non solo i valori di A0, A1 e A3 sono coerenti con le reali tensioni, nel limite della precisione del ADC, si nota pure come gli ingressi lasciati liberi siano fortemente influenzati dalla misura dell’ultimo ingresso realmente collegato ad una tensione.

Come mai la misura in sequenza dei cinque ingressi, senza buttare una lettura, è corretta ?

La risposta è semplicissima, su Ardino l’ADC viene fatto lavorare in single run e non in free run, infatti guardando il relativo codice troviamo quanto segue:

#if defined(ADCSRA) && defined(ADCL)
	// start the conversion
	sbi(ADCSRA, ADSC);

	// ADSC is cleared when the conversion finishes
	while (bit_is_set(ADCSRA, ADSC));

	// we have to read ADCL first; doing so locks both ADCL
	// and ADCH until ADCH is read.  reading ADCL second would
	// cause the results of each conversion to be discarded,
	// as ADCL and ADCH would be locked when it completed.
	low  = ADCL;
	high = ADCH;

Il bit ADCC (registro ADCSRA) viene settato ogni volte per avviare la conversione, si autoresetta alla fine, e non viene settato il bit ADATE (registro ADCSRA) applicando come sorgente ADIF, il che consentirebbe l’auto trigger del ADC ogni volta che termina una conversione (free run).
Presumibilmente nelle vecchie versioni di Arduino la gestione del ADC era in free run, altrimenti non sarebbe stato necessario il delay(1), ora commentato, all’interno della funzione, sicuramente poi è stato scelto il modo single run per non dover inserire un delay forzato o obbligare gli utenti a gettare la prima lettura dopo il cambio canale, in modo single run il problema non esiste perché la commutazione dell’ingresso avviene con l’ADC fermo.
Ho controllato il sorgente “wiring_analog.c” della versione 0023, anche questa lavora in single run, praticamente il sorgente è lo stesso dell’attuale 1.0.4 salvo le differenze su i controlli del tipo processore per gestire la Leonardo.

Adesso scatta la domanda da 1.000.000 di Euro, come mai a volte è comunque necessario buttare via delle letture, quando si cambia canale, per ottenere dei valori corretti ?
Anche in questo caso la risposta è semplicissima, il problema è legato all’impedenza d’uscita del generatore di tensione che andate a misurare, se questa è maggiore di 10 kohm il sistema di campionamento del ADC non riesce a recepire la nuova tensione con sufficiente rapidità pertanto sono necessari più cicli di lettura per permettergli di adattarsi.
In questi casi la vera soluzione è aumentare il tempo di sampling del ADC, però su Arduino è fisso a ~10ksps e per modificarlo tocca agire direttamente su i registri del ADC, se non si è capaci di farlo si fa prima ad eseguire 2-3-…n letture consecutive in modo da ottenere lo stesso il corretto valore.

Dal data sheet del 328 sezione ADC.

The ADC is optimized for analog signals with an output impedance of approximately 10 k? or less.
If such a source is used, the sampling time will be negligible. If a source with higher imped-ance is used, 
the sampling timewill depend on how long time the source needs to charge the
S/H capacitor, with can vary widely. The user is recommended to only use low impedance
sources with slowly varying signals, since this minimizes the required charge transfer to the S/H
capacitor.

PaoloP: Se l'ADC divide l'intervallo di misurazione in 1024 step, ogni step è pari a 5/1024 = 4.882 mV

Esatto

Se cerco di misurare una corrente di 3 mV mi restituisce 0 perché nell'intervallo 0-4.8, corretto?

Esatto, però misuri una tensione e non una corrente :)

Se voglio misurare 5V restituisce 1023 perché è tra 4.994 e 5, giusto? Oppure arrotonda e salta sempre al successivo a meno che non si zero?

L'ADC non arrotonda, il numero dei count aumenta di 1 ogni volta che la tensione incrementa di valore pari a quello dello step. Esempio pratico, se lo step vale 5 mV esatti (per semplicità) il numero dei count rimane 0 fino a che la tensione non raggiunge 5mV, rimane 1 fino a che la tensione non raggiunge 10 mV, rimane 2 fino a che la tensione non raggiunge 15 mV, così via fino al valore 5*1023 = 5.115 V, da questo punto in poi il numero dei count rimane fisso a 1023 perché questo è il valore massimo rappresentabile dal ADC, se la tensione sale ulteriormente non c'è modo di saperlo.

così via fino al valore 5*1023 = 5.115 V, da questo punto in poi il numero dei count rimane fisso a 1023 perché questo è il valore massimo rappresentabile dal ADC, se la tensione sale ulteriormente non c'è modo di saperlo.

La tensione sulle entrate analogiche (come su tutte le entrate) deve restare sotto la tensione di alimentazione +0,5V. Se la tensione supera questo livello i diodi di protezione conducono e si rischia che una corrente troppo alta daneggi l' ATmega. Ciao Uwe

uwefed: La tensione sulle entrate analogiche (come su tutte le entrate) deve restare sotto la tensione di alimentazione +0,5V. Se la tensione supera questo livello i diodi di protezione conducono e si rischia che una corrente troppo alta daneggi l' ATmega.

In realtà se c'è una sufficiente resistenza in serie al pin la tensione, prima della R, può diventare anche molto più alta del limite Vdd+0.5V perché limita la corrente nei diodi, che poi è lo scopo delle resistenze da 100-330 ohm messe in serie ai pin dei micro, come protezione, quando si devono interfacciare con sistemi dotati di alimentazione diversa da quella del micro. C'è una interessante AN di Microchip che mostra come collegare direttamente la 220 AC in ingresso ad un loro micro 12C508 (molto vecchio e ormai obsoleto), sfruttando i diodi di clamping con una resistenza da 20 Mohm in serie al pin, al fine di realizzare un dimmer per lampadine ad incandescenza.,

Usando PORTK e PORTF so solo se i valori si trovano a 0 o 1023 tramite il bit, ottimo se li setto come digitali.
Ma in modalità analog c’è la possibilità di prelevare il valore direttamente dai registri senza fare analogread?

pablos: Ma in modalità analog c'è la possibilità di prelevare il valore direttamente dai registri senza fare analogread?

Non riesco a capire il senso della domanda, se il pin è settato come input per ADC non puoi usarlo come input digitale e viceversa.

PaoloP: Io ho capito questo: Se l'ADC divide l'intervallo di misurazione in 1024 step, ogni step è pari a 5/1024 = 4.882 mV Se cerco di misurare una corrente di 3 mV mi restituisce 0 perché nell'intervallo 0-4.8, corretto? Se voglio misurare 5V restituisce 1023 perché è tra 4.994 e 5, giusto? Oppure arrotonda e salta sempre al successivo a meno che non si zero?

Secondo me nell'uso "quotidiano" si può approssimare la spiegazione di Astrobeed specificando che ciò che interessa sapere in una conversione, oltre alla risoluzione di 10 bit, è la tensione di riferimento: con questi 2 valori si ha la minima tensione misurabile. Ovviamente riducendo la tensione di riferimento si diminuisce la differenza fra uno step e l'altro, come infatti si consiglia sempre di utilizzare l'Aref interna di 1,1V.

Quindi con un po' di matematica si ha che la minima V misurabile è data da Aref/1024. Con 5V, si ha 5/1024=4,8 mV Con 1V1 si ha 1,1/1024=1,07mV

Salve, ho collegato ad un Arduino Uno + Ethernet Shield che utilizzo come webserver con la libreria webduino, due sensori analogici LM35 (temperatura) e un humidity sensor Quando collego le due sonde il risultato della temperatura è sballato mentre se le collego singolarmente i risultati sono perfetti! Che problema può avere???

gianmarco_sitzia: Salve, ho collegato ad un Arduino Uno + Ethernet Shield che utilizzo come webserver con la libreria webduino, due sensori analogici LM35 (temperatura) e un humidity sensor Quando collego le due sonde il risultato della temperatura è sballato mentre se le collego singolarmente i risultati sono perfetti! Che problema può avere???

Invece di agganciarti al thread di un'altra persona, aprine uno tuo e metti non solo lo sketch che stai usando ma anche il circuito del tuo progetto specificando bene i componenti (che sensore di umidità è, per esempio). ;)