Делается программный таймер, аппаратный таймер и аппаратные внешние прерывания только под кнопку отдавать это мягко говоря нерационально.
В одном аппаратном таймере обновляются все программные таймеры, которые могут быть использованы для чего угодно.
Значит заводим программный таймер для опроса кнопки, например с тиком каждые 100мс и переменную-счетчик. Далее проверяем в нем если кнопка нажата и если счетчик меньше 30 то инкрементируем его, иначе ставим флаг об удержании и выполняем функцию которая должна выполнятся при удержании ее. Если кнопка не нажата - сбрасываем счетчик и флаг удержания.
Псевдокод:
u08 buttonCounter=0;
u08 buttonHold=0;
u16 Timers[1]={0};//массив счетчиков программных таймеров
interupt HardwareTimer1(){//прерывание аппаратного таймера каждые 25мс
if(Timers[0]++==4){// 100мс/25мс=4 раза
Timers[0]=0;
onProgTimer1();
}
}
void onProgTimer1(){//этот программный таймер тикает каждые 100ms
if(button1==PRESSED){
onButton1Press();//функционал когда кнопку нажали
if(buttonCounter<30){//ждем пока счетчик досчитает до 30 - 100мс*30 раз=3000мс=3 сек
buttonCounter++;
}else{
if(buttonHold==0){
buttonHold=1;//Ставим флаг удержания кнопки
onButton1Hold();//выполняем функционал при удержании
}
}
}else{
buttonCounter=0;//сбрасываем таймер-счетчик
onButton1Release(buttonHold);//функционал когда кнопку отпустили
buttonHold=0;//сбрасываем флаг удержания кнопки
}
}