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:
naco je tam ta reference? Tím se určuje nejvyžší hodnota tzn. 1024?
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");
}
}
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).
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ý…
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.
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;
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).
Ani ne .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 .