[Atmega32][C]Zmiany kanałów ADC i zapis do tablicy

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
grandcapucin
-
Posty: 3
Rejestracja: 13 sty 2011, 10:39
Lokalizacja: PL

[Atmega32][C]Zmiany kanałów ADC i zapis do tablicy

Post autor: grandcapucin » 13 sty 2011, 11:47

Cześć,

używam AVRStudio + WinAVR i wszystko kompiluje się poprawnie. Niestety nie mogę rozgryźć swojego błędu przy przełączaniu kanału ADMUX. Próbowałem już na wiele sposobów dodając różne opóźnienia, żeby wyzerować rejestr ADCH z którego odczytuję zmienne.

Program pobiera pomiary z 4 kanałów ADMUX[0:4] i zapisuje je do tablicy:

Kod: Zaznacz cały

volatile unsigned int dalmierz[4] = {0,0,0,0};
w zależności od wlk. pomiaru, zostają podjęte inne akcje w tym uruchomienie PWM itd. Kiedy jednak zacząłem przeprowadzać próby, okazało się, że bez względu którego kanału użyję(podam stan wysoki, ale mniejszy niż REF(przez diodę)), zawsze dochodzi do wykonania instrukcji nawet jeżeli zastrzegę, że ma się wykonać po dokonaniu z konkretnego kanału instrukcją:

Kod: Zaznacz cały

if (dalmierz[3]>=126){..}
wygląda to tak jakby dowolna wartość odczytana z dowolnego weścia ADMUX zapisywała nią całą tablicę dalmierz[4]

poniżej kod:

Kod: Zaznacz cały

void inicjalizacja (void)
{
/*******WEJŚCIA*****/
/*******WYJŚCIA*****/
				// 7654 3210
DDRA = 0x00;		// 0000 0000	wejścia ADC z dalmierzy

/********ADC********/					// 7654 3210
ADMUX = 0x60;		// 0110 0000 odniesienie=AVCC, pomiar wyrównaj do lewej żeby czytać 8 bitów
ADCSRA = 0xC6;		// 1100 0110 konfiguracja ADC, opis w dokumentacji projektu
SFIOR=0x00;					

}


int main (void)
{
sei();			//globalne włączenie przerwań
for(;;)
	{
	unsigned int m=0;
	unsigned int i=0;		//pomocnicza zmienna do iteracji "i"	
			sei();
			inicjalizacja();

			for(m=0;m<4;m++){ dalmierz[m]=0;}//przypisanie wartości początkowych w tabeli
			
			for(i=0;i<4;i++)
				{
					
				if(i==0){
					ADCSRA |= (1<<ADSC);	//odczytanie wartości do tabeli dalmierz z ADC
					_delay_ms(15);			//opóźnienie w celu wykonania funkcji przerwania
					dalmierz[0]=ADCH;		//odczytanie cyfrowej wartosci sygnalu
					ADMUX =	0x61;
					}
				else if(i==1){
					ADCSRA |= (1<<ADSC);	//odczytanie wartości do tabeli dalmierz z ADC
					_delay_ms(15);			//opóźnienie w celu wykonania funkcji przerwania
					dalmierz[1]=ADCH;		//odczytanie cyfrowej wartosci sygnalu
					ADMUX =	0x62;
					}
				else if(i==2){				
					ADCSRA |= (1<<ADSC);	//odczytanie wartości do tabeli dalmierz z ADC
					_delay_ms(15);			//opóźnienie w celu wykonania funkcji przerwania
					dalmierz[2]=ADCH;		//odczytanie cyfrowej wartosci sygnalu
					ADMUX =	0x63;
					}
				else{
					ADCSRA |= (1<<ADSC);	//odczytanie wartości do tabeli dalmierz z ADC
					_delay_ms(15);			//opóźnienie w celu wykonania funkcji przerwania
					dalmierz[3]=ADCH;		//odczytanie cyfrowej wartosci sygnalu
					ADMUX =	0x60;
					}
				_delay_ms(15);
				}
if (dalmierz[3]>=126){ //podaję wartość około ~200
       ...//instrukcje
       cli();
       for(m=0;m<4;m++) dalmierz[m]=0;//wyzerowanie odczytu
}
chyba tyle, dziękuję za pomoc, wiadomo, że czasem jak się nad czymś ślęczy to się zupełnie zatraca perspektywę :roll:

keruseykaryu

Post autor: keruseykaryu » 13 sty 2011, 18:57

Czemu nie czekasz na ADIF tylko walisz sztywne delaye? No i czemu odczytujesz tylko ADCH a nie cały ADCW?
No i może jednak cały kod byś pokazał, bo to nieskładne nieco jest co widzę.

grandcapucin
-
Posty: 3
Rejestracja: 13 sty 2011, 10:39
Lokalizacja: PL

Post autor: grandcapucin » 13 sty 2011, 19:41

Wyrównuję do lewej ADLAR-em więc chyba mogę wykorzystać tylko ADCH. W miedzyczasie zamieniałem delay-e na :

Kod: Zaznacz cały

while(bit_is_set(ADCSRA,ADSC)){};
ale nie przynosi to żadnego efektu. Mogło się coś skopać z tym ADC?
Wysyłam całość w załączniku, bo kod jest raczej za długi >30 żeby go tu umieszczać.

Jeszcze gdzieś znalazłem informację, że potrzeba 50 pustych przerwań ADC, żeby zmienić kanał, więc nic mi nie szkodziło tego też dodać. Ale efekt jest taki, że jeden, dokładnie ADMUX=2, nie działa.
Załączniki
nowawersja.rar
częściowo zakomentowany program i plik nagłówkowy
(19.39 KiB) Pobrany 423 razy

Awatar użytkownika
edwacc
Użytkownik
Posty: 163
Rejestracja: 14 paź 2008, 10:19
Lokalizacja: świętokrzyskie knieje

Post autor: edwacc » 13 sty 2011, 19:52

Wlasnie pracuje nad projektem, w ktorym wykorzystuje ADC w Atmega32 i robie to tak:

Kod: Zaznacz cały

void adc_start(unsigned char channel)
{
	ADMUX &= 0b11111000;
	ADMUX |= channel;
	ADCSRA |= (1 << ADSC);
	while(ADCSRA & (1 << ADSC)){};
}

void adc_init(void)
{
DDRA &= ~((1 << PA5) | (1 << PA7) | (1 << PA4));
	PORTA &= ~((1 << PA5) | (1 << PA7) | (1 << PA4));
	ADMUX |= (1 << REFS1) | (1 << REFS0); //| 1 << MUX0 | 1 << MUX2;
	ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
	ADCSRA |= (1 << ADSC);
} 
Korzystam z trzech kanalow ustawianych w czesci inicjalizacyjnej i ich numer podaje w argumencie funkcji.

keruseykaryu

Post autor: keruseykaryu » 13 sty 2011, 19:55

Wyrównuję do lewej ADLAR-em więc chyba mogę wykorzystać tylko ADCH.
Nie. I tak musisz odczytać ADCL (albo cały ADCW i potem małe dzielonko) bo inaczej nici z tego.
Wszyćko wyjaśni nota katalogowa. Nie chce mi się pisać tego.
grandcapucin pisze:W miedzyczasie zamieniałem delay-e na : Kod:
while(bit_is_set(ADCSRA,ADSC)){};


ale nie przynosi to żadnego efektu. Mogło się coś skopać z tym ADC?
Pisałem o ADIF a nie o ADSC.
grandcapucin pisze:Jeszcze gdzieś znalazłem informację, że potrzeba 50 pustych przerwań ADC, żeby zmienić kanał, więc nic mi nie szkodziło tego też dodać. Ale efekt jest taki, że jeden, dokładnie ADMUX=2, nie działa.
Pomysłowość ludzka nie zna granic. Szkoda, że nie umią czytać not katalogowych. Tam wszyćko opisane jest. Fajne wykresy są co i jak.

grandcapucin
-
Posty: 3
Rejestracja: 13 sty 2011, 10:39
Lokalizacja: PL

Post autor: grandcapucin » 13 sty 2011, 20:18

Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH.
Może jestem cienki jęz., ale to chyba popiera to co wcześniej powiedziałem.

Próbuję z ADIF-em, ale rezultat jest podobny, albo jeszcze gorszy, bo już kompletnie od czapy się włącza.

Czytałem notę katalogową, ale skoro nie miałem innego pomysłu to uznałem, że warto spróbować.

ODPOWIEDZ