So I'm trying to store some numbers (like you would to enter a security pin for a lock) using an Arduino uno with a RobotDyn 3x4 keypad. I can get the keypad to display the number associated with the key pressed by doing a Serial.print on the case, but I can't seem to store the number and add it to the next number. I'm not sure what I'm doing wrong, probably a million things.
This is the code I have so far for this part of the project:
// analog pin connected to keypad
#define KEYPAD_PIN A0
// milliseconds to wait, to make sure key is pressed
#define TIME_TO_WAIT 100
int kp;
String kk;
void setup()
{
Serial.begin(9600);
}
char keypad()
{
// reading once
int r1 = analogRead(KEYPAD_PIN) / 10 * 10;
// waiting
delay(TIME_TO_WAIT);
// reading 2nd time - to make sure key is pressed for at least TIME_TO_WAIT milliseconds
int r2 = analogRead(KEYPAD_PIN) / 10 * 10;
if (r1 == r2) {
switch (r1) {
case 510: { char kp = 0; } break;
case 1020: { char kp = 1; } break;
case 930: { char kp = 2; } break;
case 850: { char kp = 3; } break;
case 790: { char kp = 4; } break;
case 730: { char kp = 5; } break;
case 680: { char kp = 6; } break;
case 640: { char kp = 7; } break;
case 600: { char kp = 8; } break;
case 570: { char kp = 9; } break;
case 540: { char kp = '*'; } break;
case 480: { char kp = '#'; } break;
}
return kp;
}
}
void store()
{ String kk = kk + kp; }
void loop()
{
keypad();
store();
Serial.println(kp);
}
Currently the code will not display the value for kp and kk is a million 0's. Thanks in advance for taking a look at my messy code.
Analogue is notoriously noisy - testing for equality is unlikely to give good results - allow 3 to 5 counts either side of the value you expect, and see how that goes.
I think I maybe described it poorly. I am able to get it to read the case value when I press the button. If I put Serial.print and the number there instead of { char kp = 0; } then it will display the number but I can't (using this code) get it to store a number associated with the case to use in another function or in the loop.
This will not work because you a declaring a new char variable named kp, you have not put single quotes around the value and in any case it will go out of scope at the end of the {} code block.
You already have a global variable named kp to which the keypress value could be assigned, so remove the char type specifier in the code similar to the line above and use it
String kk = kk + kp;
You cannot add an integer to a String, especially as you have just declared it and because it is a local variable it will have an unknown value.
You need to read up on the scope of variables an variable types
So I read about scope, and how to return a value from within a function. I thought I could do that with return, but maybe I'm misunderstanding it?
I changed the code to put single quotes on everything moved the return to within the {} but it still doesn't allow me to see what is being pressed from the loop.
Also I changed that int to char which would maybe help since it's being defined earlier? IDK. Thank you for looking at it. Here's the updated version based on your comments:
// analog pin connected to keypad
#define KEYPAD_PIN A0
// milliseconds to wait, to make sure key is pressed
#define TIME_TO_WAIT 100
char kp;
String kk;
void setup()
{
Serial.begin(9600);
}
char keypad()
{
// reading once
int r1 = analogRead(KEYPAD_PIN) / 10 * 10;
// waiting
delay(TIME_TO_WAIT);
// reading 2nd time - to make sure key is pressed for at least TIME_TO_WAIT milliseconds
int r2 = analogRead(KEYPAD_PIN) / 10 * 10;
if (r1 == r2) {
switch (r1) {
case 510: { char kp = '0'; } break;
case 1020: { char kp = '1'; } break;
case 930: { char kp = '2'; } break;
case 850: { char kp = '3'; } break;
case 790: { char kp = '4'; } break;
case 730: { char kp = '5'; } break;
case 680: { char kp = '6'; } break;
case 640: { char kp = '7'; } break;
case 600: { char kp = '8'; } break;
case 570: { char kp = '9'; } break;
case 540: { char kp = '*'; } break;
case 480: { char kp = '#'; } break;
return kp;
}
}
}
void store()
{ String kk = kk + kp; }
void loop()
{
keypad();
store();
Serial.println(kp);
}
OK so doing this helped and now I am cocatonating but the problem is it scrolls endlessly and keeps adding new numbers even though one has not been pressed... like it just keeps adding them.
I guess I probably need to figure out a way to make it so that it adds only when a new number is pressed though I'm a little unsure how to do that... back to google.
What analog value do you get when no key is pressed? Look for that value before accepting a new key. Add a key value that means NO_KEY_PRESSED and check for that before adding the key character to your string.
Something like this:
// analog pin connected to keypad
#define KEYPAD_PIN A0
// milliseconds to wait, to make sure key is pressed
#define TIME_TO_WAIT 100
const char NO_KEY_PRESSED = 0;
String kk;
void setup()
{
Serial.begin(9600);
}
char keypad()
{
char key = NO_KEY_PRESSED;
static char previousKey = NO_KEY_PRESSED;
// reading once
int r1 = analogRead(KEYPAD_PIN) / 10 * 10;
// waiting
delay(TIME_TO_WAIT);
// reading 2nd time - to make sure key is pressed for at least TIME_TO_WAIT milliseconds
int r2 = analogRead(KEYPAD_PIN) / 10 * 10;
// If the signal isn't stable, assume no key is pressed
if (r1 != r2)
{
previousKey = NO_KEY_PRESSED;
return NO_KEY_PRESSED;
}
switch (r1)
{
case 510: key = '0'; break;
case 1020: key = '1'; break;
case 930: key = '2'; break;
case 850: key = '3'; break;
case 790: key = '4'; break;
case 730: key = '5'; break;
case 680: key = '6'; break;
case 640: key = '7'; break;
case 600: key = '8'; break;
case 570: key = '9'; break;
case 540: key = '*'; break;
case 480: key = '#'; break;
}
// Accept a key only if it is different from the previous key
// Otherwise holding down a key will cause it to repeat
if (key != previousKey)
previousKey = key;
else
key = NO_KEY_PRESSED; // key is still pressed from last time
return key;
}
void store(char key)
{
kk = kk + key;
}
void loop()
{
char key = keypad();
if (key != NO_KEY_PRESSED)
{
store(key);
Serial.print(key);
}
}
johnwasser:
What analog value do you get when no key is pressed? Look for that value before accepting a new key. Add a key value that means NO_KEY_PRESSED and check for that before adding the key character to your string.
Something like this:
// analog pin connected to keypad
#define KEYPAD_PIN A0
// milliseconds to wait, to make sure key is pressed #define TIME_TO_WAIT 100
// reading once
int r1 = analogRead(KEYPAD_PIN) / 10 * 10;
// waiting
delay(TIME_TO_WAIT);
// reading 2nd time - to make sure key is pressed for at least TIME_TO_WAIT milliseconds
int r2 = analogRead(KEYPAD_PIN) / 10 * 10;
// If the signal isn't stable, assume no key is pressed
if (r1 != r2)
{
previousKey = NO_KEY_PRESSED;
return NO_KEY_PRESSED;
}
switch (r1)
{
case 510: key = '0'; break;
case 1020: key = '1'; break;
case 930: key = '2'; break;
case 850: key = '3'; break;
case 790: key = '4'; break;
case 730: key = '5'; break;
case 680: key = '6'; break;
case 640: key = '7'; break;
case 600: key = '8'; break;
case 570: key = '9'; break;
case 540: key = '*'; break;
case 480: key = '#'; break;
}
// Accept a key only if it is different from the previous key
// Otherwise holding down a key will cause it to repeat
if (key != previousKey)
previousKey = key;
else
key = NO_KEY_PRESSED; // key is still pressed from last time
OMG THIS WORKS 100% THANK YOU SO MUCH!!! I have been trying to get this part of my project to work now for like a month. I have every other aspect of it going (it's a robot bartender and it works using Alexa normally but I need a version that doesn't use internet too) and this silly keypad problem has been driving me nuts. I'm going to study the changes you made till I understand why this works like it does, but thank you again for taking the time to fix this for me! Also thanks to every person that contributed you all are the best!
I can se that the purpose being to zero the last digit, eg 988 becomes 980 and so on and that this is done to stabilize fluctuations in analog readings. But it makes no sense to multiply it with 10 - instead OP could settle on byte values (eg. 988 becomes 98) and save some memory. Or what about just using 8bit resolution in the first place?