Hi,
I was looking through the "Components Library" for a timer but didn't find what I thought would work so I'm looking for some help.
What I'm trying to do is create a counter while a button is pressed (held low).
If the button is held low for longer than (or equal to) 2 seconds, carryout the remaining code that will follow.
If the button is held low, less than 2 seconds, do nothing and reset the counter.
Can someone help me with this?
Thanks,
Brian
Brian
I would try (if highest timing accuracy is needed):
1. Configure a port interrupt that reacts to both positive and negative edges.
2. When the button is pressed the interrupt will be executed and you can check the port input state. If it is "pressed" state you can start either a 2s SW or HW timer.
3. If the interrupt fires again and it is found to be in the off state you can reset the HW or SW timer.
4. If the HW or SW timer fires (not reset within the 2 second period - i.e. the button remained pressed) it can carry or, or trigger the execution, of the next routine.
If the accuracy/resolution requirement is not that high and you have a system tick in operation (eg. every 50ms) it can also be used to sample the input state at each Tick point in time and count the number of successive periods where the button remains pressed. When there are 40 samples in a row pressed (counter >= 40) you can execute or trigger execution of the next routine. Every time you sample the button as not pressed simply reset the counter. Below is working code that does this.
The second method is the simplest in a man-machine environment where 2s +/- 50ms is not an issue. It also avoids possible switch bouncing effects in the interrupt case which may require a little caution to avoid race states when sampling the sate after each interrupt.
Regards
Mark
#define TICK_PER_SECOND 20
extern void fnTickCheck(void)
{
static int iPressInterval = 0;
if (_READ_PORT_MASK(A, BUTTON) == 0) { // is key pressed?
if (++iPressInterval >= (2 * TICK_PER_SECOND)) { // pressed - count the duration
if (++iPressInterval == (2 * TICK_PER_SECOND)) {
fnReactNow(); // pressed time elapsed - execute routine
}
else {
if (iPressInterval > (2 * TICK_PER_SECOND)) {
iPressInterval--; // peak hold the pressed duration until the key is released
}
}
}
}
else { // not pressed
iPressInterval = 0; // reset the press integrator
}
}
Hi Mark, thanks for the feedback.
When I view _READ_PORT_MASK(A, BUTTON) I don't fully understand that. I'm still getting started with Kinetis uC's.
My assumptions are as follows:
To test my understanding, I'll replace:
These steps will help me understand how the code is being processing.
If all works correctly I'll place NegVal(); for each color led, in the appropriate locations, and allow the code to run forever and see what happens when I press the button.
My screen capture below shows my code incorrectly written, I was testing some ideas to get a better understanding before I responded. I've been trying to figure this out myself before asking for help.
Thanks,
Brian
Brian
_READ_PORT_MASK() is just a macro:
#define _READ_PORT_MASK(ref, mask) (GPIO##ref##_PDIR & (mask))
_READ_PORT_MASK(B, 0x00020000); is therefore
(GPIOB_PDIR & 0x00020000)
Which is what you need for your input.
I just check on a FRDM-K22F, adding the LEDs more or less as you suggest.Note that the FRDM-K22F has red,green and blue and not yellow (although yellow results when read and green are on).
I did have an error in the original code since there were two lines incrementing the counter. This is the correct code:
{
static int iPressInterval = 0;
if (_READ_PORT_MASK(B, PORTB_BIT17) == 0) { // is key pressed?
_SETBITS(A, PORTA_BIT2); // green LED off
if (++iPressInterval >= (2 * TICK_PER_SECOND)) { // pressed - count the duration
if (iPressInterval == (2 * TICK_PER_SECOND)) {
_CLEARBITS(A, PORTA_BIT1); // red LED on
}
else {
if (iPressInterval > (2 * TICK_PER_SECOND)) {
iPressInterval--; // peak hold the pressed duration until the key is released
_CLEARBITS(D, PORTD_BIT5); // blue LED on
}
}
}
}
else { // not pressed
iPressInterval = 0; // reset the press integrator
_CLEARBITS(A, PORTA_BIT2); // green LED on
_SETBITS(D, PORTD_BIT5); // blue LED off
}
}
I have attached a binary for the board showing it in operation plus a simulation (unzip the attached and start the simulation with a double click on uTaskerV1.4.12_FRDM-K22F_ButtonTest2s.exe. When it runs it looks like below and you can click on the button to hold it down and see the LED reacting (same as on the HW).
Regards
Mark
You mentioned a binary and a zip file uTaskerV1.4.12_FRDM-K22F_ButtonTest2s.exe would be attached.
Brian
They are attached - you may need to be logged in to see them.
Regards
Mark
Got it! Thanks
Great, thanks Mark, I'll give it a go!