Hi,
I am using a NANO 328p to send IR commands. I am wondering what the best way to detect buttons, given 5 buttons that map below to pins. I want to debounce the press and do that for combinations also.
These are button inputs on PortD with internal pullups enabled on all listed pins.
Fwd = 12
Rev = 11
Lef = 10
Rit = 9
Tbo = 8
So I can have a combination of button presses I want to do. Like:
Fwd
Fwd + Lef
Fwd + Rit
Rev
Rev + Lef
Rev + Rit
etc.....
When you press two buttons "at the same time", how long do you want to wait to determine if the first button that closes is a single button or part of a combination?
I took a stab at making a debounce but I think I have logic holes in what I want to accomplish. I want to look for changes on PINB which is the upper byte of PORTD pin status register on Nano 328P. I verified that masking off the upper 3 bits and looking at Pin8 ~ Pin12 works. These inputs are all pull high so unpressed state is B00011111.
So now I have the port status for the state of the pins I am interested in. This pins are connected to momentary switches. Each correspond to a direction to control a remote vehicle.
pin 12 - FWD
pin 11 - REV
pin 10 - Right
pin 9 - Left
pin 8 - Turbo
So I guess I am debouncing 5 pins for changes. The problem is if a change happens during my while loop, I will exit with the status of the pins not completing the debounce. loadTX-Decode is used by my switch case statement to decode 1 button or 2 buttons correspond to what action.
Example: I can push and hold FWD, then while doing that, push and hold RIGHT or LEFT.
Since I am controlling something in real time, sending a 0 or stop command between button combinations is going to make movement jerky and non-continuous. Adding in more than 10ms debounce will serious lag the response of the vehicle. Not sure how to handle this.
void readButtonPress() {
Whatisinit = PINB & B00011111; // apply mask to focus on pins of interest
if (Whatisinit != B00011111){ // a button was pressed
WhatNow = PINB & B00011111;
count = 0;
while ((Whatisinit = WhatNow) && (count < 5)) {
delay(4);
WhatNow = PINB & B00011111;
count++ ;
loadTX_Decode = WhatNow; // pass along the debounced switch presses to decode function
}
}else{
loadTX_Decode = B00011111; // pin 8 to pin 12 all high means no button press or all stop
}
}
I see what you are trying and I think this might do what you want:
void readButtonPress()
{
static byte wereUnpressed = B00011111;
static boolean newChange = false;
byte areUnpressed = PINB & B00011111; // apply mask to focus on pins of interest
if (areUnpressed != wereUnpressed)
{
// The pattern has changed. Start a timer.
lastChangeTime = millis();
newChange = true;
}
else
{
// The pattern has NOT changed
if (newChange && millis() - lastChangeTime > 20)
{
// The change has been present for 20 ms
wereUnpressed = areUnpressed; // Remember the new pattern
loadTX_Decode = areUnpressed; // Act on the new pattern
newChange = false; // Mark the pattern as handled.
}
}
}
Ah, I see where I went off the track. I was of the mindset that I needed to hold the debounce in a captive loop. Falling through to the next pass through is the right way. I will give it a try tomorrow. Today was family day :). Thanks for the help!
I had a chance to test the function. It keeps returning 31 no matter what button I press. Also, it seems to send it over and over even when the button is released. Trying to figure out where it is hanging up. Also, updates the serial monitor only when the key is let go. Not while it is held down.
OK, I modified your code and now seems to be working. But I think it is not debouncing anything. I increased the > 20 to seconds and it instantly decodes the button press. Still not where I want it to be....I will continue to tinker.
void readButtonPress(){
static byte wereUnpressed = B00011111;
byte lastChangeTime;
static boolean newChange = false;
byte areUnpressed = PINB & B00011111; // apply mask to focus on pins of interest
if (areUnpressed != wereUnpressed)
{
lastChangeTime = millis(); // The pattern has changed. Start a timer.
newChange = true;
}
if (newChange && (millis() - lastChangeTime) > 20) // The pattern has NOT changed
{
// The change has been present for 20 ms
wereUnpressed = areUnpressed; // Remember the new pattern
loadTX_Decode = areUnpressed; // Act on the new pattern
newChange = false; // Mark the pattern as handled.
}
}
The value 31 (B00011111) means none of the buttons are pressed. Just ignore that value. If pressing a button is not changing the pattern then I suspect your buttons are wired wrong.
The variable 'loadTX_Decode' will always have a value. Do you have a way to detect when it has a NEW value? I would probably use a value like B00100000. Act on the pattern only when it is not B00100000. When done with a value, set loadTX_Decode to B00100000.
I have something that works. It is going through and evaluating the millis() difference in timing.
I send the content of myTime3 to serial monitor at 1200 baud (the output needed for IR). The loop count comes back at 33ms. When I bump up the serial output to 115,200 baud it comes back as expected and counts, 0, 1, 2 , 3, 4, 5---> jumps out and write the bit pattern out.
I thought serial UART was a hardware function.....so why is 1200 baud causing my loop delay to multiply by 6 or so......33ms with a 5 millisecond count?