Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

4
voti

Misurare la luminosità esterna con l'ADC degli AVR

Utilizziamo l'utilissimo ADC integrato nell'ATMega328 in coppia con un fotoresistore per misurare il grado luminosità esterna.
Avendo a disposizione un'Arduino, utilizzo quello, ma nel codice non verrà utilizzata alcuna funzione di "semplificazione" fornita dalle librerie Arduino, si farà riferimento alle porte e ai registri dell'ATMega.


Il Circuito





Iniziamo a vedere com'è formato il circuito...
Sono presenti 8 LED, tutti collegati sulla PORTD dell'ATMega (pin 0-7 di Arduino), che avranno l'incarico di mostrare il valore della luminosità in forma binaria.
L'ADC però restituisce un numero a 10 bit in un registro a 16 bit (MIN = 0; MAX = 1023).
Viene quindi inserito un'altro LED sul 5° pin della PORTB (pin 13 di Arduino), che ci indicherà se i LED stanno mostrando i MSB o i LSB (MSB = LED on; LSB = LED off).
Come si vede sempre dal circuito, infine, è presente un fotoresistore che varierà il suo valore "resistivo" in base alla luce esterna.
E' aggiunta anche un resistenza di 100K per una misurazione più accurata in scarsità di luce.


Il Sorgente


Il codice utilizzato è il seguente, opportunamente commentato per una facile comprensione:

#include <avr/io.h>
#include <util/delay.h>
int main ()
{
  uint16_t adc_result;

    //Initialize PORTD pins to show the conversion result on 8 LEDs (first MSB, then LSB)
  DDRD = 0b11111111;
  
  //Initialize PORTB for MSB/LSB LED indicator
  DDRB = 0b11111111;
  
  //Initialize ADC
  ADCinit();

    while (1)
  {
    //Reading analog value from the fifth pin of PORTA (bit 5)
    adc_result = ADCread(5);
        //Pointer for MSB and LSB ---- AVR use Little Endian representation
    uint8_t *ptr = (uint8_t *) &adc_result;
    
    //Show binary value on LEDs
    //MSB (LED on PORTB is on)
    PORTB = 0b00100000;
    PORTD = ptr[1];
        //Wait 2 seconds
    _delay_ms(2000);
        //LSB (LED on PORTB is off)
    PORTB = 0b00000000;
    PORTD = ptr[0];
        //Wait 2 seconds
    _delay_ms(2000);
  }
}

void ADCinit ()
{
  //REFS1(bit 7) = 0 ---- REFS0(bit 6) = 1
  //Voltage Reference Selection = AVCC
  ADMUX = 0b01000000; 
  
  //ADEN (bit 7) = 1, ADC Enabled
  //ADPS2 (bit 2) = 1 ---- ADPS1 (bit 1) = 1 ---- ADPS0 (bit 0) = 1, Prescaler = FCPU/128
  ADCSRA = 0b10000111;
}


uint16_t ADCread (uint8_t channel)
{
  //Security (channel must be < 7, in ADPS2/ADPS1/ADPS0)
  ADMUX = (ADMUX & 0xF0) | (channel & 0x07);  
  
  //Conversion Start, set ADSC (bit 6) in ADCSRA register
  ADCSRA |= (1<<ADSC);
  
  //Wait for conversion complete (ADIF is set in ADCSRA when conversion is complete)
  while ( !(ADCSRA & (1<<ADIF)) );
  
  //Clear ADIF bit for other conversion in the future
  ADCSRA |= (1<<ADIF);
  
  //Conversion result is automatically saved in ADC register (16 bit register)
  return ADC;
}


Conclusioni



Il progetto è realizzato per testare il funzionamento dell'ADC integrato negli AVR, e sembra funzionare davvero bene, spero sia una risorsa utile per voi.

foto.jpg

foto.jpg

Un saluto a tutti,
Biagio.

3

Commenti e note

Inserisci un commento

di ,

Esatto, però il numero massimo dovrebbe essere 7 non 8 (vai da 0 a 7). Ovviamente devi poi prenderti la sola parte intera di questa proporzione (un cast a un int senza segno?). Per accendere i LED potresti pensare a un shift a sx del numero costante 0xFF: se il risultato della proporzione è 0, tutti i LED spenti, se è 1, si accende solo il primo e così via, fino a 7. Questo numero shiftato lo mandi sul Port dati dei LED. Ovviamente dovresti invertire la polarità dei LED: 0 (acceso) 1 (spento) Non ho avuto modo di provare quello che sto dicendo (può darsi che ho detto pure qualche cavolata). Prova ;)

Rispondi

di ,

In pratica sarebbe fare: (Risultato_ADC * 8)/1023

Rispondi

di ,

Ottimo. Però invece di visualizzare il dato "raw" che esce dall'ADC, utile a fini diagnostici/didattici ma poco attraente per gli esseri umani :-) prova a fare un luxmetro, con la sola stringa di 8 LED: tutti i LED spenti (ADC=0), nessuna luce, tutti i LED accesi, massima luce (ADC=1023).

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.