Potentiometers in my project send MIDI data, therefore I need 7-bit resolution. Here is how my current debouncing algorithm works:
First I'm setting the active input on 4051 multiplexers on which potentiometers are connected:
void setMuxOutput() {
//reset the variable to 0 after its value reaches 8 using masking
muxInput &= 7;
//switch to next mux input
PORTC = muxInput << 2;
}
After that I'm reading the pots:
void readPots() {
//check analogue inputs from 2 4051 analogue multiplexers
for (int i=0; i<NUMBER_OF_MUX; i++) {
//calculate pot number
uint8_t potNumber = (i*8) + muxInput;
//read analogue value from mux
//we need 7-bit value for MIDI message
int8_t tempValue = analogRead(analogueInputArray[i]) >> 3;
//if new reading is stable send new MIDI message
if (potValueStable(tempValue, lastAnalogueValue[potNumber], analogueValueTimer[potNumber])) {
//debugging
Serial.print("Pot number: ");
Serial.println(potNumber);
Serial.print("Value: ");
Serial.println(tempValue);
Serial.print("Current time: ");
Serial.println(millis());
Serial.println();
}
}
//increment mux input for next loop iteration
muxInput++;
}
potValueStable is a function which returns true if pot value passes through a series of conditions:
potValueStable(int16_t currentValue, int16_t previousValue, uint32_t analogueValueTimer) {
//calculate difference between current and previous reading
int16_t analogueDiff = currentValue - previousValue;
if (analogueDiff < 0) analogueDiff *= -1;
/*
When value from pot hasn't changed for more than ANALOGUE_TIMEOUT_MAX value (time in ms), pot must
exceed FILTER_AMOUNT (2) value. If the value has changed during ANALOGUE_TIMEOUT_MAX, it must be
different from previous reading (analogueDiff > 0). If any condition is true, analogueValue timer
is updated. If there is some difference between the two readings and change occurred in less
than ANALOGUE_TIMEOUT_MIN ignore the reading.
*/
if
(
(analogueDiff >= ANALOGUE_THRESHOLD) ||
(
(analogueDiff > 0) &&
((millis() - analogueValueTimer) < ANALOGUE_TIMEOUT_MAX)
&& ((millis() - analogueValueTimer) > ANALOGUE_TIMEOUT_MIN)
)
)
{
//reset timer on each new value
analogueValueTimer = millis();
//update previous pot value
previousValue = currentValue;
return true;
}
return false;
}
ANALOGUE_TIMEOUT_MAX is set to 200ms and ANALOGUE_TIMEOUT_MIN is set to 5ms.
So, this is how the regular readings look like:
Pot number: 8
Value: 73
Current time: 115934Pot number: 8
Value: 74
Current time: 115944Pot number: 8
Value: 75
Current time: 115960Pot number: 8
Value: 76
Current time: 115979
Now I waited a couple of seconds and then continued to move the pot:
Pot number: 8
Value: 78
Current time: 118244Pot number: 8
Value: 79
Current time: 118280Pot number: 8
Value: 80
Current time: 118349
So, if you get stable reading from pot and then you don't move it for longer than ANALOGUE_TIMEOUT_MAX (200ms) the difference between last and current reading must be ANALOGUE_THRESHOLD, which is 2. All fine so far, but there is still a case when values start jumping and this is the part I'm struggling to solve (note that I moved the pot only first time, the rest of values were jumping without any touching of pot):
Pot number: 8
Value: 100
Current time: 190818Pot number: 8
Value: 101
Current time: 190830Pot number: 8
Value: 100
Current time: 190907Pot number: 8
Value: 101
Current time: 190919Pot number: 8
Value: 100
Current time: 190982Pot number: 8
Value: 101
Current time: 190993Pot number: 8
Value: 100
Current time: 191011
Time difference between those values is less than I defined with ANALOGUE_TIMEOUT_MAX and more than ANALOGUE_TIMEOUT_MIN, so they're right in the range when it's actually possible to move the pot at that speed. So, what are your suggestions for this problem? I would appreciate any advice.