Witam forumowiczów,
Natknąłem się na pewien problem, z którym nie wiem jak sobie poradzić. Sprawa dotyczy nieprawidłowej obsługi przerwania INT0 podczas wykonywania komend sterujących wyświetlaczem LCD.
Do Atmega32 podłączone są:
- standardowy wyświetlacz LCD,
- źródło impulsów (dokładniej jest to liniał cyfrowy),
- przyciski.
Impulsy wprowadzone na pin INT0 mają wywoływać procedurę odczytu stanu z dwóch innych wejść, wykonywana jest prosta operacja (zliczanie kroków w przód lub w tył) a wynik wyświetlany na LCD.
Jest to programowo zrealizowane w oparciu o dwa osobne przerwania i pętlę:
1. przerwanie INT0, wywoływana jest procedura odczytu stanu na wejściach i odpowiednio zwiększany lub zmniejszany jest wynik. Impulsy pojawiają się dosyć gęsto, nawet co około 20 us (mikrosekund), ale przeważnie odstępy są większe. Czas wykonywania podprogramu obsługi tego przerwania zajmuje 250 cykli zegara, co daje jakieś 15us przy zegarze 16MHz.
2. przerwanie TIMER0, użyte jest do odświeżania wyświetlacza. Przerwanie wyskakuje co 16ms, ale tylko co 12-te wywołanie jest odświeżany LCD, czyli mniej wiecej 5x na sekundę. Zawartość wyświetlacza jest konstruowana "na żywo" na podstawie aktualnej wartości zmiennych.
3. Pętla główna, gdzie obsługiwane są tylko przyciski.
PROBLEM polega na tym, że część impulsów które trzeba zliczać jest gubiona. Przy odświeżaniu wyświetlacza 5x na sekundę gubi się około 20% impulsów, bez względu na częstotliwość impulsów wyzwalających INT0 (przy założeniu, że nie są krótsze od pewnej granicznej wartości).
Nie jest to na pewno spowodowane zbyt małymi odstępami pomiędzy wywołaniami INT0. Można to łatwo sprawdzić, co też zrobiłem na dwa sposoby:
- wyłączam przerwanie TIMER0, natomiast wyświetlacz odświeżam przyciskiem, otrzymuję wynik dokładny, czyli wszystkie impulsy są zliczane
- spowalniam odświeżanie na przykład do 1x na sekundę albo jeszcze wolniej, w efekcie gubionych jest odpowiednio mniej impulsów.
Wydaje mi się, że podczas wykonywania komend obsługujących LCD (Locate, Lcd) dzieje się jedna z dwóch rzeczy:
a) przerwania zewnętrzne są wyłączane (nie są obsługiwane przerwania, które są zagnieżdżone jedne w drugich),
b) brakuje miejsca na zapisanie stanu programu, zapełnia się jakiś stos albo coś takiego (?)
Tak ma być czy robię coś źle? Jakieś pomysły o co może chodzić i jak podejść do problemu?
Natknąłem się na pewien problem, z którym nie wiem jak sobie poradzić. Sprawa dotyczy nieprawidłowej obsługi przerwania INT0 podczas wykonywania komend sterujących wyświetlaczem LCD.
Do Atmega32 podłączone są:
- standardowy wyświetlacz LCD,
- źródło impulsów (dokładniej jest to liniał cyfrowy),
- przyciski.
Impulsy wprowadzone na pin INT0 mają wywoływać procedurę odczytu stanu z dwóch innych wejść, wykonywana jest prosta operacja (zliczanie kroków w przód lub w tył) a wynik wyświetlany na LCD.
Jest to programowo zrealizowane w oparciu o dwa osobne przerwania i pętlę:
1. przerwanie INT0, wywoływana jest procedura odczytu stanu na wejściach i odpowiednio zwiększany lub zmniejszany jest wynik. Impulsy pojawiają się dosyć gęsto, nawet co około 20 us (mikrosekund), ale przeważnie odstępy są większe. Czas wykonywania podprogramu obsługi tego przerwania zajmuje 250 cykli zegara, co daje jakieś 15us przy zegarze 16MHz.
2. przerwanie TIMER0, użyte jest do odświeżania wyświetlacza. Przerwanie wyskakuje co 16ms, ale tylko co 12-te wywołanie jest odświeżany LCD, czyli mniej wiecej 5x na sekundę. Zawartość wyświetlacza jest konstruowana "na żywo" na podstawie aktualnej wartości zmiennych.
3. Pętla główna, gdzie obsługiwane są tylko przyciski.
PROBLEM polega na tym, że część impulsów które trzeba zliczać jest gubiona. Przy odświeżaniu wyświetlacza 5x na sekundę gubi się około 20% impulsów, bez względu na częstotliwość impulsów wyzwalających INT0 (przy założeniu, że nie są krótsze od pewnej granicznej wartości).
Nie jest to na pewno spowodowane zbyt małymi odstępami pomiędzy wywołaniami INT0. Można to łatwo sprawdzić, co też zrobiłem na dwa sposoby:
- wyłączam przerwanie TIMER0, natomiast wyświetlacz odświeżam przyciskiem, otrzymuję wynik dokładny, czyli wszystkie impulsy są zliczane
- spowalniam odświeżanie na przykład do 1x na sekundę albo jeszcze wolniej, w efekcie gubionych jest odpowiednio mniej impulsów.
Wydaje mi się, że podczas wykonywania komend obsługujących LCD (Locate, Lcd) dzieje się jedna z dwóch rzeczy:
a) przerwania zewnętrzne są wyłączane (nie są obsługiwane przerwania, które są zagnieżdżone jedne w drugich),
b) brakuje miejsca na zapisanie stanu programu, zapełnia się jakiś stos albo coś takiego (?)
Tak ma być czy robię coś źle? Jakieś pomysły o co może chodzić i jak podejść do problemu?