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

[atmega8][C][adc]problem z odczytem 5 kanałów autokalibracja

esnow 31 Sty 2009 20:00 2277 4
REKLAMA
  • #1 6083030
    esnow
    Poziom 14  
    witam,
    chce aby mój line follower po postawieniu na powierzchni zapamiętywał stan z czujników, następnie zapamiętywał stan z nad czarnej linii. Miałoby to służyć autokalibracji

    kod jest następujący ale coś nie działa:/

    
    void init_ADC(unsigned int m)
    {
    	
    /*
    ADMUX = 0b01100000
    		  x - REFS1
    		   1 - REFS0
    		    1 - ADLAR
    			 -  - ...
    			  x - mux3
    			   x - mux2
    			    x - mux1
    				 x - mux0 */
    if(m==0) ADMUX = 0b01100000; //adc0   
    if(m==1) ADMUX = 0b01100001; //adc1   
    if(m==2) ADMUX = 0b01100010; //adc2   
    if(m==3) ADMUX = 0b01100011; //adc3   
    if(m==4) ADMUX = 0b01100100; //adc4   
    
    // Zezwolenie na konwersję
    ADCSRA |= _BV(ADEN);
    // Wybranie częstotliwości dla taktowania przetwornika
    ADCSRA |= _BV(ADPS0);
    ADCSRA |= _BV(ADPS1);
    ADCSRA |= _BV(ADPS2);
    }

    teraz odczytywanie stanów z czujników:

    
    if(bit_is_set(PINC, PD5)){
    _delay_ms(100);
    while(bit_is_set(PINC, PD5)){}
    }
    	init_ADC(0);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	a=ADCH;
    	
    	init_ADC(1);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	b=ADCH;
    	
    	init_ADC(2);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	c=ADCH;
    	
    	init_ADC(3);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	d=ADCH;
    	
    	init_ADC(4);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	e=ADCH;
    if(bit_is_set(PINC, PD5)){
    _delay_ms(100);
    while(bit_is_set(PINC, PD5)){}
    }
    	
    	init_ADC(0);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	A=ADCH;
    	
    	init_ADC(1);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	B=ADCH;
    	
    	init_ADC(2);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	C=ADCH;
    	
    	init_ADC(3);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	D=ADCH;
    	
    	init_ADC(4);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	E=ADCH;
    	
    	
    	cn1=(a+A)/2;
    	cn2=(b+B)/2;
    	cn3=(c+C)/2;
    	cn4=(d+D)/2;
    	cn5=(e+E)/2;
    


    i teraz sprawdzanie w pętli while oraz porównanie.
    (dodatkowo zapalanie diód kontrolnych)
    
    while(1)
    	{	
        init_ADC(0);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	p1=ADCH;
    	
    	init_ADC(1);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	p2=ADCH;
    	
    	init_ADC(2);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	p3=ADCH;
    	
    	init_ADC(3);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	p4=ADCH;
    	
    	init_ADC(4);
        ADCSRA |= _BV(ADSC);
        while( ADCSRA & _BV(ADSC)) {};
    	p5=ADCH;
    
    	if(p2<cn2&&p3>cn3&&p4<cn4){   //00100
    	d3_on;
    	prawy_on(255);
    	lewy_on(255);}
    	
    	if(p2>cn2&&p3<cn3&&p4<cn4){   //01000
    	d2_on;
    	prawy_on(255);
    	lewy_on(210);}
    
    	if(p2<cn2&&p3<cn3&&p4>cn4){   //00010
    	d4_on;
    	prawy_on(210);
    	lewy_on(255);}
    	
    	//d1_off;
    	d2_off;
    	d3_off;
    	d4_off;
    	//d5_off;
    }


    problem jest taki, że silniki nie chca krecic diody caly czas mrugaja, tak jakby odczyt z adc zajmowal za duzo czasu.
    sama kalibracja działa, ale nie wiem czy program nie powinienie czekac w petli while(1) ileś ms co zmiana kanału adc.

    jak najlepiej odczytywać wartość z 5 kanałów?
    (próbowałem jeszcze ADCSRA |= _BV(ADFR); z free runing ale to wogole nie chcialo dzialac)
  • REKLAMA
  • #2 6086263
    kasaidolar
    Poziom 19  
    Strasznie bez sensu to robisz. Dlaczego za kazdym razem jak zmieniasz kanał robisz od nowa caly ADC init?? Zmieniaj tylko kanał. Poza tym dalbym te warunki w if kazdy w osobnym nawiasie.

    Dodano po 5 [minuty]:

    ustaw sobie najpierw na poczatku programu to:
    
    	// Wybranie wewnętrznego żródła napięcia odniesienia - Internal 2.56V Voltage Reference with external capacitor at AREF pin
    	ADMUX |= _BV(REFS0);		
    	ADMUX |= _BV(REFS1);
    	// Zezwolenie na konwersję	
    	ADCSRA |= _BV(ADEN);		
    	// Wybranie częstotliwości dla taktowania przetwornika  (1/8 częstotliwosci zegara kontrolera) 
    	ADCSRA |= _BV(ADPS0); 	 
    	ADCSRA |= _BV(ADPS1);
    	set_sleep_mode(SLEEP_MODE_ADC);
    
    jak tam chcesz

    a pozniej odpalaj:
    
    			ADCSRA|= _BV(ADSC); 				//Start pojedynczej konwersji
       			while(bit_is_set(ADCSRA,ADSC)){};   
       			a = ADCH;                               //itd
    
    


    A zmiany wejsc wykonuj przez:
    
    ADMUX |= _BV(MUX0); // wylaczenie bitu to ADMUX &= ~_BV(MUX0);
    
  • REKLAMA
  • REKLAMA
  • #4 6092106
    kasaidolar
    Poziom 19  
    No to ADLAR musi byc. Chodzilo mi tylko zebys zrobil jeden init na poczatku programu a bity ustaw sobie jak chcesz. A co do sleep mode adc poczytaj strone chyba 201 dokumentacji
  • #5 6106084
    esnow
    Poziom 14  
    wsztstko miałem ok z adc, przepisalem kod.

    problem jest nastepujacy, PWM nie chce działać w parze z ADC.

    albo jedno działa albo drugie,
REKLAMA