Leggere un valore analogico direttamente dal registro ADCH in asincrono

Buongiorno,
ho necessità di leggere un pin analogico senza che la lettura analogica introduca un ritardo. Non ho necessità ne' di alte velocità di acquisizione e ne' di utilizzare i 10 bit, 8 bit sono sufficienti.
Non ho necessità nemmeno di usare l'interrupt.

Pensavo di usare questo codice

 ` /*  The bit of code below was taken from:
   *  http://yaab-arduino.blogspot.it/p/oscope.html
   */
  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (0 & 0x07);    // set A0 analog input pin
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX |= (1 << ADLAR);  // left align ADC value to 8 bits from ADCH register

  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements`

per settare il convertitore e poi, nel loop, dove ne ho bisogno eseguire:

valoreAnalogico = ADCH;

Funziona? Lo chiedo perchè cercando in rete ho trovato molte cose diverse ma questa mi sembra semplice e funzionale e non introduce alcun ritardo nel loop da sembrare troppo bella.
Qualcuno potrebbe suggerirmi la configurazione per lasciare il prescaler a 128?

Grazie

@fabio67 : in conformità al REGOLAMENTO , punto 7, cortesemente edita il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone a forma di piccola matita :pencil2: che si trova in basso del tuo post), seleziona TUTTA la parte di codice e premi l'icona </> nella barra degli strumenti per contrassegnarla come codice.

Per maggiori informazioni ... punto 17.2 del succitato regolamento. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà sistemato il codice, nel rispetto del suddetto regolamento nessuno ti risponderà, quindi ti consiglio di fare il tutto al più presto. :wink:

Scusate, avevo cliccato PRIMA l'icona e poi inserito il codice tra le virgolette che vengono mostrate pensando fosse la stessa cosa.
Fatto

Mi rispondo da solo, se non sbaglio:

ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0)

ma mi rimane un dubbio.
Mi sembra di capire che per far funzionare in maniera continua l'ADC ci sia bisogno di un segnale di trigger configurabile con il registro ADCSRB ma, nell'esempio che ho trovato e che ho riportato, il registro viene azzerato e non riconfigurato.
Può il convertitore essere triggerato dal segnale di EOC in modo da non essere necessario alcun altro segnale? O comunque funzionare in maniera continua senza una ben precisa frequenza di campinamento?

Prova a dara un'occhiata qui, nella sezione " Free running sampling" spiega come settare l'ADC per la lettura continua, leggendo il risultato con un interrupt.
Attenzione che nel codice è stata omessa la keyword "volatile" nella dichiarazione di aval, necessaria visto che si usa nell'interrupt.

Ciao, Ale.

1 Like

A suo tempo avevo fatto anche io delle prove per ADC FreeRunning ed avevo verificato la lettura anche su due canali diversi (passaggio da A0 ed A1 e viceversa) ... magari questo programmino può essere utile :wink: :

#include <avr/sfr_defs.h>

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() {
   delay ( 500 );
   Serial.begin ( 115200 );
   //
   // Init ADC for freeRunning mode prescaler 32, VREF internal 5V, start on A0
   ADCSRA = 0;
   sbi ( ADCSRA, ADEN );
   sbi ( ADCSRA, ADATE );
   sbi ( ADCSRA, ADPS2 );
   sbi ( ADCSRA, ADPS0 );

   ADCSRB = 0;

   ADMUX  = 0x40;

   sbi ( ADCSRA, ADSC );
}

void loop() {
   int analog_A0, analog_A1;
   unsigned long tStart_0, tEnd_0, tStart_1, tEnd_1;
   //
   // read 10 times A0 and then calculates the average of the values
   tStart_0 = micros();
   analog_A0 = 0;
   for ( byte i = 0; i < 10; i++ ) {
      loop_until_bit_is_set ( ADCSRA, ADIF );
      analog_A0 += ADC;
      cbi ( ADCSRA, ADIF );
   }
   tEnd_0 = micros();
   analog_A0 /= 10;
   //
   // switch to analog port A1
   tStart_1 = micros();
   cbi ( ADCSRA, ADEN );
   ADMUX  = 0x41;
   sbi ( ADCSRA, ADEN );
   sbi ( ADCSRA, ADSC );
   // read one time analog port A1
   loop_until_bit_is_set ( ADCSRA, ADIF );
   analog_A1 = ADC;
   cbi ( ADCSRA, ADIF );
   //
   // switch back to analog port A0
   cbi ( ADCSRA, ADEN );
   ADMUX  = 0x40;
   sbi ( ADCSRA, ADEN );
   sbi ( ADCSRA, ADSC );
   tEnd_1 = micros();
   //
   // print the values
   Serial.print ( "Valore A0 = " );
   Serial.print ( analog_A0 );
   Serial.print ( " - Elapsed time 0 = " );
   Serial.println ( tEnd_0 - tStart_0 );
   Serial.print ( "Valore A1 = " );
   Serial.print ( analog_A1 );
   Serial.print ( " - Elapsed time 1 = " );
   Serial.println ( tEnd_1 - tStart_1 );
}

Guglielmo

1 Like

Grazie a entrambi per i suggerimenti.
Vi aggiorno comunque su dei test fatti : la porzione di codice, trovata su internet e ricondivisa, funziona senza interrupt e non introduce ritardo nel loop.

Fabio

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.