Arduino Forum

Using Arduino => Programming Questions => Topic started by: kustom on Feb 09, 2014, 04:34 pm

Title: Debouncing a potentiometer
Post by: kustom on Feb 09, 2014, 04:34 pm
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:

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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:

Quote

Pot number: 8
Value: 73
Current time: 115934

Pot number: 8
Value: 74
Current time: 115944

Pot number: 8
Value: 75
Current time: 115960

Pot number: 8
Value: 76
Current time: 115979


Now I waited a couple of seconds and then continued to move the pot:

Quote
Pot number: 8
Value: 78
Current time: 118244

Pot number: 8
Value: 79
Current time: 118280

Pot 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):

Quote
Pot number: 8
Value: 100
Current time: 190818

Pot number: 8
Value: 101
Current time: 190830

Pot number: 8
Value: 100
Current time: 190907

Pot number: 8
Value: 101
Current time: 190919

Pot number: 8
Value: 100
Current time: 190982

Pot number: 8
Value: 101
Current time: 190993

Pot 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.
Title: Re: Debouncing a potentiometer
Post by: Robin2 on Feb 09, 2014, 04:58 pm
What happens if you take a few readings and average them? 4 or 8 readings makes the averaging easier.

Is the impedance of the pot 10k or less?

I presume you know to allow a settling time when you change to reading a different pot.

...R
Title: Re: Debouncing a potentiometer
Post by: kustom on Feb 09, 2014, 05:02 pm

What happens if you take a few readings and average them? 4 or 8 readings makes the averaging easier.

Is the impedance of the pot 10k or less?

I presume you know to allow a settling time when you change to reading a different pot.

...R


In between setMuxOutput and readPots functions is function which reads 4x5 button matrix and handles few LEDs, so I pressumed that time needed for that is enough to allow some settling of pins. The pots are 10k yes, linear. I haven't tried averaging the pots yet, I'll try.
Title: Re: Debouncing a potentiometer
Post by: kustom on Feb 09, 2014, 06:03 pm

In between setMuxOutput and readPots functions is function which reads 4x5 button matrix and handles few LEDs, so I pressumed that time needed for that is enough to allow some settling of pins.


Wrong presumption. Time difference was less than 1 ms, so I added a new variable, uint32_t muxSettleTime, so now setMuxOutput looks like this:

Code: [Select]
void setMuxOutput() {
 
   if (!muxSettleTime) {

//reset the variable to 0 after its value reaches 8 using masking
   muxInput &= 7;
   
   //switch to next mux input
   PORTC = muxInput << 2;

muxSettleTime = millis();

}

}


And readPots() is also slighty modified:

Code: [Select]
void readPots() {

if ((millis() - muxSettleTime) > 3) {

muxSettleTime = 0;


....


...


muxInput++;

}


Due to 3 ms delay between seting pins and reading the values, I also removed the following check from potValueStable function:

Code: [Select]
&& ((millis() - analogueValueTimer) > ANALOGUE_TIMEOUT_MIN)

So far, the values aren't jumping but I'll play around with pots for some more time and report back here.