I am making a keypad using the pro micro as an HID device for the game "osu!"
I am adding up to 6 buttons on each individual pin. I am using a pull-down resistor.
I used the debounce library and made my own code from it. Is there anyway to optimize the code such that it reduces space like using an array for example?
Here is the code for one button. I use this function for all the buttons and put them in a loop.
#include "Keyboard.h"
const byte button1Pin = 2; // the number of the pushbutton pin
const byte button2Pin = 3;
// Variables will change:
byte button1State; // the current reading1 from the input pin
byte button2State;
byte lastButtonState[7] = {LOW, LOW, LOW, LOW, LOW, LOW}; // the previous reading1 from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 10; // the debounce time; increase if the output flickers
void button1()
{
// read the state of the switch into a local variable:
int reading1 = digitalRead(button1Pin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading1 != lastButtonState[0]) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading1 is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading1 != button1State) {
button1State = reading1;
// only toggle the LED if the new button state is HIGH
if (button1State == HIGH) // HIGH because when pressing the button, 5v will connect from the button to the pin. also the resistor is connected to the ground so when button is pressed, the path to least resistance is the volts
{
Keyboard.press('x');
}
else
{
Keyboard.release('x');
}
}
}
The MoToButtons class of the MobaTools library debounces and manages up to 32 buttons in one instance.
If you don't need anything else of MobaTools, you can copy MoToButtons.h into your sketch directory. It contains everything you need. Or you install the complete library by means of the library manager.
(johnwasser, I asked myself the question, but it seems that gale_electronics use digital pins).
To optimize the code, if my approach suits you, the 6 keys test is done like this: (this is an example for demo, the code must be adapted a bit in reality)
if (button1 & pressed) {action...}
if (button2 & pressed) {action...}
if (button1 & released) {action...}
You need pullups (use the internal ones, see setup), and the buttons are wired between the pin and the ground (for security, I add a 1 k resistor between the pin and the button)
#define button1 4 // binary value of the pushbutton pin 2
#define button2 8 // binary value of the pushbutton pin 3
#define button3 16 // binary value of the pushbutton pin 4
#define button4 32 // binary value of the pushbutton pin 5
#define button5 64 // binary value of the pushbutton pin 6
#define button6 128 // binary value of the pushbutton pin 7
byte Down, Stat, Up, kkk; // variables for 6 keys together (max 16)
void setup() { // INITIALIZATION CODE
PORTD |= button1|button2|button3|button4|button5|button6; // PD7..2 with pullups (pin7....pin2)
Serial.begin(115200); // (9600 is the default serial-monitor)
}
void loop() { // MAIN CODE
detectButtons(); // is a button pressed or released ?
if (button1 & Down) Serial.println("KEY 1 PRESSED+++"); // your treatment
if (button1 & Up) Serial.println("Key 1 released--"); // ...
}
void detectButtons (void) { // debounce, state, and front detections
delay(20); // delay for demo...
byte iii = ~PIND & 0xFC; // reading PORTD pin 7..2 (with pullups)
byte jjj = Stat; //
Stat = iii & kkk; // while key is maintained pressed
Down = (jjj ^ Stat) & Stat; // when key is just pressed down
Up = (iii ^ jjj) & jjj; // when key is released
kkk = iii; // key configuration stored for next use
}
Yikes! They are using Direct Port Access to read pins 2 through 7. That's not "6 buttons on each individual pin". That's like setting pins 2 through 7 to "INPUT_PULLUP" and using digitalRead() on each one.
gale_electronics uses digital pins 2 and 3 in his example, it doesn't seem to be 6 buttons on an analog pin (with resistors), so I condensed the code (with a direct digital reading) since he wanted to optimize the size.
adopt your function and handover the index (starting with 0!!!)
pseudo code - untested:
void button(byte i)
{
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin[i]);
if (reading != lastButtonState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != buttonState[i]) {
buttonState[i] = reading;
if (buttonState[i] == HIGH) // HIGH because when pressing the button, 5v will connect from the button to the pin. also the resistor is connected to the ground so when button is pressed, the path to least resistance is the volts
{
Keyboard.press('x');
}
else
{
Keyboard.release('x');
}
}
}
}
step 2
bundle the arrays into a structure
step 3
make a class with member function
step 42
never start variable numbering with 1 again
You’ll want to have a timer on each input; since you appear to enjoy getting down with the code, I suggest you implement vertical counters - it would fit right in with you byte-wide approach.
Hi noiasca, in this IDE example, I read:
"how to debounce an input, which means checking twice in a short period of time"
"Short period of time" isn't a delay ?
No problem! I made it clear that my first example was a quick demo, where I used the delay() function for convenience, to display the activated keys on the terminal-series. If you want the non-blocking version, it's not too difficult:
#define button1 4 // binary value of the pushbutton pin 2
#define button2 8 // binary value of the pushbutton pin 3
#define button3 16 // binary value of the pushbutton pin 4
#define button4 32 // binary value of the pushbutton pin 5
#define button5 64 // binary value of the pushbutton pin 6
#define button6 128 // binary value of the pushbutton pin 7
#define allButtons 4 + 8 + 16 + 32 + 64 + 128 // binary value of all buttons together
byte Down, Stat, Up, tempo; // variables for 6 keys together (max 16)
unsigned long previousmillis; // debounce period
void setup() { // INITIALIZATION CODE
PORTD |= allButtons; // PD7..2 with pullups (pin7....pin2)
Serial.begin(115200); // (9600 is the default serial-monitor)
}
void loop() { // MAIN CODE
detectButtons(); // is a button pressed or released ?
}
void detectButtons (void) { // debounce, state, and front detections
if (millis() - previousmillis > 20) { // xx ms delay for debounce, usually 10 or 20 (ms)
previousmillis = millis(); //
byte iii = ~PIND & allButtons; // reading PORTD pin 7..2 (with pullups)
byte jjj = Stat; //
Stat = iii & tempo; // while key is maintained pressed
Down = (jjj ^ Stat) & Stat; // when key is just pressed down
Up = (iii ^ jjj) & jjj; // when key is released
tempo = iii; // key configuration stored for next use
if (button1 & Down) Serial.println("KEY 1 PRESSED+++"); // your treatment
if (button1 & Up) Serial.println("Key 1 released--"); // ...
}
}
Closer. It is still not as good as you can do; you really need a timing mechanism on each input line.
This is illustrated in the code from @noiasca's #10 above.
It was untested code - there were a few thinkos and maybe a show-stopper, I fixed it up like so
void button(byte i)
{
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin[i]);
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != lastButtonState[i]) {
lastDebounceTime[i] = millis();
lastButtonState[i] = reading;
if (lastButtonState[i] == LOW) // LOW because I wired it to use the internal pull up resistors.
{
// Keyboard.press('x');
Serial.print(i); Serial.println(" pressed");
}
else
{
// Keyboard.release('x');
Serial.print(i); Serial.println(" released");
}
}
}
}
and threw it into the wokwi where it seems to function.
To understand why you need want a timer on each input, crank up the debounce interval you've coded to 500 ms or so and play with the buttons...
And since you've done a broadside approach to multiple pins using direct port and bit manipulation, I thought the vertical counters would be perfect.
And since you've done a broadside approach to multiple pins using direct port and bit manipulation, I thought the vertical counters would be perfect.
Show us how you add vertical counters on my code, because I'm not sure I understand the benefit of it. Of course, there are many ways to manage buttons, but the one I use works perfectly and it can't be shorter! (that's the purpose of this particular code : to be short, 6 lines for 1 to 16 independent buttons). Why do you want to add counters on each bit ?
To understand why you need want a timer on each input, crank up the debounce interval you've coded to 500 ms or so and play with the buttons...
I'm trying to visualize what would happen with a 500ms (or even longer) debounce interval, but it wouldn't change the way the buttons work, they would be detected in the same way, independently of each other. Try it in a wokwi! (I don't know how to do it yet ; but wokwi and real time are not very compatible! )