Skocz do zawartości

Obsługa timera / licznika - Atmega8


Frackowiak

Pomocna odpowiedź

Zaczynam zabawę w programowanie uC pod C. Swą przygodę zacząłem od tego kursu. Jako, ze C znam w miarę dobrze to nie miałem problemów ze zrozumieniem struktury aplikacji, i w miarę rozumiałem zadania. Teraz postanowiłem zrealizować swój pomysł na wykorzystanie uC, ale do tego potrzebuje wiedzy na temat licznika i timer. Wiele naczytałem się na elektrodzie i tutaj też, ale wielu rzeczy nie rozumiem. Nie wiem o co chodzi z preskalerem, nie rozumiem kiedy timer startuje i gdzie są przechowywane info na temat tego ile czasu zliczył (generalnie jestem zagubiony w temacie bardziej niż jak zacząłem szukać). Ja chciałbym użyć timera do zliczania czasu trwania sygnału wysokiego/niskiego na wejściu uC (będą to raczej krótkie czasy rzędu ms) oraz licznika do zliczania ile razy na wejściu uC pojawił się stan wysoki/niski. Generalnie wydaje mi się, ze na początek wystarczyłby mi jakiś przykład z dobrymi komentarzami żeby temat rozjaśnić, a w miarę potrzeb w przypadku braku zrozumienia jakiś kwestii dopytywałbym się szanownych kolegów o szczegóły.

Z góry dzięki za pomoc!

Pozdrawiam!

Link do komentarza
Share on other sites

W zasadzie wielu rzeczy dowiedziałem z tego Tutoriala na temat timerów. Teraz Chciałem się dowiedzieć jak by ta wiedzę dostosować do moich potrzeb. Chodzi o to by rozpocząć zliczanie timera w momencie pojawienia się sygnału na jakimś wejściu i wyłączeniu timera i przepisanie jego wart. do jakiejś zmiennej gdy sygnał na wejściu zniknie. Myślałem o przerwaniu zewnętrznym na wejście INT0 i gdy ono wystąpi uruchomienie timera, ale nie do końca wiem czy dobrze kombinuje. Proszę o pomoc jeśli można!

Link do komentarza
Share on other sites

No to zacznij pisać, i wtedy pytaj, co nie działa, a nie boisz się, że nie zadziała, zanim napisałeś 😋 Weź może właśnie przerwanie zewnętrzne, reakcję na odpowiednie zbocze sygnału powodującą przerwanie, albo reakcja na jakiekolwiek zbocze, albo zmiana zbocza, na które reaguje po każdym przerwaniu, zależnie od potrzeb, w obsłudze przerwania odczytujesz wartość timera, zapisujesz, zerujesz i liczysz ponownie. I dajesz największy preskaler z takich, które udają satysfakcjonującą Cię dokładność, żeby nie było problemów, że nie nadążasz z odczytem timera.

Link do komentarza
Share on other sites

No więc idąc za radą Chechli zacząłem pisać (dużo się nie napisałe 😋 ) i powstało coś takiego:

volatile int licznik = 0;

void main()
{
DDRB |= _BV(0);	// wyjście
DDRB |= _BV(1);	// wyjście

PORTB &= ~_BV(0);	
PORTB &= ~_BV(1);	

DDRD &= ~_BV(PD2);	// wejście przerwania INT0
PORTD |= _BV(PD2);	// podciągnięcie do jedynki

GICR |= _BV(INT0);	// włączenie przerwania INT0
MCUCR |= _BV(ISC00);	// ustawienie wyzwolenia przerwania na zbocze opadające

sei();	// zezwolenie na obsługę przerwań

while(1)
{
	for ( int i = 0 ; i < licznik ; i++ )
	{
		PORTB |= _BV(0);
		_delay_ms(100);
		PORTB &= ~_BV(0);
		licznik--;
	}
}
}

ISR(INT0_vect)
{
TCCR1B |= _BV(CS10) | _BV(CS11);	// preskaler 64
if ( TCNT1 >= 15625 )
{
	licznik++;
}
PORTB |= _BV(1);
}

W zamyśle program miał po naciśnięciu guzika zacząć zliczać czas z dokładnością do sekundy i co sekundę zwiększać licznik, by po skończeniu obsługi przerwania w pętli for mrugnąć diodą tyle razy ile sekund trzymany był guzik.

Niestety nie do końca tak się dzieje. Po wciśnięciu guzika na około 2-3 sek dioda mająca mrugać zapala się i gaśnie tylko raz.

Będę wdzięczny za wytknięcie mi błędów w rozumowaniu.

Pozdrawiam!

[ Dodano: 03 Wrz 10 03:49 ]

OK Panowie i Panie ten problem został rozwiązany 🙂

Pozdrawiam!!!

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

Cześć,

w jaki sposób zapisać przerwanie które z założenia miałoby uruchomić się tylko raz, po czym zatrzymać timer i nie uruchamiać się ponownie ?

Mój kod wygląda następująco, ale przerwanie wykonuje się cyklicznie, mimo "cli()" zamieszczonego w jego treści.

int main (void)
{
TCCR1B |= (1 << WGM12);	
TIMSK |= (1 << OCIE1A);						
sei();													
OCR1A   = 11718;											
}

ISR(TIMER1_COMPA_vect)
{
PORTD ^= (1<<PD0)
       KRYTERIUM_CZAS = 1;
cli();
}
Link do komentarza
Share on other sites

mogę się mylić, ale nie masz w funkcji main pętli głównej, na której mógłby "zawiesić się" program

prawdopodobnie efekt cyklicznego załączania był taki, że po dojściu do końca funkcji main przez pewien czas szukał w pamięci programu kolejnych instrukcji (a napotykał tylko puste wiersze), po czym po dojściu do końca pamięci wracał na początek i wykonywał na nowo funkcję main.

int main (void)
{
   TCCR1B |= (1 << WGM12);   
   TIMSK |= (1 << OCIE1A);                       
   sei();                                                   
   OCR1A   = 11718;
   while(1);    //teraz tutaj nastąpi zawieszenie w wykonywaniu - program na mikrokontrolerze nie powinien występować bez pętli głównej
}

ISR(TIMER1_COMPA_vect)
{
   PORTD ^= (1<<PD0)
       KRYTERIUM_CZAS = 1;
   cli();
} 
Link do komentarza
Share on other sites

niechcący wprowadziłem Cię w błąd 🙂

to tylko fragment programu odpowiedzialny za działanie timera, dalej znajduję się nieskończona pętla która realizuje odczyt z przetwornika A/C.

Nie zamieszczałem całości z uwagi na przejrzystość.

Oto pozostała część programu w funkcji main:

while(1)
{
	if(PIND & (1<<PD4))
	{
		TCCR1B |= ((1 << CS10) | (1 << CS12)); 	

		while (1)
		{
			for (i=0;i<16;i++)
			{
				ADCSRA |= (1<<ADSC);			
				while (ADCSRA & (1<<ADSC));
				wartosc2 += ADCW;		
			}
			wartosc2 >>= 4;

			if (wartosc2 > wartosc1)
			{
				MAX_AMPL = wartosc2;
			}

			if (MAX_AMPL >= 600 && KRYTERIUM_CZAS && wartosc2 <= 512)
			{
				PORTB |= ((1<<PB0) | (1<<PB1));		
			}
			wartosc1 = wartosc2;
			wartosc2 = 0;
		}
	}
}

}
Link do komentarza
Share on other sites

Więc problem tkwi w samym przerwaniu. Według pierwszej lepszej instrukcji od Atmegi88 na stronach dotyczących obsługi przerwań można wyczytać:

When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are dis-

abled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled

interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a

Return from Interrupt instruction – RETI – is executed.

Co oznacza, że flaga zezwolenia globalnego na przerwanie zostanie ustawiona automatycznie po wyjściu z jego obsługi. Bez względu co byśmy z nią robili (w momencie włączenia przerwania flaga I jest zerowana, ręczne ustawienie pozwala podobno na zagnieżdżone przerwania.)

Ja na Twoim miejscu wyczyściłbym po prostu w ten sposób, powinno pomóc:

int main (void)
{
   TCCR1B |= (1 << WGM12);   
   TIMSK |= (1 << OCIE1A);                       
   sei();                                                   
   OCR1A   = 11718;
   [...] 
}

ISR(TIMER1_COMPA_vect)
{
   PORTD ^= (1<<PD0)
       KRYTERIUM_CZAS = 1;
   TIMSK &= ~(1 << OCIE1A);  //wyłączenie obsługi przerwania od trybu porównywania timera
} 
  • Lubię! 1
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!

Anonim
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.