Maker Pro
Maker Pro

help in programming long press button

I changed my debounce to 1. And I toggled the pin. The problem is still the LED turns on already without pushbutton and it can not be off.
 
your state machine is confusing and there is probably a bug

a. your interrupt may not be firing. if you got these values off Google every chip may be different and you need to check the configuration values. try to toggle (every time, ignoring the long press logic) a pin and look at it through a scope (a led isn't good enough as it may be too fast for you to notice the led turning on and off again.

b.else, your state machine is confusing and there is probably a bug. Try to understand it. Draw a state diagram. test it. if using jtag or your debugger allows you to, step through it slowly and work it out.
 
Finally, I ended making this code. It executes long press to a button for on and off. The problem is it is not exactly 3 seconds but it is 2.6 seconds. How can I make it turn on and off nearly to 3 seconds?

Code:
#include <avr/io.h> 
#include <avr/interrupt.h> 

#define F_CPU 8000000 
#define SECONDS .5 

#define NOPRESS 0 
#define PRESSED 1 
#define LONG_PUSH 6 // 3 seconds for a long button push 

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

ISR(TIMER1_COMPA_vect) 
{ 
button_timer ++; 
} 
int main(void) 
{ 

DDRB |= (1 << PINB0); //Set Direction for output on PINB0 
PORTB ^= (1 << PINB0); //Toggling only Pin 0 on port b 
DDRB &= ~(1 << PINB3); //Data Direction Register input PINB1 
PORTB |= (1 << PINB3); //Set PINB1 to a high reading 

TCNT1 = 0; 
OCR1A = (((F_CPU/256)*SECONDS)-1); // Set CTC compare value to 500ms at 8MHz AVR clock, with a prescaler of 256 
TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode 
TCCR1B |= (1 << CS12); // Start timer at Fcpu/256 
TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt 
sei(); // Enable global interrupts 


while (1) 
{ 
if ((PINB & (1<<PINB3))) { 
// button is not pushed 
button_timer = 0; 
button_flag = NOPRESS; 


} else { 
// button is pushed 
if (button_flag == NOPRESS) { 
button_timer = 0; 
button_flag = PRESSED; 
} else if (button_flag == PRESSED) { 
//button_timer++; 
if (button_timer >= LONG_PUSH) { 
//PORTB ^= 1 << PINB0; 
button_timer = 0; 
//PORTB ^= (1<<PINB0); // toggles LED 
PORTB ^= (1<<PINB0); 
button_flag = PRESSED; 
} 

} 
} 
} 

return (0); 
}
 
Great progress, I can't account for anything in particular except that:
OCR1A = (((F_CPU/256)*SECONDS)-1)

if my calculations are correct
8000000/256*0.5-1 = 15624

is OCR1A 8 bit or 16 bit? If its 16 bit it will be a overflow and likely only the bottom 8 bits of 15624 is fitting into the OCR1A
 
Yes it is 16 bits. But what would be the reason that it will overflow? I believe I made it as CTC mode and also I believe that my 0.5 value is ok because the timer count is not more than 65535.
 
opps. 16bit is fine, only if it was 8 bits it would overflow

my second idea with the timing issue is the while(1). you have code that is looping at a millions times a second just to do things you need to care about in .5 second intervals

is it worth changing the code so that you effectively use your timer as a signal.

Then in your timer ISR you can.

a. check that the button is pressed. if not 0 and possibly reset the led, else increment a count

b. check that the button has been pressed at more then 6 times. (3 sec long press) . make the led on.

c. warning there will be a bug here where if the user holds the button for a long time if the count overflows and is less then 6 it will turn the led off

you will now just have an empty while loop or for loop, and the program is totally within the ISR.

for(;;)
{
}
 
My boss told me to try to put an external xtal, because I use an internal 8MHz. I got 8.3886MHz. The error in interrupt latency became 0.004, something like that.
 
Just a couple of comments on this, based on what is discussed.

Generally it's a bad idea to do large globs of code inside an ISR. If you want a timer, just increment a tick counter inside the ISR, and do the processing outside.
If the timer interrupt is very fast, you could make a precounter inside the ISR, to divide down the interrupt interval to a more convenient rate. It's of little use to read a button input every 100us when debouncing an input is in the range of 10-30ms, depending on the quality of the pushbutton. A normal glitch period is around 10-15ms.
Personally I use 10ms as an interval and read 3 times the same state to validate the change. Then the button input is validated to be changed. If you have more than one input, you only need to AND, OR and XOR a little bit to keep the states correct all the time.

If you need a delay to execute a change or toggle a LED, use the timer ticks and count them to get your time. You can expand the timer system to any interval you need.
If this is the only application running in your program you don't need to make the it transparent, but doing that from the beginning is wise.
That way you can put in more applications with no change in the existing ones, as long as they don't interact and use the same resources.

Rule number one here is: Never use delay loops in your programs, that is a waste of processing power.

TOK ;)
 
c. warning there will be a bug here where if the user holds the button for a long time if the count overflows and is less then 6 it will turn the led off


could you get rid of this by maybe comparing the timer ticks to a value right before the timer roll over then just force a new value into the timer (assuming the new value is larger that the requirment to turn on the led)
 
No need to wait that long, at any value over the trigger just hold the timer...

IF count >6 then count = 7
ELSE count = count + 1
 
Top