logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[C][ATmega8] Przetornik ADC - pierwsze starcie

mateo19851 19 Lut 2010 16:21 3833 6
REKLAMA
  • #1 7719077
    mateo19851
    Poziom 16  
    Nie za bardzo mogę ogarnąć przetwornik A/C w ATmega8.
    Zrobiłem układ jak na schemacie. Chciałem żeby dioda zapalała się powyżej
    1V napięcia na potencjometrze, a do 1V była zgaszona.
    Napięciem odniesienia dla mnie miało być AVCC.Korzystam z 8 bitów ADCL.
    Konwersja wyzwalana int0.
    Program wygląda nastepująco:
    Załanczam standartowe biblioteki dla avr (przerwania, delay,io)

    Schemat :
    [C][ATmega8] Przetornik ADC - pierwsze starcie

    Kod:
    
    #define F_CPU 1000000
    
    int main(void){
    	inicjalizacja();
    	while(1){
    
    	}
    	
    
    }
    
    ISR(INT0_vect){
    	_delay_ms(80);//eliminuj drgania ze styków
    	ADMUX|=_BV(ADSC);//start konwersji
    	_delay_ms(100);//czekaj na wynik
    	if(ADCL<=0xCC){
    		PORTB&=~_BV(0);
    	}
    	else{
    		PORTB|=_BV(0);
    	};
    
    }
    
    
    void inicjalizacja(void){
    //ustawienie portów
    	DDRB|=_BV(0);
    	DDRC&=~_BV(0);
    	DDRD&=~_BV(2);
    	PORTD|=_BV(2);//pull-up
    //ADC
    	ADMUX|=(_BV(REFS0));
    	ADMUX&=~(_BV(REFS1)|_BV(ADLAR)|_BV(MUX0)|_BV(MUX1)|_BV(MUX2)|_BV(MUX3));
    	ADCSRA|=(_BV(ADEN)|_BV(ADSC)|_BV(ADPS));//zapoczątkowanie konwersji
    	ADCSRA&=~(_BV(ADPS1)|_BV(ADPS0));//preskaler CLK/16 (żeby bylo 50kHz)	
    //przerwanie INT0
    	SREG|=_BV(7);//globalna maska przerwan
    	MCUCR|=_BV(ISC01);
    	MCUCR&=~_BV(ISC00);
    	GICR|=_BV(INT0);//maska dla INT0
    	_delay_ms(100);//czekaj na pierwszą konwersję
    	
    }
    


    Układ jednak nie działa ,dioda wogóle nie świeci ... Co robię źle ?
  • REKLAMA
  • #2 7719201
    morson
    Poziom 14  
    Robisz kilka podstawowych błędów
    1. Po resecie odpowiednie rejestry procesora mają ustalone wartości (z reguły 0x00) i nie musisz im ustawiać ponownie bitów na 0 (patrz Datasheet).
    2. Używanie _delay_ms w przerwaniu to pomyłka, blokuje Ci możliwość odebrania kolejnego przerwania.
    3. Jeśli już koniecznie chcesz używać przerwań do odczytu ADC, to używaj przerwania dotyczącego zakończenia konwersji, a nie zaprzęgaj do tego licznika.
    
    ISR(ADC_vect)
    {
     int wartosc = ADC;
     // tu porównywania ewentualnie zmiana wejścia z którego będzie mierzone napięcie
     ADCSRA |= (1<<ADSC); // start kolejnej konwersji
    }
    

    Nie zapomnij aktywować zezwolenia na przerwanie.
    4. przerwania aktywuje się wygodniej sei() niż zapisywaniem do SREG.
    5. Dopiero odczytanie ADCH, pozwala na zapisanie do rejestrów przez mikrokontroler nowej wartości z aktualnego przetwarzania.
    6. Przy przetworniku niema czegoś takiego jak eliminacja drgań zestyków :)
  • REKLAMA
  • #3 7719239
    mateo19851
    Poziom 16  
    Drgania zestyków chciałem wyeliminować od przerwania INT0 wyzwalanego przyciskiem zwierającym do masy. Faktycznie zaglądłem jeszcze raz do datasheeta. Czyli to wszystko przez to,że nie odczytuje ACDH - jeśli bym wyrównał wynik do lewej to będzie chulać ? Schemat jest prawidłowo złożony ?
  • REKLAMA
  • #4 7719312
    morson
    Poziom 14  
    Na schemacie (nie przyglądałem się mu wcześniej) masz błąd ARef to wyjście lub wejście napięcia referencyjnego, nie możesz go zewrzeć do masy bo uszkodzisz wewnętrzne źródło, jeśli korzystasz z wewnętrznego do powinien tam być kondensator 100nF do masy. A jeśli korzystasz z zewnętrznego źródła to podpina się je właśnie tam.

    Jeśli wyrównasz do lewej to powinno działać, po odczytaniu ADCH.
  • #5 7723720
    mateo19851
    Poziom 16  
    Przetwornik ruszył . Jednak pojawiło się jeszcze jedno pytanie:
    ADC obsługuję w przerwaniu . Używam komendy :

    Gdzie zmienna wynik jest typu "volatile uint16_t"(globalna).
    I z tym poleceniem działa prawidłowo. Gdy stworzyłem funkcję :
    
    volatile uint8_t Low,High;
    volatile uint16_t wynik;
    void sprawdz(void){
       Low=ADCL;
       High=ADCH;
       High=wynik&0x03;
       wynik=wynik | High;
       wynik=wynik<<8;
       wynik=wynik | Low
    }
    

    Przetwornik dziwnie sie zachowuje , rozpoznaje tylko dwa poziomy napięcia.
    Czy kod jest napisany prawidłowo ?
  • REKLAMA
  • Pomocny post
    #6 7723826
    morson
    Poziom 14  
    mateo19851 napisał:
    Przetwornik ruszył . Jednak pojawiło się jeszcze jedno
    
    volatile uint8_t Low,High;
    volatile uint16_t wynik;
    void sprawdz(void){
       Low=ADCL;
       High=ADCH;
       High=wynik&0x03; // tu chyba chciałeś High=High&0x03; ?
       wynik=wynik | High; // niepotrzebnie do starego wyniku dodajesz logicznie nowy wynik, powiniwneś dać wynik = High;
       wynik=wynik<<8;
       wynik=wynik | Low
    }
    


    Wartość ADCH nigdy nie będzie większa niż 0x03 jeśli wyrównujesz do prawej, więc niewiem po co to sprawdzasz

    ps.
    Niewiem czemu komplikujesz sobie życie i zwiększasz ilość kodu
  • #7 7723925
    mateo19851
    Poziom 16  
    Faktycznie tam chodziło mi o High=High&0x03.

    Już tłumaczę czemu komplikuje sobie życie - wolę znać różne warianty rozwiązania zadania , jakbym zapomniał jeden zawsze będę znał inny :)

    Z poprawkami już działa .

    Dzięki morson za cierpliwość :)

    Temat można uznać za zamknięty .

    Pozdrawiam
REKLAMA