Efekt 888 pojawia się dlatego, że używasz operatora OR w funkcji setNum() oraz dlatego, że źle korzystasz z operatorów logicznych (AND i OR). Zamiast wpisać nową wartość do rejestru PORTD, sumujesz ją z poprzednią wartością. Sama funkcja jeszcze mogłaby wyglądać inaczej, ponieważ nadal niepotrzebnie w procedurze obsługi przerwania jest ona wywoływana - niech wszystko dzieje się w programie głównym, a w przerwaniu tylko wpisanie odpowiedniej wartości do PORTD. Czyli najlepiej byłoby stworzyć tablicę znaków do wyświetlacza. Takie coś jak masz w funkcji setNum, tylko bez wpisywania do rejestru, same bajty. Np.
Zaloguj się, aby zobaczyć kod
Aktualnie w twoim kodzie tablica cyfry[] przechowuje setki, dziesiątki i jedności zmiennej
speed. Musisz zrobić tak, żeby przechowywała już prawidłowe wartości z tablicy znaki[]. Bo po co tracić czas w przerwaniu na przepisywanie tych rzeczy? Możesz to zrobić mniej więcej w ten sposób:
Zaloguj się, aby zobaczyć kod
Wtedy w nieskończonej pętli while w programie głównym wystarczy wywołać tę funkcję tylko w momencie zmiany prędkości:
Zaloguj się, aby zobaczyć kod
Dzięki temu w przerwaniu wystarczy jedna linijka (zamiast wywołania funkcji setNum() ):
Zaloguj się, aby zobaczyć kod
Możesz tak zrobić, bo tablica ta przechowuje wartości, które trzeba wpisać do PORTD, żeby wyświetlić pożądaną wartość. Pomyśl jeszcze jak zrobić, żeby za pomocą jednej linijki i zmiennej "
i" włączać odpowiedni wyświetlacz
Dodatkowo taka operacja:
Zaloguj się, aby zobaczyć kod
Nie robi tego co byś chciał zrobić. Jeśli nie pamiętasz działań logicznych, to przeanalizuj jaki będzie jej efekt przy pomocy tablic prawdy.
Zmieniłbym także nazwę funkcji clearDigit(); bo ona nie ma za zadanie skasować cyfrę z wyświetlacza, tylko ten wyświetlacz wyłączyć

Założenie jest takie, że przed zmianą wartości na wyświetlaczu, wyłącza się go, żeby nie pojawiły się "duszki". A wyłączenie jednego wyświetlacza jest równoważne wyłączeniu wszystkich, więc wystarczy jedna linijka. Zresztą niepotrzebnie jest to w ogóle funkcja. Tę linijkę równie dobrze można przepisać do procedury obsługi przerwania. Nie tracimy wtedy kilku taktów zegara na niepotrzebny skok.
Cytat: w przyszłości od zmiennej speed wyświetlanej na ekranie zależeć będzie szybkość 'pikania' buzzera i nie jestem pewien czy wtedy to będzie działać.
Też nie wiem, czy to będzie działać, bo nie napisałeś nic na temat obmyślonej przez ciebie zasady działania

Pamiętaj, że atmega8 ma więcej niż jeden sprzętowy timer. Mogą one działać niezależnie.