Funktioniert es denn, wenn du normale digitale I/O-Ports nimmst anstatt ADC-Inputs?

Was mir auffllt ist daß du in der Tioer0-ISR ne Warteschleife auf den ADC hast (in read_adc), und zwar sogar 3 mal. Das ist nicht so toll. Wenn das dauert bekommst du die nächste Timer0-IRQ schon, wenn du noch in der Timer0-ISR bist. Dann geht kaum mehr was.

Besser wäre den ADC im free runnong mode zu betreiben und in einer ADC-ISR die Werte zu merken und den Port ein weiter zu schalten.

Nochwas zu Code: Lass die magischen Zahlen wie 0x40 weg, es ist klarer, wenn du sie Bit-Namen verwendes -- nicht nur für andere, auch für dich.