Ja generalnie korzystam z funkcji opóźniających z <util/delay.h> (_delay_ms(x), _delay_us(x)). W jednym projekcie mam zaprojektowany osobny moduł z funkcjami opóźniającymi, oparty o timer (moduł robi też inne rzeczy, więc w momencie oczekiwania robi zadania w tle). Najlepszym rozwiązaniem wydaje mi się przeniesienie funkcji do osobnego pliku .c kompilowanego z innym poziomem optymalizacji lub ręczne napisanie kodu w asemblerze i dołączenie go do linkowania (sam tak robię z większością kodu, kiedy nie chcę dać żadnych szans kompilatorowi na (de)optymalizację kodu).