Maker Pro
Maker Pro

help in programming long press button

hello, i'm a fresh graduate and got my first job.as a part of my task i need a program on how to make my button to be long pressed before lighting a LED. i am using AT90USB647. thanks in advance...
 
I have to asked... Did you sell yourself on being able to perform this task to your employer and now find yourself in a pickle? The reason I ask is because this is elementary level programming and if you sold yourself as having that experience/education this task would be easy...

Do you have any programming knowledge, tools, or experience?
 
no sir.my boss just gave me this task as an example to of learning and of reviewing my programming knowledge. I told him that I have only a little knowledge now because i did programming 4 years ago.
 
Start with writing a program to turn the led on and off.

Have you got a development board?
Are you able to write a simple program where the led turns and and turns off every second or so? Its always a good start, the hello world of embedded
 
yes ma'am/ sir. i already did that using i/o ports and by using push buttons. only now, i am confused how to program a long pressed pushbuttons.
 
use the on board timer as described in the chapter of the datasheet -> 14. 16-bit Timer/Counter (Timer/Counter1 and Timer/Counter3)

These things will be important.
a. how long can the button be pressed?
b. how much accuracy you need?

so it depends on the clockspeed, say 8MHz will use all 2^16 bits fairly fast and roll over once every 8 miliseconds which is not helpful . I've worked with the HCS12 and that will have a divider effectively slowing down the ticks so it won't roll over so fast.
 
There are even easier ways then dealing with timers if accuracy of say 1ms is enough... Just implement an x=x+1 counter loop with a 1ms delay (between polling button state) when the button is pressed, in that loop if x overflows your long press duration kick out of the loop flagged as a long press...
 
You stated you had programming experience several years back, how much? Was it anything practical?

IMO the 'logic' used in programming is like riding a bicycle you might get rusty but you don't totally forget it, so if you have the experience you should be able to wrap your head around this task if you try...
 
yeah, im trying. But the programming I had years back was so basic, that programming with microcontrollers make me feel like i did not learn anything.... That is why I have to go over it again, and it makes me nervous coz I run out of time.
 
Here is the quick and dirty of it in BASIC, not optimized or a complete program by any means, just a proof of concept of the logic... Don't yell at me if it has flaw, it's 2AM and I'm tired and it is only intended to be a proof of concept :)

Code:
'PortA.1 is the button input, pull low
'When button pressed PortA.1 will be pulled high by the button
'
'Define variables
x=0 'start value for duration loop counter
flag=0  'long press flag, clear to start

'Main program

main:

IF PortA.1 = 1 THEN 'if button pressed
    GOSUB Duration_check  'check to see how long it's pressed
ENDIF

IF flag = 1 THEN  'long press was detected
    flag=0    'reset flag for next time
    'You have a long press detected!  Now do something!
ENDIF

GOTO main  'loop back to start to wait for button press

Duration Check:

WHILE PortA.1 = 1 'aka button is pressed
    x=x+1    'increase duration timer
    PAUSE 1  'pause for 1ms

    IF x > 2000 Then 'long press duration check time, 2000 = 2 seconds
        x=0  'reset duration timer for next time
        flag=1  'long duration detected flag
        RETURN 'a long press detected jump back to main loop with flag =1
    ENDIF

WEND 'if button still pressed loop back to increase x again, if not kick out

x=0 'reset duration timer for next time
RETURN 'just a short press return to main loop
 
are you working with c or assembly?

If you know how to configure the GPIO (push button inputs and leds outputs) you should try cocacolas suggestion.

make a loop that you know takes 1 ms to to complete. and keep checking the input if its pressed keep counting.

this won't compile, though should give you some ideas.

bool pressed = false;
while(!pressed)
{
delay(); // subroutine that takes close to a ms. note all other statements if, while etc will take a small time to execute.
// check status of the button. this assumes all other pins are not used.
// you may yneed to mask the other ones out if they are.
if (PORTA ==0x01)
{
count++;
}
else
{
pressed = true.
}

}

print ("time is %d ms", count);
 
Last edited:
I found this in the google. Can i ask what is missing/wrong with isr?


#define F_CPU (_MCU_CLOCK_FREQUENCY_)
#define T0_PRESCALER 1024
#define TIMER0_RELOAD 0x9f // 10ms overflow at 1024 prescaler at 10MHz

#define BUTTON PINC.2 // port pin to use as button
#define LONG_PUSH 2 // # seconds for a long button push
#define LONG_PUSH_CTR (F_CPU / T0_PRESCALER / (0xff - TIMER0_RELOAD + 1) * LONG_PUSH)
#define DEBOUNCE 25 // # ms for a valid button push
#define DEBOUNCE_CTR (F_CPU / T0_PRESCALER / (0xff - TIMER0_RELOAD + 1) * DEBOUNCE / 1000)

// Button status ===================================
#define NOPUSH 0
#define PUSHED 1
#define SHORT 2
#define LONG 3
#define HANDLED 4
//#define CHECK_LONG // whether we check for long pushes or not

unsigned char button_flag = NOPUSH; // current button status
unsigned int button_timer; // for debouncing button

// Timer 0 overflow interrupt service routine
// 10ms overflow
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0 += TIMER0_RELOAD; // reset for 10ms overflow
if (!BUTTON) { // button is down ...
if (button_flag == NOPUSH) { // is this a new push ?
button_timer = 0; // yup - start the debounce timer
button_flag = PUSHED; // note that it's down
}
#ifdef CHECK_LONG
if (button_flag == PUSHED) { // button is down - have we already noted that ?
button_timer++; // yup - inc the debounce timer
if (button_timer == LONG_PUSH_CTR) { // long enough for a LONG push ?
button_flag = LONG; // yup - note a LONG push
}
}
#endif
} else {
if (button_flag == PUSHED) { // button is up, was it pushed before ?
if (button_timer > DEBOUNCE_CTR) { // yup, was it long enough for a short push ?
button_flag = SHORT; // past bounce timeout, was a short push
} else button_flag = NOPUSH; // nope, too short - was a bounce
}
if (button_flag == HANDLED) { // button is up, did we handle it ?
button_flag = NOPUSH; // yup - reset back to waiting for push
} // otherwise, wait till we handle it
}
}
 
time dependent pushbutton

I modified a program and made a time dependent pushbutton program. The problem is it keeps lighting all through out the time. Can someone please help me correct it. Thank you so much in advance.


#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#define SECONDS .1
#define F_CPU 8000000UL
#define PRESCALER 256
#define LONG_PUSH 2 // # seconds for a long button push
#define DEBOUNCE 25 // # ms for a valid button push


// Button status ===================================
#define NOPRESS 0
#define PRESSED 1
#define SHORT 2
#define LONG 3
#define HANDLED 4
#define CHECK_LONG // whether we check for long pushes or not

unsigned char button_flag = NOPRESS; // current button status
unsigned int button_timer; // for debouncing button


//Main Method
int main(void)

{

DDRB &= ~(1 << PINB3); //Data Direction Register input PINB3
PORTB |= 1 << PINB3; //Set PINB1 to a high reading

DDRB |= (1 << PINB0); //Set Direction for output on PINB0
PORTB ^= 1 << PINB0; //Toggling only Pin 0 on port b


TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

sei(); // Enable global interrupts
OCR1A = (((F_CPU/PRESCALER)*SECONDS)-1); // Set CTC compare value to 100ms at 8MHz AVR clock, with a prescaler of 256
TCCR1B |= (1 << CS12); // Start timer at Fcpu/256

for (;;)
{

}
}

ISR(TIMER1_COMPA_vect)
{
if (!PINB3)
{

if (button_flag == NOPRESS)
{
button_timer = 0; // start the debounce timer
button_flag = NOPRESS; // note that it's down

}
#ifdef CHECK_LONG
if (button_flag == PRESSED) { // button is down - have we already noted that ?
button_timer = button_timer++; // yup - inc the debounce timer
if (button_timer == LONG_PUSH) { // long enough for a LONG push ?
button_flag = LONG; // yup - note a LONG push
}
}
#endif
} else {
if (button_flag == PRESSED) { // button is up, was it pushed before ?
if (button_timer = DEBOUNCE) { // yup, was it long enough for a short push ?
button_flag = SHORT; // past bounce timeout, was a short push
} else button_flag = NOPRESS; // nope, too short - was a bounce
}
if (button_flag == HANDLED) { // button is up
button_flag = NOPRESS; // reset back to waiting for push
}
else
{button_flag = NOPRESS;} // otherwise, wait till we handle it
}
}
 
I won't comment any further. It's just a matter of familiarising yourself with the equipment and micro by reading the data sheet. Don't get overwhelmed with code you don't understand from google. Coca cola gave you sound logic in basic, as I have with c for a simpler solution not using interrupts.

If you already have code that registers the button being pressed its not hard to keep it in the loop and count a variable in software, exit the loop when No longer pressed. It's just a matter of knowing in time how long a loop takes. Hint Toggling a pin and watching the output on a scope is useful for this.
 
i modified the program.instead of overflow mode i made it ctc mode. but it just light all trough out the time.


#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#define SECONDS .1
#define F_CPU 8000000UL
#define PRESCALER 256
#define LONG_PUSH 3 // # seconds for a long button push
#define DEBOUNCE 0.25 // # ms for a valid button push


// Button status ===================================
#define NOPRESS 0
#define PRESSED 1
#define SHORT 2
#define LONG 3
#define HANDLED 4
#define CHECK_LONG // whether we check for long pushes or not

unsigned int button_flag = NOPRESS; // current button status
unsigned int button_timer; // for debouncing button


//Main Method
int main(void)

{

DDRB &= ~(1 << PINB3); //Data Direction Register input PINB3
PORTB |= 1 << PINB3; //Set PINB1 to a high reading

DDRB |= (1 << PINB0); //Set Direction for output on PINB0
PORTB ^= 1 << PINB0; //Toggling only Pin 0 on port b


TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

sei(); // Enable global interrupts
OCR1A = (((F_CPU/PRESCALER)*SECONDS)-1); // Set CTC compare value to 100ms at 8MHz AVR clock, with a prescaler of 256
TCCR1B |= (1 << CS12); // Start timer at Fcpu/256

for (;;)
{

}
}

ISR(TIMER1_COMPA_vect)
{
if (!(PINB & (1<<PINB3)))
{

if (button_flag == NOPRESS)
{
button_timer = 0; // start the debounce timer
button_flag = NOPRESS; // it is not down

}
#ifdef CHECK_LONG
if (button_flag = PRESSED)

if (button_flag == PRESSED) { // button is down - have we already noted that ?
button_timer++; // inc the debounce timer
if (button_timer == LONG_PUSH) { // long enough for a LONG push ?
button_flag = LONG; // yup - note a LONG push

}
}
#endif
} else {
if (button_flag == PRESSED) { // button is up, was it pushed before ?
if (button_timer == DEBOUNCE) { // was it long enough for a short push ?
button_flag = SHORT; // past bounce timeout, was a short push
} else button_flag = NOPRESS; // nope, too short - was a bounce

}
if (button_flag == HANDLED) { // button is up
button_flag = NOPRESS; // reset back to waiting for push

}
else
{button_flag = NOPRESS;} // otherwise, wait till we handle it
}
}
 
a. an int button_timer will never be = 0.25 (DEBOUNCE).

b. I don't see any place in the interrupt sub routine where you toggle the pin. I guess you want to toggle it once you have done a long press.
 
Top