Wystarczy Ci jeden timer
![Szczęśliwy :)](https://forum.atnel.pl/images/smilies/icon_e_smile.gif)
Zresztą 16 bitowy Timer1 marnotrawiony do takich rzeczy to grzech
![Pokazuje język :P](https://forum.atnel.pl/images/smilies/icon_razz.gif)
Twój problem wynika z tzw. liniowego podejścia do programowania. Najpierw zadaj sobie pytanie co robi kluczowa dla Twojego projektu funkcja _delay_ms(). Ano nie robi ona NIC. To jest jej istotą. Robienie niczego. Zatrzymuje pracę procesora na określony czas. I tyle. Oczywiście wejście w przerwanie spowoduje wyskoczenie z tej funkcji i obsługę przerwania, ale po zakończeniu obsługi przerwania procesor wróci do wykonywania _delay_ms() czyli do nierobienia nic.
Nie da się w ten sposób zakończyć pracy tej funkcji. Procesor po obsłużeniu przerwania wraca w to miejsce na którym przerwał i nic na to nie można poradzić.
Trzeba podejść inaczej. Zerwać z liniowym pisaniem programu. Mechanizm wygląda tak:
1. Uruchamiamy sobie Timer sprzętowy w trybie CTC ( w AT8 najlepiej chyba będzie Timer2)
2. Włączamy przerwanie typu Compare dla tego timera. Tak by wykonywało się np. co 1 ms. (bit OCIE2x w rejetrze TIMSK)
3. Włączamy przerwania globalne - sei()
4. Deklarujemy sobie globalną zmienną typu uint16_t np. Timer_programowy i zaopatrujemy ją w specyfikator volatile
5. W procedurze obsługi przerwania zwiększamy te zmienną o jeden za każdym razem - Timer_programowy++;
6. W pętli głównej programu kontrolujemy "wątki" przez użycie warunku IF np.
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Czy widzisz co się teraz będzie działo?
Program startuje. Przelatuje przez pętlę główną while(1). I widzi warunek. Czy Timer_programowy jest równy 5000? Nie, oczywiście, że nie jest bo jest równy zero (zmienna globalna jest inicjalizowana zerem). Nie zapala więc diody.
Ale nagle nadchodzi przerwanie od Timera2 (sprzętowego). Co się dzieje w jego procedurze? Zwiększa się wartość zmiennej Timer_programowy. Teraz wynosi ona już 1. Ale warunek w pętli głównej dalej jest niespełniony.
Po wystąpieniu 5000 przerwań zmienna uzyska wartość 5000 i warunek się spełni. Dioda się zaświeci. A skoro przerwania występują co 1 ms to stanie się to dokładnie 5 sekund po uruchomieniu programu.
Może wydaje Ci się to dziwne, i pokręcone. Ale to bardzo uproszczony przykład, zobacz:
1. W żadnym miejscu program nie czeka.
2. W pętli głównej możesz w ten sposób sprawdzać dziesiątki najróżniejszych warunków.
3. Możesz powołać sobie dowolną ilość zmiennych podobnych do timer_programowy i każda będzie sterowała innym procesem.
4. To samo przerwanie możesz użyć do multipleksowania wyświetlaczy.
Najpierw oswój się z tym mechanizmem. Obsługa klawiszy to następny krok.
Przyciski można obsłużyć też timerem. Po prostu rośnięcie zmiennej odmierza czas. I służy do niwelacji drgań styków i nie tylko.
Dlatego przeczytaj poradnik Mirka o drganiach styków. OK ?