Таймер нужно использовать - SysTick, пусть отсчитывает системное время (я обычно в миллисекундах условных считаю). А конечные автоматы запоминают условное время нажатия или отпускания кнопки, а состояние меняют лишь спустя определенное количество единиц этого времени. Использовать всякие delay'и в коде можно разве что на стадии инициализации (когда требуется подождать некоторое время, скажем, для инициализации дисплея), да и то, если ждать нужно много, лучше это обернуть в конечный автомат. Тогда человек не будет офигевать от тормозов железки, да и значительно снизится вероятность просрать какое-нибудь событие.
У меня на этом таймере есть функции задержек.