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