Analog decoding of keypad on DFRobot LCD/keypad shield

This is more of a conceptual question so I don’t have code to post yet but having conquered the LCD portion of the DFRobot LCD shield/keypad, I am now planning my attack on the keypad. From the schematic, the keypad is read by obtaining the values from AD0. AD0 is attached to a resistor string of five resistors from Vcc to Gnd with values of 2k, 330, 620, 1k and 3.3k. The “RIGHT” switch is from the junction of the 2k and the 330 to ground so when it is depressed (grounded), AD0 should read 0.0v. For the “UP” key, it should be somewhere around 0.825v (330/2000 * 5). The next switch 'DOWN" still uses AD0 at the same junction so now I should see approximately 2.375v (950/2000 * 5) and so on up to the “LEFT” switch which should produce about 3.75v.

So I read the value using AnalogRead(0) and must now compare it against each of the five possible values, accounting for the possibility that it might not match exactly. I’m looking for some ideas on the most efficient strategy for decoding the AnalogRead(0) value. Would a series of IF statements that bracketed the associated values be the most efficient way to do this? Maybe something like:

keypressed=analogRead(0);
if keypressed == 0
{
keycode = “SW_RIGHT”;
}
if keypressed > 3.70
{
keycode = “SW_LEFT”;
}
if (keypressed < 3.70 & keypressed > 3.30)
{
keycode = “SW_DOWN”;
}

and so on.

It seems to me that if the resistor string was properly chosen, you could have values that when divided by a constant end up with integer results that could then related to keys pressed but I have not yet discerned what that relationship is even though I have “done the math” of calculating the voltages for each divider.

I would welcome any ideas for attacking this in the smallest code possible because I have a sense that the way I proposed above is not going to be either fast or efficient.

paul

first of all, you don’t get the voltage, but a value between 0 and 5 volts, represented by a value between 0 and 1023.
do 0 is 0V and 1023 is 5V

maybe you could write your won small function that checks if a value is between some border values.

like this (just a concept):

#define difference 100
void setup()
{..}

void loop()
{
  ..
  keypress = analogRead(0)
  if(checkVal(keyPress, 800, difference)
    keycode = "SW_LEFT";
  //etc etc
}

boolean checkVal(int value, int ref, int diff)
{
  if(value>ref-diff && value<ref+diff)
    return true;
  return false;
}

You're absolutely right about the reported value being a number between 0 and 1023 - I was getting one step ahead of myself and maybe it would be better to skip the voltage conversion and just deal with the raw numbers. Just out of interest, I wrote a quick sketch to write the voltages to the LCD as I pressed each button and here is how it came out:

5.0v no button pressed 3.63v "Select" button pressed 2.47v "Left" button 1.61v "Down" button 0.70v "UP" button 0.0v "Right" button

I'll repeat that using the raw numbers but I can already see that I can test for the condition of a button pressed by looking for a voltage (or equivalent value) of 4v or lower. If I only have to test the conditions when there is a button pressed, I guess the overhead issue is not that big of a deal.

I like your idea of using a central value with an expected difference! I think if used with the raw values, that might be the way to go.

paul

I use the following code, which is based off of the example code that I found:

const int button_right	= 0;
const int button_up		= 1;
const int button_down	= 2;
const int button_left	= 3;
const int button_select	= 4;
const int button_none	= 5;

// read the buttons
int
read_LCD_buttons (void)
{
  int adc_key_in = analogRead (A0);

  // the buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  // We make this the 1st option for speed reasons since it will be the most likely result
 if (adc_key_in > 1000)
   return button_none;

 if (adc_key_in < 50)
   return button_right;

 if (adc_key_in < 195)
   return button_up;

 if (adc_key_in < 380)
   return button_down;

 if (adc_key_in < 555)
   return button_left;

 if (adc_key_in < 790)
   return button_select;

 return button_none;
}

If you are worried about the speed of reading the keys, you don’t want to do floating point, particularly floating point division. This is due to the fact that floating point arithmetic is all simulated by doing many integer instructions.