Atmega8 ADC + timer


Witam.
Zbudowałem układ, który składa się z dwóch części. Pierwsza to generator o częstotliwości 125kHz, druga to przetwornik ADC, który mierzy sygnał i zapala diody w zależności od niego.
Oba podukłady (podprogramy) oddzielnie działają poprawnie. Jednak jak skleiłem dwa kody (jeden od ADC drugi od generatora) to już zaczęły się schody.
Jak dotąd nie używałem dwóch przerwań w jednym programie i może stąd popełniłem błąd.
Problem objawia się tym, że jak w main() mam tak jak w programie poniżej to diody podłączone do portu D cały czas zapalają się i gaszą sekwencyjnie zgodnie z funkcją Test(). Tak jakby była ona wpisana w while(1). No i wtedy nie działa ADC.
Natomiast jak zostawię samo InitADC() to Test() wykona się raz i ADC działa.
Skąd może brać się takie zachowanie?

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
#define led0 (1 << PD0)
#define led1 (1 << PD1)
#define led2 (1 << PD2)
#define led3 (1 << PD3)
#define led4 (1 << PD4)
#define led5 (1 << PD5)
#define led6 (1 << PD6)
#define Out PD7
#define Square PB1
 
volatile int histereza=100;
volatile int x=0,i=0;
volatile int pomiar=0;
#define wart1 530//530
#define wart2 615//615
#define wart3 660
#define wart4 705
#define wart5 750
 
//--------------Przerwanie ADC-------------------
ISR(ADC_vect)
{
	pomiar = ADC;
	if      ((pomiar > wart1-histereza) && (pomiar <= wart1+histereza)) 	PORTD = 0b00000001;
	else if ((pomiar > wart1+histereza) && (pomiar <= wart2+histereza))	PORTD = 0b00000011;
	else if ((pomiar > wart2+histereza) && (pomiar <= wart3+histereza)) 	PORTD = 0b00000111;
	else if ((pomiar > wart3+histereza) && (pomiar <= wart4+histereza)) 	PORTD = 0b00001111;
	else if ((pomiar > wart4+histereza) && (pomiar <= wart5+histereza)) 	PORTD = 0b00011111;
	else PORTD = 0x00;
}
 
//-------------Konfiguracja ADC-----------------
void InitADC(void)
{
	ADMUX = _BV(REFS0) | _BV(REFS1) ;// Napięcie odniesienia wewnętrzne, AREF podłączony z GND przez 100n 
			//| _BV(MUX0); // Kanał ADC1
	ADCSRA = _BV(ADFR) // Free Running
			| _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0)  // preskaler , f = 8MHz/128 = 62,5 kHz (w zakresie 50kHz-200kHz)
			| _BV(ADEN) // Aktywacja przetwornika
			| _BV(ADIE) // Aktywne przerwanie od ADC
			| _BV(ADSC); // Start pierwszej konwersji
}
 
void InitSquare()
{
	//Tryb CTC
	TCCR1A = (1 << COM1A0); 
	TCCR1B = (1 << WGM12) | (1 << CS10); // Preskaler 1
	TIMSK = (1 << OCIE1A) | (1 << TOIE1);
	OCR1A = 31;//31 
}
 
void Test(void)
{
	for (int i=0;i<=5;i++)
	{
		PORTD = 1<<i;
		_delay_ms(100);
	}
	for (int i=5;i>=0;i--)
	{
		PORTD = 1<<i;
		_delay_ms(100);
	}
}
 
int main()
{
	DDRD = 0xff;
	DDRB |= (1 << Square);
 
	Test();
	InitADC();
	InitSquare();
	sei();
		while(1)
		{
		}
}




Portret użytkownika mirley

Re: ADC

Zmień tryb działania ADC z ciągłego na pojedynczy.... i wywołuj go wtedy kiedy chcesz zmierzyć. Poza tym twój program wykona tylko raz procedurę Test bo masz ją poza pętla główną

-

UWAGA! Możliwy jest zakup zaprogramowanych uC i zestawów elementów itp. do niektórych projektów. O dostępność proszę pytać via email. Konkretne oferty pojawiają się w cenniku.

Portret użytkownika gosc

Dodałem do programu funkcję

Dodałem do programu funkcję wywoływaną od przerwania, czyli w moim przypadku:

ISR(TIMER1_COMPA_vect)
{
}
Co ciekawe teraz z tą funkcją program nie wykonuje funkcji Test() cyklicznie. Tzn diody zapalą się raz w odpowiednim kierunku i tyle. Bez powyższego kodu zapalają się i gaszą cały czas. Wiem, że nie są w while(1), ale tak się dzieje.
Dodanie tego kodu nie spowodowało jednak do końca prawidłowego działania. Tzn. idzie funkcja Test() potem inicjalizacje ADC i timera. Działa generator, nie działa ADC.
Quote:
Zmień tryb działania ADC z ciągłego na pojedynczy
- spróbuję tak, chociaż nie wiem czemu w takiej konfiguracji jak mam to nie działa :/

Portret użytkownika gosc

Edit:

No niestety pojedynczy tryb ADC nie pomógł. Robię to tak:

void InitADCSingle(void)
{
	ADMUX = _BV(REFS0) | _BV(REFS1) ;// Napięcie odniesienia wewnętrzne, AREF podłączony z GND przez 100n 
			//| _BV(MUX0); // Kanał ADC1
	ADCSRA = _BV(ADEN) // Aktywacja przetwornika
			| _BV(ADIE) // Aktywne przerwanie od ADC
			| _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);  // preskaler , f = 8MHz/128 = 62,5 kHz (w zakresie 50kHz-200kHz)
} 
...
...
while(1)
	{
		if (!((ADCSRA & (1 << ADSC)) == 1))
		{
			ADCSRA |= (1 << ADSC);
		}
		_delay_ms(100);
	}

Oczywiście w main() wywołuje funkcję InitADCSingle().