Nie analizowałem dokładnie kodu, jednak na początek miałbym taką uwagę.
Zauważyłem, że wyłączasz przerwania, po czym ponownie je włączasz.
Po pierwsze we funkcji
przerwania_wylacz() robisz to niepoprawnie (powinno być & zamiast |). Poza tym dla uzyskania większej czytelności lepiej zrobić to tak:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Wtedy nie ma wątpliwości jaki bit ustawiasz czy też zerujesz.
Po drugie, wyłączenie przerwań jest często błędnie interpretowane. Ustawienie czy też zerowanie (akurat w tym przypadku) bitu OCIE0B w rejestrze TIMSK0 oznacza tylko wyłączenie zezwolenia na przerwanie. Timer cały czas zlicza impulsy (TCNT0) i kiedy jego wartość zrówna się z wartością rejestru OCR0B zostanie ustawiona flaga OCF0B w rejestrze TIFR0. W tej sytuacji procedura obsługi przerwania nie zostanie uruchomiona, ponieważ zezwolenie jest wyłączone, jednak flaga jest ustawiona i zostaje zapamiętana. Kiedy ponownie włączysz zezwolenie na to przerwanie (OCIE0B w TIMSK0), procedura jego obsługi zostaje natychmiast uruchomiona niezależnie od aktualnego stanu licznika TCNT0, bo przecież flaga została już ustawiona wcześniej.
Flaga zostaje wyzerowana dopiero wtedy, gdy przerwanie zostanie obsłużone (przez procedurę obsługi) lub gdy wyzerujemy ją programowo. Ewentualnym rozwiązaniem wydawałoby się może wyłączenie zliczania przez licznik (by uniknąć ustawienia flagi), ale to i tak nie zawsze zagwarantuje, że flaga nie zostanie ustawiona. Dlatego moim zdaniem lepszym rozwiązaniem (przynajmniej w tym przypadku) jest programowe zerowanie flagi tuż przed zezwoleniem na przerwanie:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.