|
|
View previous topic :: View next topic |
Author |
Message |
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
Auto-Increment Switch When Held Down |
Posted: Mon Mar 27, 2017 10:33 pm |
|
|
Hello Colleagues,
I am about to start writing a routine to handle a button that will auto-increment when it is held down, and will increment faster as it is held down longer. This is a really common thing to do, found everywhere, yet I can't find a post addressing this requirement. Maybe I am missing it, so please forward me the link, but it would be good to open this topic up for discussion.
I have written this same thing a half dozen times, and every time it is different. I have used interrupts to log how long the button has been held down, and I have taken the delay in between each increment as being the inverse of the time that the button has been held down. The longer the hold, the shorter the delay. I have written this routine with a few levels of increment speed called out by Flags. I have liked eliminating the interrupts, but then you end up with a couple of accumulators that keep track of the timing, and this can be different depending on the complexity of your code as you go into that routine.
What I am wondering is if any of you have a cool little piece of code that you re-use for this scenario, or if anyone has a rule of thumb that they use to get this done. I imagine that there is a logical perspective to this problem that I may not be seeing, so again, I would like to see what my fellow experts have to say about this subject.
Thanks so much for your input! _________________ Life is too short to only write code in assembly... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Tue Mar 28, 2017 9:49 pm |
|
|
Thank you for your reply, PCM programmer!
My apologies for not mentioning that post. I really like the versatility of that routine and I will probably use it with a few additions around it if I don't get a head-slapper from someone on meeting my ideal requirements.
The system that I am designing is industrial, so I am reluctant to use the delay_ms function for fear of my system possibly hanging as a result. I know that I can use an interrupt and a timer instead...so I may if I don't get a head-slapper.
Additionally, I have a lot of increments to get through on this project, so I would like to have something that would increment faster as it is held down longer. I see from your routine that I can just have a register to decrement the "Rate" variable the longer it is held down and I can use the aforementioned interrupt routine to accomplish this (if necessary).
As I mentioned initially, I would prefer to stay away from the interrupts for this, so I will probably do as I have a register that just keeps track of how many times the routine has been polled to keep the timing, but again, this has the drawback of being dependent on how often you actually poll. If you have a bunch of delay_ms statements in there, that gets hard to predict.
This is something that I have to do all the time, and unless I get a head-slapper, this is probably something that I will just develop with the input of this thread so that we can come up with something that is useful to all of us. Hopefully we can develop something that can go into the Code Library as an augmentation to what you have already done, PCM. Thoughts? _________________ Life is too short to only write code in assembly... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19543
|
|
Posted: Wed Mar 29, 2017 12:40 am |
|
|
Though you want to avoid a timer. I'd say 'do it'.
Spend some time(!), getting into using a timer. Then use a system 'tick' for everything.
I scan a keyboard with a 'tick'. The key has to be present for two successive ticks to be seen (so debounce). If it is present for a number of ticks (held), the key repeats. Initially needs ten ticks (my tick is every hundredth of a second), so 10 repeats/second. However the number of ticks needed for the repeat, is decremented after five ticks, and counts down every five ticks to 4. So the repeat starts at 10/second, but after half a second goes to 11/sec, then 12.5, then 14.2 then 16.6 then 20, then 25/second. When the key is released, the counter goes back to 10.
You need to ramp smoothly or the behaviour will be unuseable.
Honestly the delays are fine for simple 'one code path' code, but for anything else a core timer is needed.
The timer is a powerful tool, and really needs to be part of your 'armoury', to make code. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Mar 29, 2017 6:36 am |
|
|
I totally endorse Ttelmah's comments.
I use a similar scheme to achieve auto-repeat.
I usually use a 1ms tick, but that's my quirk.
I also use the same 'tick' to control all my other timing functions.
Each function has its own timer counter.
All the timers increment/decrement on every tick.
Once you've got your head round it, it's easy to do and keep track of.
This method only ties up one timer and leaves all the others free.
Mike |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19543
|
|
Posted: Wed Mar 29, 2017 10:23 am |
|
|
I must admit I use faster ticks on most modern processors, but when that particular code was written, they were flat out at only a few MHz. 1/100th second worked really well as a software debounce, and unless a faster tick is needed for something, slower uses less of the processor's time... |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Wed Mar 29, 2017 10:32 am |
|
|
Thank you all for your input! This is exactly what I was hoping for.
I agree, I think that I will have to embrace my available timers more. I've grown up from the low-end range of devices, so I am used to only having a couple timers. Another thing that has kept me from using an interrupt based timer system is it is objected to when you are writing code for safety critical applications. I don't know if it was in IEC-61131 or some other safety standard that I have poured over, over the years, but I remember that interrupts were a no-no. That said, I have never had my code reviewed to such a standard and I have been writing code for 20 years. I would be REALLY interested in hearing from anyone with experience in developing in accordance to these standards...and how they tackle the button interface challenge. I've been doing something similar to get ticks instead of using interrupts. Here is basically how it goes (without pre-loading it):
Code: |
int16 TickCounter; // Declare counter
if (TickCounter == 0)
{
TickCounter = TickCounterPreLoad; // Load the counter with a value that sets the pace of the tick
ActuallyCheckButtons(); // Go and check the buttons
}
else
{
--TickCounter; // Decrement the tick counter
}
|
Now you have to have the button checking routine keep track of how many ticks each button gets, so you end up burning up some Global variables. As I mentioned earlier, the other drawback of this scheme is that it is dependant on the code around it. That said, typically when you are inside a loop that increments/decrements a value the timing is pretty consistent.
Again, I would be interested to know what others think of checking buttons with respect to safety critical programming and not using interrupts. _________________ Life is too short to only write code in assembly... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19543
|
|
Posted: Wed Mar 29, 2017 11:30 am |
|
|
There is actually nothing against interrupts in safety critical systems. It's usually accepted that they have to exist.
The problems are
1) They are so processor specific.
2) They can lead to difficult to track intermittent faults.
3) They can lead to stack overflow.
4) Interrupt overload.
Now the PIC (12/16/18), doesn't have the third problem (because they don't have a variable stack).
The second is down to using a carefully structured code.
The fourth only happens with external interrupt events, where if they arrive faster than expected, the rest of the code can become starved of resources. This is down to only using interrupts with known maximum frequencies (serial or timer for example), or adding hardware to limit the rate (a non retriggerable multivibrator for example on an external interrupt input).
The first is unfortunately unavoidable unless you go to one of the truly 'critical' processors, with very tightly defined/tested architecture... |
|
|
SkeeterHawk
Joined: 16 Oct 2010 Posts: 31 Location: Florissant, CO
|
|
Posted: Wed Mar 29, 2017 12:19 pm |
|
|
Great response, Ttelmah! It is good to get your input on this structure. I've always thought the same thing because you can't create a RTC without interrupts...unless you use a "critical" processor and an external RTC.
I think that I personally will start moving into utilizing the resources that I have at my disposal. I won't try anything stupid, like having nested calls within my timer loops or anything and cross the review bridge when/if it comes. I will probably just use the timer to set a flag that will trigger the acquisition of the buttons whenever the system gets ready for it.
Anyway, this has been a great discussion, and I sincerely appreciate everyone's input. _________________ Life is too short to only write code in assembly... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|