[Risolto] ADC in Running Free Mode - Leggere 2 Ingressi

Ciao a tutti,
sono Marco e questo è il mio primo post sul forum.
Stò facendo il mio primo progetto con Arduino, e si tratta di ricostruire con componenti Thought Hole questo spelndido orologio:
http://www.vonnieda.org/tc18
e aggiungere funzionalità. Arrivo dalla programmazione PIC, ma questo è il mio primo progetto con arduino e processori AMTEL.
Ho questo problema. Il circuito dell'orologio, ha un Booster che trasforma i 9 Volt di alimentazione in 30-60 Volt per alimentare il display. Questa tensione, viene generata da un circuito Booster L-C ( qua il princicpio Make a simple boost converter).
La tensione generata viene re-inmessa dento all'Arduino tramite un partitore sul Pin ADC0, e poi elaborata per mantenere l'alta tensione stabile.
Ho preso il codice originale dell'orologio e lo sto riadattando, ma non riesco a fare una cosa. Vorrei mettere sul pin ADC2 una fotoresistenza e poi avere anche la regolazione automatica della luminosità, ma per come l'autore ha scritto il codice non riesco a fare 2 letture diverse dall'ADC.

Posto il codice di impostazione dell'ADC:

  // Internal 1.1V Voltage Reference, Single Ended Input on ADC0
  ADMUX = _BV(REFS1) | _BV(REFS0);
  // ADC Enable, ADC Auto Trigger Enable, ADC Interrupt Enable
  // ADC Prescaler 128
  ADCSRA |= _BV(ADEN) | _BV(ADATE) | _BV(ADIE) 
    | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
  // ADC Start Conversion (starts free running mode)
  ADCSRA |= _BV(ADSC);

Il codice è commentato bene e per quello che capisco, fa partitr l'ADC in Free Running. Mi sono documento e ho capito che si tratta di una modalità che permette all'ADC di effettuare letture continue, e scatenare un Interrupt, quando una lettura è discponibile.
Infatti vi posto la routine di interrupt come l'ho modificata io, ma non funziona:

ISR(ADC_vect) {
  uint8_t tmp;            // temp register for storage of misc data
  tmp = ADMUX;            // read the value of ADMUX register
  tmp &= 0x0F;            // AND the first 4 bits (value of ADC pin being used) 

    low = ADCL;
    high = ADCH;
 
  if (tmp == 0){
    if (voltage_sample++ > 20) {
      voltage_sample = 0;
     int adc = (high << 8) | low;
      voltage = 1.066f / (0x3ff - 1) * adc * 112.344;
      // We don't let the boost generator go below 10 or above 230
      // Those equate to roughly VCC and 60v so allowing it to
      // go too high can start blowing up components.
      if (voltage > voltage_target + voltage_drift && OCR2B > 10) {
        OCR2B--;
      }
      else if (voltage < voltage_target - voltage_drift && OCR2B < 230) {
        OCR2B++;
      }
    }
    ADMUX = ADMUX+2;            // add 1 to ADMUX to go to the next sensor
  }
  else if (tmp == 2){
        // put ADCvalue into whatever register you use for ADC2 sensor
        //ADMUX &= 0xF6;      // clear the last 4 bits to reset the mux to ADC0
        light = (high << 8) | low;
        ADMUX &= 0xF8;
        //Serial.println(light);
  } 

}

A quanto ho capito devo leggere gli ultimi 4 bit del registro ADMUX per capire che porta dell'ADC sto leggendo, fare la lettura di ADCL e ADCH, e poi a seconda di ADMUX ho il valore della porta che mi interessa.
Invece non è così, se eseguo questo codice sull'orologio, sembra che la fotoresistenza collegata al pin ADC2 prenda il sopravvento, e mi regoli la luminosità del display entrando nella routine quando tmp==0. Ho provato anche con altri ingressi ma nulla cambia.
Ho cercato un po' in giro ma non ho trovato molto aiuto.

Grazie a tutti

PS è un Arduino UNO, quindi ATMEGA 328P
PSS Mi piace cominciare subito con qualcosa di difficile, altrimenti non c'è gusto :slight_smile:

Ho sbloccato il tread senó nessuno puó rispondere.
Ciao Uwe Federer

Per il tubo VLD mi manca il riscaldamento del filo emettitore elettroni.
Quello normalmente deve essere alimentato in alternata per garantire una luminositá uniforme.
Ciao Uwe

uwefed:
Per il tubo VLD mi manca il riscaldamento del filo emettitore elettroni.
Quello normalmente deve essere alimentato in alternata per garantire una luminositá uniforme.
Ciao Uwe

Ciao Uwe,
grazie della risposta, ma questo step l'ho già passato. L'orologio funziona perfettamente e il tubo si accende e mostra i digit.
Ho il problema sull'ADC che ho scritto. In effetti sto rielaborando un progetto funzionante che utilizza un MAX6921 per pilotare i tubi.
Marco

UweFederer:
Ho sbloccato il tread senó nessuno puó rispondere.
Ciao Uwe Federer

Ciao scusa,
ma posso sbloccarlo io o deve farlo un moderatore?

Spiegami meglio.
Vuoi fare 2 letture dall'ADC, una fatta in automatico in free running mode ed una usando un'analogRead dal codice?
Se è così, non ti può funzionare perché nel momento in cui usi l'analogRead, l'ADC viene reimpostato. Inoltre l'ADC è multiplexato, quindi per fare 2 letture da 2 pin diversi viene cambiato canale ma l'ADC è sempre quello.
E' questo il problema o non ho capito io?

leo72:
Spiegami meglio.
Vuoi fare 2 letture dall'ADC, una fatta in automatico in free running mode ed una usando un'analogRead dal codice?
Se è così, non ti può funzionare perché nel momento in cui usi l'analogRead, l'ADC viene reimpostato. Inoltre l'ADC è multiplexato, quindi per fare 2 letture da 2 pin diversi viene cambiato canale ma l'ADC è sempre quello.
E' questo il problema o non ho capito io?

Ciao leo72,
no io voglio fare 2 letture da due pin diversi in Running Free Mode....
grazie

Vabbè, vuoi fare comunque 2 letture.
Però hai il problema che ti ho menzionato. Cambiando canale, il multiplexer viene reinizializzato e quindi ci sono alcune precauzioni da prendere.
Leggi il datasheet cap. 23.5.1 Il 2° paragrafo parla proprio del cambio di canale in free running.

se ricordo bene l'interrupt è lanciato anche in lettura singola.
In generale la prima lettura dopo il cambio pin va buttata via.

leo72:
Vabbè, vuoi fare comunque 2 letture.
Però hai il problema che ti ho menzionato. Cambiando canale, il multiplexer viene reinizializzato e quindi ci sono alcune precauzioni da prendere.
Leggi il datasheet cap. 23.5.1 Il 2° paragrafo parla proprio del cambio di canale in free running.

lesto:
se ricordo bene l'interrupt è lanciato anche in lettura singola.
In generale la prima lettura dopo il cambio pin va buttata via.

Grazie leo72, lesto,
mi leggo il datasheet stasera, però a quanto dici lesto una cosa del genere?

ISR(ADC_vect) {

  volatile byte low = 0;
  volatile byte high = 0;
  volatile byte low1 = 0;
  volatile byte high1 = 0;

  uint8_t tmp;            // temp register for storage of misc data
  tmp = ADMUX;            // read the value of ADMUX register
  tmp &= 0x0F;            // AND the first 4 bits (value of ADC pin being used) 

    low = ADCL;
    high = ADCH;
 
  if (tmp == 0){
      voltage = 1.066f / (0x3ff - 1) * adc * 112.344;
    ADMUX = ADMUX+2;            // add 1 to ADMUX to go to the next sensor
  }
  else if (tmp == 2){
        low1 = ADCL;
        high1 = ADCH;
        light = (high1 << 8) | low1;
        ADMUX &= 0xF8;
  } 

}

dovrebbe funzionare?

Grazie

se il problema è quello di "scartare" la prima lettura in realtà credo che basti invertirle...

per il codice che hai scritto mi pare solo mancare la parte relativa a OCR2B, che non capisco a cosa serva (non ho il datasheet sotto mano)

lesto:
se il problema è quello di "scartare" la prima lettura in realtà credo che basti invertirle...

per il codice che hai scritto mi pare solo mancare la parte relativa a OCR2B, che non capisco a cosa serva (non ho il datasheet sotto mano)

Grazie lesto, stasera provo.
Per OCR2B non so esattamente, il codice non è mio, lo sto studianto ed adattando.
Il datasheet dice:

The Timer/Counter (TCNT2) and Output Compare Register (OCR2A and OCR2B) are 8-bit registers.

leo72:
Vabbè, vuoi fare comunque 2 letture.
Però hai il problema che ti ho menzionato. Cambiando canale, il multiplexer viene reinizializzato e quindi ci sono alcune precauzioni da prendere.
Leggi il datasheet cap. 23.5.1 Il 2° paragrafo parla proprio del cambio di canale in free running.

ciao leo, nel datasheet del 328P non c'è il paragrafo 23.5.1, si ferma al 23.3.3 :slight_smile:

lesto:
se il problema è quello di "scartare" la prima lettura in realtà credo che basti invertirle...

per il codice che hai scritto mi pare solo mancare la parte relativa a OCR2B, che non capisco a cosa serva (non ho il datasheet sotto mano)

Ciao lesto,
grazie per il suggerimento, ho invertitole letture nella routine di interrupt e adesso funziona perfettamente.
Giusto per capire io come funziona, e se avessi 3 sonde da leggere, diciamo A, B, e C, mi troverei nei valori ADCH e ADCL B, C e poi A?

Grazie Ancora.

Marco

l'ADC di default "pensa" a 10bit, i reguistri sono a 8 bit, da quì la necessita di usare 2 registri, uno tiene 8bit e l'altro gli alti 2

di solito ADCL tiene gli 8 bit più a destra (i meno sisgnificativi) e ADCH i 2 più significativi, ma con un flag li puoi invertire

se imposti l'ADC a lavorare a 8 bit userai solo ADCL

Ops. Cap. 24.5.1.
ADC Input Channels.

Comunque OCR2B è l'Output Compare Register B del timer 2 ed è usato per modificare la frequenza del segnale PWM generato sul pin OC2B del micro, che sicuramente è collegato al transistor che funge da switching per caricare il condensatore dello step-up.

In pratica il feedback della tensione generata viene utilizzato per regolare la stessa in modo da ottenere un valore di tensione più preciso e stabile.

lesto:
l'ADC di default "pensa" a 10bit, i reguistri sono a 8 bit, da quì la necessita di usare 2 registri, uno tiene 8bit e l'altro gli alti 2

di solito ADCL tiene gli 8 bit più a destra (i meno sisgnificativi) e ADCH i 2 più significativi, ma con un flag li puoi invertire

se imposti l'ADC a lavorare a 8 bit userai solo ADCL

Grazie lesto,
questo l'avevo capito leggendo il datasheet. quello che non mi è chiaro è la sequenza di lettura degli ingressi in running Free Mode. Se quello che ho capito è giusto devo scartare la prima lettura, quindi in caso di 3 ingressi su ADC0, ADC1 e ADC2, mi troverò le letture nella routine di interrupt nell'ordine ADC1, ADC2 e infine ADC0, dico bene?

Grazie

marcolino7:
quello che non mi è chiaro è la sequenza di lettura degli ingressi in running Free Mode. Se quello che ho capito è giusto devo scartare la prima lettura, quindi in caso di 3 ingressi su ADC0, ADC1 e ADC2, mi troverò le letture nella routine di interrupt nell'ordine ADC1, ADC2 e infine ADC0, dico bene?

Cambiando canale, la prima lettura effettuata sul nuovo canale è nulla perché riflette quella effettuata sul precedente canale.
Quindi passando da ADC0 ad ADC1, la prima lettura fatta su ADC1 sarà uguale all'ultima fatta su ADC0.