So this has likely been covered, but my foggy brain is having trouble finding the answer. I am creating an elevator keypad like device for a project. And one of the things that I am needing to do is register the various buttons being pressed, and only being pressed once (not hold button down and it triggers it over and over).
I am only including the needed lines of code (not the extras that are not relevant [ie Ethernet shield, RFID reader, 4 digit display]). What happens here, is I have 12 buttons each wired to a digital input on a Mega board with internal pullup resistor turned on and buttons grounded to the ground pin.
When I push button 1, it triggers (going low) and sends serial command button 1 pressed. However button 2 is also triggered and that loops as long as button 1 is held down. When button 1 is released I get the Serial command that button 1 released. Similar thing happens with button 2.
I am really at a loss here and my foggy brain just wants it to be when button 1 is pressed a single event is triggered for button 1, and then when button 1 is released it allows another button to be pushed. Much love and Thank you in Advance for seeing what my tired ol brain is failing to see.
// CONSTANTS
//elevator buttons
const int num_buttons = 12;
const int button_1 = 38;
const int button_2 = 39;
const int button_3 = 40;
const int button_4 = 41;
const int button_5 = 42;
const int button_6 = 43;
const int button_7 = 44;
const int button_8 = 45;
const int button_9 = 46;
const int button_0 = 48;
const int button_clue = 47;
const int button_go = 49;
bool pushed[num_buttons];
// elevator buttons pushed
int buttonposition1 = -1;
int buttonposition2 = -1;
int buttonposition3 = -1;
int buttonposition4 = -1;
int button_pushed = 0;
String buttonsequence = "";
String button1 = "";
String button2 = "";
String button3 = "";
String button4 = "";
void setup()
{
Serial.begin(115200);
pinMode(button_1, INPUT_PULLUP);
pinMode(button_2, INPUT_PULLUP);
pinMode(button_3, INPUT_PULLUP);
pinMode(button_4, INPUT_PULLUP);
pinMode(button_5, INPUT_PULLUP);
pinMode(button_6, INPUT_PULLUP);
pinMode(button_7, INPUT_PULLUP);
pinMode(button_8, INPUT_PULLUP);
pinMode(button_9, INPUT_PULLUP);
pinMode(button_0, INPUT_PULLUP);
pinMode(button_clue, INPUT_PULLUP);
pinMode(button_go, INPUT_PULLUP);
}
void loop() {
// read button pushes
int status_button1 = digitalRead(button_1);
int status_button2 = digitalRead(button_2);
int status_button3 = digitalRead(button_3);
int status_button4 = digitalRead(button_4);
int status_button5 = digitalRead(button_5);
int status_button6 = digitalRead(button_6);
int status_button7 = digitalRead(button_7);
int status_button8 = digitalRead(button_8);
int status_button9 = digitalRead(button_9);
int status_button0 = digitalRead(button_0);
int status_button_clue = digitalRead(button_clue);
int status_button_go = digitalRead(button_go);
if (status_button1 == LOW and button_pushed == 0) {
Serial.println("triggered 1, low");
numButtonPushed("1", false);
} else if (status_button1 == HIGH and button_pushed == 1) {
Serial.println("triggered 1, high");
numButtonPushed("1", true);
}
if (status_button2 == LOW and button_pushed == 0) {
Serial.println("triggered 2, low");
numButtonPushed("2", false);
} else if (status_button2 == HIGH and button_pushed == 1) {
Serial.println("triggered 2, high");
numButtonPushed("2", false);
}
}
int numButtonPushed(String buttonNumber, bool buttonReleased) {
if (buttonReleased == false) {
if (button_pushed == 0) {
Serial.println("Button " + buttonNumber + " pushed.");
button_pushed = 1;
}
} else if (buttonReleased == true) {
Serial.println("Button " + buttonNumber + " released.");
button_pushed = 0;
}
}
void clueButtonPushed() {
}
void goButtonPushed() {
}
Your logic is unnecessarily complex. Also, you would benefit from using arrays.
Here is your logic issue. When button 1 is pressed numButtonPushed() function sets button_pushed to 1. When the you check status_button2 it is HIGH and button_pushed is 1 and therefore the logic assumes button 2 is being released! It then calls numButtonPushed() and sets button_pushed to 0 and then loop() starts over and assumes button 1 was just pressed...ad infinitum.
Also, it seems like a pretty simple concept: only register the button being pushed and ignore others. However, you have to ask yourself: If one button is already registered as pushed and if more buttons are then pushed when the first is released do I register another button pushed? OR Do I wait until no buttons are pushed and register the first button pushed as the one pushed?
Then throw in 1 more variable and 1 more condition in for loop,
Change your bool array to array of appropriate type(ex. uint8) to hold multiple entries entries of same number on keypad or whatever and as soon as that extra variable reaches to 4 call the function which gonna deal whatever will be next and reset at the end the array to initial state. Plus u have to have some sort of timer.
Ideally this should be event-time based code.
Interrupts+timers and 99% of time ic must sleep. I bet there are many examples in internet of someone who already did this or very close to this project just take it and adapt to your needs not to spent too much time on trial and error unless its just a fun hobby project and u are willing to learn by doing.
Best approach is register manipulation but as i am working not on atmega mcu and have limited free time for datasheet cant come up with better approach than to cycle thru the loop for pinmode.
For 3rd question i++ in fact is in for loop search for matching closing bracket. Its right after i++ which means i++ is within for loop.
for (unsigned char i = button_1; i <= button_go; pinMode(i++, INPUT_PULLUP));
As i understood u r referring to this loop not the second one. And here i see 3 options of incrementing “i” either where it is now or outside of the brace separately or in conditional section.
Update: i missed “cryptic” part. Well with that i cant argue ya some are not happy. But this one isnt that bad u havent seen my ternery chaining stretching 2 good lines on screen
I'm sorry that I was so vague. It was not my intention. Yes, I am wanting 4 digits to be saved then the go button is pushed and it acts on it. The reason I am adding a go button, is the code could be 4 digits, or it could be smaller. 'GO' would theoretically send what has currently been entered.
All that being said. I am intrigued by the loops for setting and reading the value of buttons. But unfortunately that level of coding is a bit lost on me.
I have been coding in one format or another off-on for over 30 years, and there is times that things still kick my butt when I encounter a methodology that I am unfamiliar with (arrays being one of them). Can someone be kind enough to show me what they mean by this a little further.
Yes I have heard of the keypad library. However this project is for an elevator type game where you enter a 4 digit code and click go. The buttons are reminiscent of elevator buttons. (The other reason, I had the elevator buttons, and such made into a stainless steel plate custom for this game.) This Arduino is serving multiple uses (It has an RFID reader, a 4 digit display, the 12 buttons, ethernet shield, and quite possible a reed switch to measure if a door is open or closed.) The idea, is when the 4 digit code is entered and go is pressed, it is send via API call to Node Red. Node Red is waiting for a specific string of numbers. If the wrong string is entered the crown molding lights change to red for 1 second and then go back white (this is done via an API call to another Arduino with REST commands.) The clue button is to trigger to a games master that they are requesting a clue for their current puzzle. and the RFID is for the final puzzle of the game.
As for this Arduino, I was only giving the pertinent lines of code/area that I am having trouble with. Because once I understand the code, I can adapt it to what I need quite quickly and easily.
This part of the code is a bit of an oddity to me so that is why it is kicking my butt. Does this help?
Okay... Found some code that was explained to me, and it makes sense now. Here is the basic configuration of what I settled on. This is almost completed, I still have other things to do on this, but it is working better now. Thank you for the suggestions, I really do appreciate your time.
//elevator buttons
int nbts = 12;
int bts[12];
boolean btgs[12];
// elevator buttons pushed
String buttonsequence = "";
void setup()
{
Serial.begin(115200);
for (int x = 0; x < nbts; x++) bts[x] = x + 38;
for (int x = 0; x < nbts; x++) btgs[x] = false;
for (int x = 0; x < nbts; x++) pinMode(bts[x], INPUT_PULLUP);
Serial.println(F("Ready for API."));
}
void loop() {
// read button pushes
for (int i = 0; i < nbts; i++) {
if (!btgs[i]) {
if (digitalRead(bts[i]) == LOW) {
// Serial.print("bt" + String(i) + ": ");
// Serial.println("pressed");
btgs[i] = true;
if (i == 10) { // go button pressed
Serial.println("Go Button Pressed!");
goButtonPushed();
} else {
if (buttonsequence.length() == 4) {
Serial.println("Max code reached cannot add additional numbers, simulating go button.");
goButtonPushed();
} else {
buttonsequence += String(i + 1);
display.clear();
display.showNumberDec(buttonsequence.toInt(), false);
Serial.print("sequence: ");
Serial.println(buttonsequence);
}
}
}
} else {
if (digitalRead(bts[i]) == HIGH) {
// Serial.print("bt" + String(i) + ": ");
// Serial.println("released");
btgs[i] = false;
}
}
// put code to do actions
}
}
void goButtonPushed() {
Serial.println(buttonsequence);
buttonsequence = "";
}
for (unsigned char i = button_1; i <= button_go; i++)
pinMode(i, INPUT_PULLUP);
and
for (unsigned char i = button_1; i <= button_go; i++) {
pushed[i - button_1] = digitalRead(i)) {
if (!pushed[i - button_1]) {
Serial.print(F("triggered"));
Serial.print(i - button_1);
Serial.println(F("pushed"));
button_pushed = !button_pushed;
//call whatever function u want and reset the array there;
}
}
i assume you're thinking they are the same thing. but it's helpful to others reading/reviewing the code to see common approaches. that saves time, is more easy to spot bugs and allows more time for the unique parts of the code
for example, if (!pushed[i - button_1]) looks like it's checking is the button is being pressed. i would have first checked for a state change and then check ifi the button became pushed