AD prevodnik, rozbehnuti, atmega168

Opět Vás zdravím.
Momentálně se snažím naučit a laboruju s AD převodníkem v atmeze168. Problém je, že nejsem moc angličtinář, abych si přelouskal všechno co je v datashitu… Stáhnul jsem si nejaký kód, že to pochopím z něj v simulátoru, ale převod se mi nějak nedaří v ADC jsou pořád samé nuly…

a ještě takové noob otázky:

  1. naco je tam ta reference? Tím se určuje nejvyžší hodnota tzn. 1024?
  2. a proč je tam ten prescaler? přece čím rychlejší převod tím líp ne? Nebo to má nejaký vliv na přesnost?

zapojení:
7 - VCC +5V
8 - GND zem
20 - AVCC +5V
21 - AREF +5V
22 - GND zem
23 - střed odporového děliče mezi +5V a zemí

Kód je takovýhle:

#include <avr/io.h>
#include <util/delay.h>

     
int16_t ReadADC(uint8_t __channel){
       ADMUX |= __channel;                // Channel selection
       ADCSRA |= _BV(ADSC);               // Start conversion
       while(!bit_is_set(ADCSRA,ADIF));   // Loop until conversion is complete
       ADCSRA |= _BV(ADIF);               // Clear ADIF by writing a 1 (this sets the value to 0)
     
       return(ADC);
}
     
void adc_init(){
            ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); //Enable ADC and set 128 prescale
}
     
int main (void){
        
		adc_init();
     
		while (1){
			DDRD=0xFF;
			PORTD=ReadADC(0);
			while(1) asm volatile("nop");
		}     	
}

Děkuji

  1. ano
  2. v onom DS by ses dočetl, že f(adc) má výt v určitém rozsahu. Obvykle 50-200 kHz. Frekvence mimo rozsah snižuje rozlišení.
    Program by měl fungovat, provede ovšem pouze 1 převod, pak se zasekne na druhym while. Na port by se mělo vypsat dolních 8bitů (2 nejvyšší jsou mimo rozsah a bylo by dobrý zkontrolovat jesli překladač nepoužije instrukce na kopírování wordu a nepřepíše tím vedlejší registr).

AD převod v simulátoru???

Koukám na to v simulátoru, ale pouštím přes debugwire. Nevím no, s tím potrem jsem tam dal já, na otestvání. Čekal bych že v tech 8mi bitech bude aspon nějaká jednička. Každopadně, když se dokončí převod, ten 16bitový ADC registr je prázdný…

Program funguje, zkoušel jsem v reálu.

  1. Místo připojení +5V na pin AREF je lepší nastavit v kódu referenci AVCC.
    V datašítu v tabulce “Voltage Reference Selections for ADC” najdeš jak nastavit bity REFS0,REFS1.

  2. ADMUX |= __channel;
    To není dobře.
    Zkus si v simulátoru přepnutí z kanálu 5 na 2:
    ADMUX |= 0;
    ADMUX |= 5;
    ADMUX |= 2;

  3. ADCSRA |= _BV(ADSC); while(!bit_is_set(ADCSRA,ADIF)); // Loop until conversion is complete ADCSRA |= _BV(ADIF); // Clear ADIF by writing a 1 (this sets the value to 0)Toto funguje, ale jednodušší je využít toho, že bit ADSC se po skončení převodu vrátí do nuly.
    ADCSRA |= _BV(ADSC); while(bit_is_set(ADCSRA,ADSC)); // Loop until conversion is complete

Tak jsem to dnes pustil znovu a jede to, takže byl nejspíš problém někde na mé straně(asi nějaký nedotek v kontaktním poli). Admux “|=” jsem opravil na “=”. Děkuju za rady.

Oprava je ovšem špatná. V tom registru jsou další bity, jako nastavení reference a zarovnání dat. Tohle nastavení každym převodem vynuluješ. |= bylo správně, jen je předtím potřeba ony 4 bity muxu vynulovat (1 nop za změnou kanálu taky není od věci).

V tom konkrétním případě to zrovna vyhovovalo. Teď už je to lepší? :slight_smile:

ADMUX&=(0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); asm volatile("nop"); ADMUX|=__channel;

Ani ne :slight_smile: .ADMUX &= ~((1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0)); ADMUX |= __channel; asm volatile("nop");
Výsledkem “0<<x” je nula. Když pak touto nulou vymaskuješ jakýkoli registr, zbyde v něm opět nula, nikoli původní hodnoty na požadovaných místech.

Ovšem “MUX4” asi bude překladač u M168 hledat poměrně těžko :smiley:.

Njn musím se ještě hoodně učit. Ještě že ty programy po mě nebudeš nikdy číst :laughing: