Skocz do zawartości

[C] ADC, pomiar z kolejnych kanałów


filipson

Pomocna odpowiedź

witam.

mam problem z moim algorytmem. mam 5 czujników CNY70(1 chwilowo zepsuty).

Pomiary wykonuję poprzez przerwanie adc_vect.

Mam napisana funkcje diagnostyczna void run_diagnostic(void) która zapala diody odpowiadające poszczególnym czujnikom w przypadku wykrycia koloru czarnego. Jednak ta sygnalizacja nijak ma się do rzeczywistości.

Próg dobierałem kilka razy, ale nie ma to zbyt dużego wpływu.

Starałem się zrobić to wg zasady wart_adc=Uzm/Uref*1024.

U mnie Uzm dla czarnego to od 2,6 do 2,8V.

/*
* filbat.c
*
* Created: 2011-12-05 19:52:45
*  Author: filip grzeszczak, aleksy kabat
*/ 

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

#include "inc/porty.h"
#include "inc/pid.h"
#include "inc/silniki.h"

/* F_CPU 16 000 000 */


#define ADC_P 600   //próg ADC

uint8_t alg_flag;	//flaga dla algorytmu
uint8_t diag_flag; 	//flaga dla przelaczenia w trym serwisowy
volatile uint8_t adc_flag; 	// flaga ADC	  

volatile int sensors[5];  	//tablica przechowujaca wartosci napiecia na czujnikach zwracane przez ADC
volatile uint8_t channel=0;   	//indeks tablicy sensors[]


/****************************run_lf********************************
funkcja odczytuje stan senow na pinach PA0..PA4 i zapisuje
go w tablicy sen_status[]. 
Stan senow jest przemnazany zgodnie z przyjeta waga. 
Na podstawie koncowych wartosci skladowych sen_status[] obliczany
jest blad diff.
zmienna diff jest dalej przekazywana do funkcji pid.		    
******************************************************************/

void run_lf(void) {
short int sen2L,sen1L,sen0,sen1R,sen2R;
short int diff=0;	//blad obliczany z wag czujnikow
short int turn=0;	//skret wyliczony przez PID na podstwie diff
short int PowerL=0;	
short int PowerR=0;

while(alg_flag){
//ADMUX |= (0x0F & channel); 
   ADMUX &= 0xf0;
ADCSRA |= (1<<ADSC);
if(adc_flag)
       { 
           if(sensors[0] > ADC_P) { 
               sen2L = -4; 
               //sen_channel++; 
           } 
           else    sen2L = 0; 

           if(sensors[1] > ADC_P) { 
               sen1L = -2; 
               //sen_channel++; 
           } 
           else    sen1L = 0; 

           if(sensors[2] > ADC_P) { 
               sen0 = 0; 
               //sen_channel++; 
           } 
           else    sen0 = 0; 

           if(sensors[3] > ADC_P) { 
               sen1R = 2; 
               //sen_channel++; 
           } 
           else    sen1R = 0; 

           if(sensors[4] > ADC_P) { 
               sen2R = 4; 
               //sen_channel++; 
           } 
           else    sen2R = 0; 

diff=sen1L+sen2L+sen0+sen1R+sen2R;   //sumowanie wag czujnikow   
	} //endif

turn=PIDcall(diff);	

if(turn==0) {
PowerL=MAX_DUTY;
PowerR=MAX_DUTY;

}//endif
else{

PowerR = MAX_DUTY - turn;	
PowerL = MAX_DUTY + turn;

}//endelse	
GoAhead(PowerL,PowerR);
adc_flag=0; //zerowanie flagi dla pomiaru
if((PIND & (1<<PIND3))==0) {
_delay_ms(100);
alg_flag=0;
}
} //endwhile 
LED0_ON;
}//end run_lf()

void run_diagnostic(void) {
ADMUX |= (0x0F & channel); 
   ADCSRA |= (1<<ADSC);
while(diag_flag) {

if(adc_flag)
       { 
           if(sensors[0] > ADC_P) { 
               LED2L_ON; 
           } 
           else    LED2L_OFF; 

           if(sensors[1] > ADC_P) { 
               LED1L_ON; 

           } 
           else    LED1L_OFF; 


           if(sensors[2] > ADC_P) { 
               LED0_ON;
           } 
           else    LED0_OFF; 

           if(sensors[3] > ADC_P) { 
               LED1R_ON;
           } 
           else    LED1R_OFF; 
		_delay_ms(100);
	ADMUX |= (0x0F & channel); 
	ADCSRA |= (1<<ADSC);
	}//endif
	if((PIND & (1<<PIND2))==0) {
	diag_flag=0;
	}

}
LED0_ON;//endwhile	
}//end run_diagnostic()

/*#######################################################*/
/*------------------------MAIN---------------------------*/

int main(void)
{
ports_init();
LED0_ON;
ADMUX |= (1 << REFS0);                            	// Włączenie ADC + napięcie odniesienia 
ADCSRA |= (1<<ADEN) | (1<<ADIE);                  	// Interrupt Enable 
   ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); 	// Częstotliwość pracy (preskaler = 128, fp=125kHz) 
sei(); 		//wlaczenie globalnych przerwan
   while(1)
   {

	if((PIND & (1<<PIND3))==0) {		//wlacznik algorytmu
	_delay_ms(100);
	LED0_OFF;
	alg_flag=1;
	run_lf();

	}//endif  
	if((PIND & (1<<PIND2))==0) { 	//wlacznik trybu serwisowego, mozliwy tylko przy wylaczonym algorytmie
	_delay_ms(100);
	LED0_OFF;
	diag_flag=1;
	run_diagnostic();			
    }
}//endwhile
}//end main()


// ***** OBSŁUGA PRZERWANIA ADC ***** //
ISR(ADC_vect)    {                                    
   sensors[channel] = ADCW;                              
   channel++;                                    
//ADMUX |= (0x0F & channel);  [b] //TEGO NIE ROZUMIEM DO KOŃCA![/b]
ADMUX &= 0xf0; //zerowanie 4 młodszych bitów 
   ADMUX |= channel; //ustawianie numeru kanału 

if(channel<5) {
       ADCSRA |= (1<<ADSC);  //zainicjowanie kolejnego pomiaru              
   }
else {
channel=0; //wyzerowanie licznika
adc_flag=1; //ustawienie flagi sygnalizujacej zakonczenie pomiaru
}	
}

Część funkcji, min. PID i ustawianie portów są w innych plikach. Narazie nie mają znaczenia, chodzi o funkcję run_diagnostic i pomiar ADC.

Myślę, żę błędnie przełączam kanały do kolejnych pomiarów. Prawde mówiąc nie do końca rozumiem ten zapis, skopiowałem go z innego algorytmu.

Mam nadzieję, że ktoś pomoże mi to zrozumieć 🙂

EDIT dodaje schemat :

Link do komentarza
Share on other sites

Polecam użyć tej funkcji, którą kiedyś gdzieś znalazłem

/*
 ADMUX |= (1<<REFS0)|(0<<REFS1); //porównuje z AVCC,  AREF--||--GND
       //0 tylko dla zasyganlizowania ze jest tam zero bo to nic nie zmienia
       ADCSRA |= (1<<ADEN);

int getADC(char number)
   //number należy do <0, 7>, kod nie sprawdza szkoda pamięci FLASH
   {
           ADMUX &= 0xf0; //zerowanie 4 młodszych bitów
           ADMUX |= number; //ustawianie numeru kanału

           ADCSRA |= 1<<ADSC; //zaczyna konwersję
           while(ADCSRA & (1 << ADIF));    //dopoki bit ADIF nie jest ustawiony nie jest gotowa kowersja
           ADCSRA &= ~((1 << ADSC) | (1 << ADIF)); //zeruj flage konwersji i rozkaz rozpoczecia
           return ADCW;
   }

przykładowo:

zamienna = getADC(1);

wykona konwersje na kanale 1 a wynik zapisze do zmiennej.

Taki mały zakres zmian może być spowodowany za małym prądem diody led, albo źle dobranym opornikiem przy kolektorze fototranzystora.

Link do komentarza
Share on other sites

Taki mały zakres zmian może być spowodowany za małym prądem diody led, albo źle dobranym opornikiem przy kolektorze fototranzystora.

Nie wiem czy mnie dobrze zrozumiales 🙂 przy czarnym mam ok 2,6V, a przy bialmy ok 0,1V\

to chyba odpowiedni zakres zmian? mam oporniki 200Ohm(inaczej niz w schemacie, robione na szybko a akurat nie mialem 330 w smd 0805) przy diodach i 47k przy kolektorze.

Link do komentarza
Share on other sites

Próg masz ustawiony jako 600 co przy zasilaniu 5V (?) daje ok. 2,9V - których wg. swoich słów nie uzyskujesz.

Próg powinieneś ustawić na 300 co da 1,5V...

PS. Najlepiej na diody wyprowadź górne 4 bity wyniku z jednego kanału ADC to będziesz w przybliżeniu widział jaki jest wynik i czy napięcie czujnika jest poprawnie odczytywane przez ADC...

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

@Robodude

OK, sprawdzilem, zmienilem prog bo faktycznie cos pomieszalem. Jednak najwazniejsze okazalo sie byc numerowanie zmiennej channel. Robilem to od 0 do 4 co nie mialo zbytniego sensu poniewaz czujniki sa na pinach PA3-PA7 🙂

wszystko dziala. musze wymienic jeden czujnik bo jest zepsuty(sprawdzalem aparatem, dioda IR nie swieci)

@Harnas

dzieki za funckje, jednak zalezalo mi na wykorzystaniu przerwan 🙂

Pozdrawiam

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.