Problema con analogRead

Ho uno strano problema con analogRead() e non riesco a capire perchè mi succede.

Uso tre ingressi analogici e un lcd per vedere i valori letti.
Uno lo uso come un digitale, quindi nel setup() ho messo pinMode INPUT numerando il pin secondo i pin analogici ma da 14 a 19 anzichè da 0 a 5.
Agli altri due pin ho collegato dei potenziometri.
Con un analogRead() leggo il primo valore analogico dal potenziometro.
Il secondo valore analogico dell'altro potenziometro lo leggo solo quando vedo che il pin che uso come digitale è alto, per farlo uno digitalRead() e un interruttore.
Se lascio l'interruttore aperto vedo il primo valore analogico correttamente.
Se invece chiudo l'interruttore il secondo valore analogico lo vedo correttamente, ma il primo che continuo a leggere sale e scende da solo...
Non capisco perchè succeda, ho letto che servono almeno 100us per ricaricare il condensatore dell'analogRead(), ma anche mettendo 10 millisecondi di delay tra un analogRead() e l'altro non cambia...

domanda banale: il primo ingresso analogico è collegato a qualcosa con tensione fissa,quando lo vedi flottare?

Come hai collegato l'interuttore? usi una resistenza pullup/pulldown?
Ciao Uwe

dopo varie prove ho scoperto che se prima di leggere quello che mi serve metto un'analogRead() a vuoto funziona tutto correttamente.
Per esempio se invece di mettere

int a = analogRead(A0);

metto

analogRead(A0);
int a = analogRead(A0);

funziona.
Ma è normale che faccia così?

La prima volta che si usa l'ADC è bene fare una lettura a vuoto per calibrare il circuito S&H interno. Questo vale anche nel caso di ADC spento per motivi di sleep o altro.
Potresti postare lo sketch usato per capire cosa può succedere?

Allora, ecco quello che ho scoperto:

#include "LiquidCrystal.h"
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);
}

void loop() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(analogRead(A0));
  lcd.setCursor(8, 0);
  lcd.print(analogRead(A2));
  lcd.setCursor(0, 1);
  lcd.print(analogRead(A1));
  lcd.setCursor(8, 1);
  lcd.print(analogRead(A3));
  
  delay(500);
}

Con questo codice stampo sull'lcd quello che leggo dai pin analogici 0, 1, 2 e 3.
Quello che c'è collegato ai pin A0 e A1 lo lascio fisso, mentre faccio variare quello collegato ai pin A2 e A3:

  • se alzo A3 cambia anche il valore di A0
  • se alzo A2 cambia anche il valore di A1

Quando alzo A2 o A3 vedo correttamente i valori di A2 e A3 (almeno sembra che salgano correttamente), mentre gli altri valori si alzano di un po' ma non in modo stabile, rimangono sempre più alti del normale ma un po' salgono e un po' scendono.

Se invece faccio:

#include "LiquidCrystal.h"
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);
}

void loop() {
  lcd.clear();
  lcd.setCursor(0, 0);
  analogRead(A0);
  lcd.print(analogRead(A0));
  lcd.setCursor(8, 0);
  lcd.print(analogRead(A2));
  lcd.setCursor(0, 1);
  analogRead(A1);
  lcd.print(analogRead(A1));
  lcd.setCursor(8, 1);
  lcd.print(analogRead(A3));
  
  delay(500);
}

funziona tutto correttamente.
Anche se non metto analogRead() a vuoto per i pin A2 e A3 funziona, forse perchè A0 e A1 rimangono sempre uguali?

Se invece degli analogRead() a vuoto metto un delay(10) i valori diventano instabili come all'inizio.

p.s. non ho collegato più nessun interruttore.

p.p.s.

leo72:
La prima volta che si usa l'ADC è bene fare una lettura a vuoto per calibrare il circuito S&H interno. Questo vale anche nel caso di ADC spento per motivi di sleep o altro.

Intendi una lettura a vuoto all'inizio di tutto e poi basta o ogni volta prima di leggere da un pin analogico?
Perchè se metto una lettura a vuoto in setup() non funziona l'lcd.
edit: forse non si era resettato bene l'lcd :wink: ho riprovato e funziona ma i valori sono instabili come all'inizio.

Non vedo nel setup l'assegnazione degli ingressi analogici.

Se non lo fai, è normale che tu debba effettuare una "lettura a vuoto", poiché con essa Arduino capisce che quell'ingresso è di input.

cyberhs:
Non vedo nel setup l'assegnazione degli ingressi analogici.

Se non lo fai, è normale che tu debba effettuare una "lettura a vuoto", poiché con essa Arduino capisce che quell'ingresso è di input.

Se si usano i pin analogici come ingressi appunto analogici, non è necessario dichiarare i pin come input usando pinMode dato che questo controlla l'ingresso digitale del pin e non l'ADC, che viene agganciato al pin in oggetto dalla funzione analogRead.

@d407376:
esiste una modalità di lettura, descritta nel datasheet, detta "Free Running Mode", in cui si possono eseguire più letture una dietro l'altra. Se però in questa modalità si cambia canale (cioè pin letto), la prima lettura dopo il cambio di canale rispecchierà il canale precedente e solo quella successiva sarà riferita al nuovo canale.
Ora, analizzando l'analogRead dell'Arduino mi pare che sia impostata proprio questa modalità per cui il problema riscontrato potrebbe essere dato da questo. Quindi la lettura a vuoto per ricalibrare l'ADC è necessaria affinché esso cambi canale correttamente.

pinMode per i pin analogici sò che non va usato, come ha detto leo.

leo72:
@d407376:
esiste una modalità di lettura, descritta nel datasheet, detta "Free Running Mode", in cui si possono eseguire più letture una dietro l'altra. Se però in questa modalità si cambia canale (cioè pin letto), la prima lettura dopo il cambio di canale rispecchierà il canale precedente e solo quella successiva sarà riferita al nuovo canale.
Ora, analizzando l'analogRead dell'Arduino mi pare che sia impostata proprio questa modalità per cui il problema riscontrato potrebbe essere dato da questo. Quindi la lettura a vuoto per ricalibrare l'ADC è necessaria affinché esso cambi canale correttamente.

Grazie, ho capito il perchè :wink:
Mettendo un analogRead() a vuoto prima non è un grand problema, ma se si volesse mettere non in free running sarebbe possibile?
Questa modalità riguarda proprio l'altmega o come è scritta la funzione?

d407336:
se si volesse mettere non in free running sarebbe possibile?
Questa modalità riguarda proprio l'altmega o come è scritta la funzione?

La risposta semplice è no. Devi cambiare il core dell'Arduino ed ovviamente poi tutto quello che fa uso dell'analogRead non funzionerebbe più per come era stato inizialmente pensato per cui lascia perdere. :wink:

ok
un'altra cosa, se all'interno del programma metto analogReference(INTERNAL) per leggere da un pin, poi rimetto analogReference(DEFAULT) per leggere da un altro pin e lo faccio in continuazione non ci sono problemi?

d407336:
ok
un'altra cosa, se all'interno del programma metto analogReference(INTERNAL) per leggere da un pin, poi rimetto analogReference(DEFAULT) per leggere da un altro pin e lo faccio in continuazione non ci sono problemi?

Non collegare nulla al pin AREF, però.

no, non collego niente :wink:
chiedevo solo per sapere se fare continuamente queste operazione è troppo "stressante" per l'atmega

Ha ragione Leo quando dice che non è indispensabile usare il pinmode per gli ingressi analogici, ma io lo uso lo stesso per attivare o disattivare il resistore interno.

Cosa ne fai delle resistenze Pullup nei ingressi analogici? Sbagli la misura visto che creii un partitore resistivo tra impedenza del segnale che leggi e la resistenza pullup che é tra 20k e 50kOhm.
Ciao Uwe

uwefed:
Cosa ne fai delle resistenze Pullup nei ingressi analogici? Sbagli la misura visto che creii un partitore resistivo tra impedenza del segnale che leggi e la resistenza pullup che é tra 20k e 50kOhm.
Ciao Uwe

non ho capito a cosa ti riferisci...

d407336:

uwefed:
Cosa ne fai delle resistenze Pullup nei ingressi analogici? Sbagli la misura visto che creii un partitore resistivo tra impedenza del segnale che leggi e la resistenza pullup che é tra 20k e 50kOhm.
Ciao Uwe

non ho capito a cosa ti riferisci...

Si riferisce a cyberhs, che abilita le pull-up interne ma legge il pin in modo analogico. Non ho idea di come lavori arduino internamente, ma a basso livello si può scollegare la porta digitale condivisa con quella analogica, lasciando collegato solo il circuito di conversione AD, se arduino fà la stessa cosa allora abilitare le pull-up non porta alcuna differenza in quanto vengono scollegate dal pin.

Ciao.

No, l'Arduino non disabilita i buffer digitali sui pin analogici quando fa la lettura analogica.

leo72:
No, l'Arduino non disabilita i buffer digitali sui pin analogici quando fa la lettura analogica.

Ok, ora lo so, quindi rimane il quesito posto da uwefed nei confronti di cyberhs. Mi rispondo da solo, se al pin collegni un NTC verso GND eviti di usare una R serie fisica per il partitore.

Ciao.