0
votes

I made a keypad that gives me an analog value. Now I want to detect which key is pressed based on the resistance. The values however are non linear.

I did this with a lot of "if/else-es". Is there a better way to do this?

if(analogValue < 159){
  keyPress(KEY_A_ACUTE);
}else if(analogValue < 400){
  keyPress(KEY_I_ACUTE);
}else if(analogValue < 537){
  keyPress(KEY_O_ACUTE);
}else if(analogValue < 624){
  keyPress(KEY_U_ACUTE);
}else if(analogValue < 685){
  keyPress(KEY_N_TILDE);
}else if(analogValue < 800){
  keyPress(KEY_E_ACUTE);
}
1
Depends, if it's only those 6 cases, it's fine. If it were >100 and performance is an issue, I would use a binary search for the matching intervalCtx
it's just these 6 cases but I'm trying to learn while doing so I was looking around for a function to map the values to the correct integersSam Apostel
Suggest using a 'jump table' and a bit of calculation on the analog value to determine which entry in the jump table is to be useduser3629249
temperature. humidity, supply voltage, circuit resistance, (perhaps even the phase of the mood) will cause changes in the analog readings. What is the reading when no button is pressed? Does the code allow for 'keybounce'user3629249
@user3629249 I know that the values I'm getting are a bit unpredictable but they fall into these bounds. my code does allow for keybounce and more but that's not the question. the code works but I don't like it. So I am asking for a better method.Sam Apostel

1 Answers

3
votes

You could create an array of a structure type and use a loop:

struct KeyValue
{
    int    key_name;
    int    max_value;  // Strictly less than threshold
};

static const struct KeyValue keys[] =
{
    { KEY_A_ACUTE, 159 },
    { KEY_I_ACUTE, 400 },
    { KEY_O_ACUTE, 537 },
    { KEY_U_ACUTE, 624 },
    { KEY_N_TILDE, 685 },
    { KEY_E_ACUTE, 800 },
};
enum { NUM_KEYS = sizeof(keys) / sizeof(key[0]) };

int analague_to_key_name(int analogue_value)
{
    for (int i = 0; i < NUM_KEYS; i++)
    {
         if (analogue_value < keys[i].max_value)
             return keys[i].key_name;
    }
    return KEY_UNKNOWN;
}

The only gotcha is dealing with values out of range — I chose to return a special KEY_UNKNOWN value but you can use any appropriate alternative strategy. Of course, the data must be in sorted increasing order of max_value.

One advantage of this technique is that it is unaffected by additions to the table, and can handle any arbitrary difference between threshold values. If the table gets big enough (a couple dozen entries, perhaps), you could switch to a specialized binary search on the value which would make fewer comparisons. The binary search is specialized because you'd need to accept a range; you might need to create the structure with min_value as well as max_value.