Storing a keypad entry on a one pin keypad (using resistors to get a key) SOLVED

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.

    switch (r1)
    {
      case 510:
        {
          char kp = 0;
        }

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);

}

So I read about scope,

It seems you didn't read the bit about scope being restricted to a code block.

  if (r1 == r2) {
        switch (r1) {
        case 510: { char kp = '0'; } break;
        case 1020:  { char kp = '1'; } break;
        case 930: { char kp = '2'; } break;
  if (r1 == r2) {
        switch (r1) {
        case 510: {  kp = '0'; } break;
        case 1020:  { kp = '1'; } break;
        case 930: {  kp = '2'; } break;

etc, etc

TolpuddleSartre:
It seems you didn't read the bit about scope being restricted to a code block.

  if (r1 == r2) {

switch (r1) {
        case 510: { char kp = '0'; } break;
        case 1020:  { char kp = '1'; } break;
        case 930: { char kp = '2'; } break;






if (r1 == r2) {
        switch (r1) {
        case 510: {  kp = '0'; } break;
        case 1020:  { kp = '1'; } break;
        case 930: {  kp = '2'; } break;


etc, etc

Ahhhh I definitely didn't understand it if I did read it! This new fix has it so I can at least get the value from kp! thank you very much!

Trying to concatenate the values still isn't working but this has been a great help!

You're not using the return value.

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.

void store()
{ 
  keypad();
  kk = kp + kk;
  
  return kk;
  }

void loop()
{
keypad();
store();
Serial.println(kk);

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.

Thank you everyone for your help on this.

void store()
{ 
  keypad();
  kk = kp + kk;
  
  return kk;
  }

You're returning a global
from a void function?

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

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);
  }
}

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!

Why divide a value by 10 just to multiply by 10 again?

analogRead(KEYPAD_PIN) / 10 * 10

Danois90:
Why divide a value by 10 just to multiply by 10 again?

analogRead(KEYPAD_PIN) / 10 * 10

I stole the code for that part from here:

The OP does not explain why but I suspect it helps give a better reading. Sorry I couldn't give you a good answer there on my own.

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?

On the other hand, if it works why fix it? :wink: