ISR Button Press Code... A better way must exist - help rqst

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, searched the forum, read the datasheets... they've gotten me this far but now I need help as usual =(

I have an Mega88P with a NO button connected to PB0. I have PB0 pulled down to ground with a 1.5k R normally, when the button is pushed, the circuit closes and PB0 is powered up to 3.3V. I want to use on pin change interrupt (PCINT0_vect).

The button should do 3 things, I don't care about actual values yet but everything is around seconds, nothing super duper long.

1 Too short a press then release, return to wherever it was in main.

2 Medium length press then release, dump bytes 0 through 511 in the EEPROM out of my USART, go into infinite loop of flashing green LED.

3 Long length press with or without release, fill 512 bytes of EEPROM with 0 values, go into infinite loop flashing green LED.

My approach: I user TIMER2 to interrupt the main every millisecond and increment a global volatile variable called TimeNow. I always have a clock with this. I store the time the button is pushed, then i do subtraction when the button is released. This gives me the time length of button presses.

My problem: It don't work and I know there must be a better way. The button push does interrupt my code but after that, I can't get it to lock up in any infinite loops nor dump data. It acts like a P.O.S.

What do professionals do when they want to have a button do what I want mine to do? How do they know the lengths of presses? Any help appreciated as always, please help me save my company time and money!

ISR(PCINT0_vect)
{		
	PCICR = 0b00000000;
	PCMSK0 = 0b00000000;
	Green_Switch(0);
	if(bit_is_clear(PINB, PB0))	 /*for when button releases goes high to low*/
	{
		PCICR = 0b00000001;
		PCMSK0 = 0b00000001;
		return;
	}
	long tempbstart, tempbuttontime;
	tempbstart = TimeNow;
	while(bit_is_clear(PINB,PB0) != 1) /*wait until button is released*/
	{
		Green_Switch(1);
		_delay_ms(100);
		Green_Switch(0);
		_delay_ms(100);
	}
	
	tempbuttontime = TimeNow - tempbstart;
	
	if (tempbuttontime <= 100)
	{	
		PCICR = 0b00000001;
		PCMSK0 = 0b00000001;
		return; /*super short press*/
	} 
	if (tempbuttontime <= 3000)
	{
		USART_Init();
		for (int h = 0 ; h<512 ; h++)
		{
			USART_Transmit_i(Get_EEPROM(h));		
		} 
		while(1)		/*die in fast blinking pattern*/
		{
			Green_Switch(1);
			_delay_ms(250);
			Green_Switch(0);
			_delay_ms(250);
		}
		
	}
	else
	{
		for (int h = 0 ; h<512 ; h++)
		{
			EEPROM_write(h,0);		
		} 
	}
	while(1)		/*die in slow blinking pattern*/
	{
		Green_Switch(1);
		_delay_ms(1000);
		Green_Switch(0);
		_delay_ms(1000);
	}
	return;/*never gets here*/
}



void Button_Init(void)
{
	PCICR = 0b00000001;
	PCMSK0 = 0b00000001;
	DDRB = 0x00;	/*all port b to input*/
	return;
}

random functions like Green_Switch do stuff that works, just ignore that, i used it to indicate to myself where my code was while being executed. My method is wrong so code probably is useless.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Without actually studying your code in detail, I suspect that you (at least) suffer from switch bounce. Using external interrupts for detecting switches is usually a bad idea due to switch bounce.

Somewhere here at AVRfreaks Peter Danegger (user 'danni') has posted his switch debouncer including a possibility to handle "autorepeat" after a certain time. This means that he detects a short and a long press.

If you start with that it might be possible to expand it to detect a third, even longer, keypress.

Sorry for not supplying details on dannis autorepeat or where this can be found, but I need to rush off to other things soon. A few search sessions should turn it up. It just might be a uploaded to the Project area here.

In any case it makes sense to start with detecting just two different lengths of keypresses, and then expand that.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Using external interrupts for detecting switches is usually a bad idea due to switch bounce.

What is the right/professional way to do it? My devices can't be garbage or I'll get fired =(

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Like Johan stated, there's debounce code here and Danni's is very good, but you'll have to find it . Others code will work too . OR you could put a debounce circuit on the pin, if the uC can't spare the time to do it in s.ware . I wonder if the ICP, after debouncing, would be the best/simplest for this app...

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is no single "right/professional way to do it". One often described approach to switch debouncing is to sample the pin in question based on a timer (typically with a period of a few milliseconds, e.g. 5 ms) and only deem the switch pressed when you've seen a certain number of identical states (e.g. 4 identical states).

Quote:
My devices can't be garbage or I'll get fired

If this is professional work then how can you not be aware of switch bounce?!

Anyway, just search out e.g. 'danni's debouncer. When doing that you will find that the subject is up here just about every other week or so. You will eventually find a few threads where this is discussed extensively, so it makes little sense to do a re-write here. Make a good cup or can of coffee, snug up and start reading those threads.

Good search terms are "switch bounce", "debounce" (and "de-bounce") and similar. Also search for authors like 'danni', 'theusch' (spelling?). To locate dannis code you might get lucky searching for "ct0", "ct1", "key_state" and "key_press" in combination (those are rather unique variable names in his code - hopefully spelled correctly, taken out of my carbon-based memory).

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

OR you could put a debounce circuit on the pin, if the uC can't spare the time to do it in s.ware

He will still need to do the short/medium/long detection in software. One of my points was that it is likely that this can be solved by tweaking dannis code so that it both handled debouncing and does this detection.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've heard carbon based memory is the greatest way to store information in the known universe being that the human brain is the most intricate/complicated thing to ever exist in nature (known universe). I'll do what I can to kill the switch bounce problems, I didn't recon that was my biggest problem but it just may be. I guess I was hoping for someone to just say "the right way to design a button is to do X Y and Z".

Someone needs to just write a book on how to do everything =)

Thanks for the responses, I'll tackle this pig yet!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan wrote:
One of my points was that it is likely that this can be solved by tweaking dannis code so that it both handled debouncing and does this detection.
By just counting how many times it's in debounced state... YEP !

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Found danni's code in this thread

https://www.avrfreaks.net/index.p...

I'll just leave this here for future AVR Freak Newbs

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In this post, the man himself (danni) points to a page with code that also does auto repeat: https://www.avrfreaks.net/index.p...

Note that he has an initial delay before repetition starts (use this for your medium long key press?) and then another delay between the repeats (use this for your long long key press?).

And again, just to push through, if you use AVRfreaks own search function looking for "ct0 ct1 key_press key_state" and tick Search for all words, then almost all the top 20 hits or so are good reads. During the last year we've been involved in several very good and revealing discussions on debouncing algorithms.

HTH! Now I'm really off to other things!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smkipus wrote:
What do professionals do when they want to have a button do what I want mine to do? How do they know the lengths of presses? Any help appreciated as always, please help me save my company time and money!

I think talk about debouncing may be throwing you off (though you certainly should understand how to do it, and the algorithm below does debounce as part of its operation).

Simply, you count how many consecutive time intervals ("ticks") the button is in the down state. In the same timer tick ISR is where you look at the button input pin(s).

You will have a small routine in the timer ISR, or triggered by it, that does this.

-if button not pushed, set counter to 0
(if counter was in #2 duration range, do #2 action)
-if button pushed, increment counter
(if count >= #3 duration, do #3 action)

Your #1 action happens automatically if neither #2 nor #3 happens.
Your #2 happens when the button push ends, if the duration of the push is within #2 bounds.
Your #3 happens as soon as the duration of the push crosses into the #3 bounds.

If you wanted to do #3 multiple times (which you say you don't), then you'd have to set a flag to avoid repeats, and only clear the flag when the button push ended.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Check out my project/library here:

https://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Someone needs to just write a book on how to do everything =)

That has all been done may times over, including documentation in the Tutorials in this Forum. It is just a matter of taking the time to read it.

I would implement your task with a finite state machine. The statemachine can be executed every 1ms. from a Timer compare interrupt( CTC mode)
STATES
KEY_NORMAL
KEY_PRESSED increment counter

When the key is released you set a flag dependent on how long it was down for. In main you check for which flag is set and execute that task.
Debouncing problems go away!

Quote:
My devices can't be garbage or I'll get fired =(

You must have a tough boss, who gives you a job that you are not experienced in and threatens you if you are fail. Seems you have been set of for failure. FSM will save you!

Edit.
I have just answered another question, where I think an FSM could be used to good advantage and is not much different to your project. This will point you in the right direction.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?