Flickering Potentiometer

hi to all,

after so many of my posts and the help given me on this forum I managed to connect:

152 potentiometers on 9 multiplexer

The problem is that the potentiometers tremble and the value in ableton is constantly changing even if i touch anything the flicker oscillates between + 2 / -2
here is the code:

#include <MIDI_Controller.h> // Include the library

// Create 2 instances of 'AnalogMultiplex' with the output pins of the multiplexers connected to
// analog input pin A0 and A1 respectively, and the address pins connected to pins 2, 3 and 4.

AnalogMultiplex multiplexers[] = {
  {A0, { 2, 3, 4, 5 } },
  {A1, { 2, 3, 4, 5 } },
  {A2, { 2, 3, 4, 5 } },
  {A3, { 2, 3, 4, 5 } },
  {A4, { 2, 3, 4, 5 } },
  {A5, { 2, 3, 4, 5 } },
  {A6, { 2, 3, 4, 5 } },
  {A7, { 2, 3, 4, 5 } },
  {A8, { 2, 3, 4, 5 } },
  {A9, { 2, 3, 4, 5 } },
  {A10, { 2, 3, 4, 5 } },
};

// Create 16 new instances of the class 'Analog', on the 16 pins of the multiplexers,
// that send MIDI messages with controller 7 (channel volume) on channels 1 - 16
Analog potentiometers[] = {
  {multiplexers[0].pin(0), MIDI_CC::Channel_Volume, 1},
  {multiplexers[0].pin(1), MIDI_CC::Channel_Volume, 2},
  {multiplexers[0].pin(2), MIDI_CC::Channel_Volume, 3},
  {multiplexers[0].pin(3), MIDI_CC::Channel_Volume, 4},
  {multiplexers[0].pin(4), MIDI_CC::Channel_Volume, 5},
  {multiplexers[0].pin(5), MIDI_CC::Channel_Volume, 6},
  {multiplexers[0].pin(6), MIDI_CC::Channel_Volume, 7},
  {multiplexers[0].pin(7), MIDI_CC::Channel_Volume, 8},
  {multiplexers[0].pin(8), MIDI_CC::Channel_Volume, 9},
  {multiplexers[0].pin(9), MIDI_CC::Channel_Volume, 10},
  {multiplexers[0].pin(10), MIDI_CC::Channel_Volume, 11},
  {multiplexers[0].pin(11), MIDI_CC::Channel_Volume, 12},
  {multiplexers[0].pin(12), MIDI_CC::Channel_Volume, 13},
  {multiplexers[0].pin(13), MIDI_CC::Channel_Volume, 14},
  {multiplexers[0].pin(14), MIDI_CC::Channel_Volume, 15},
  {multiplexers[0].pin(15), MIDI_CC::Channel_Volume, 16},

  {multiplexers[1].pin(0), MIDI_CC::General_Purpose_Controller_1, 1},
  {multiplexers[1].pin(1), MIDI_CC::General_Purpose_Controller_1, 2},
  {multiplexers[1].pin(2), MIDI_CC::General_Purpose_Controller_1, 3},
  {multiplexers[1].pin(3), MIDI_CC::General_Purpose_Controller_1, 4},
  {multiplexers[1].pin(4), MIDI_CC::General_Purpose_Controller_1, 5},
  {multiplexers[1].pin(5), MIDI_CC::General_Purpose_Controller_1, 6},
  {multiplexers[1].pin(6), MIDI_CC::General_Purpose_Controller_1, 7},
  {multiplexers[1].pin(7), MIDI_CC::General_Purpose_Controller_1, 8},
  {multiplexers[1].pin(8), MIDI_CC::General_Purpose_Controller_1, 9},
  {multiplexers[1].pin(9), MIDI_CC::General_Purpose_Controller_1, 10},
  {multiplexers[1].pin(10), MIDI_CC::General_Purpose_Controller_1, 11},
  {multiplexers[1].pin(11), MIDI_CC::General_Purpose_Controller_1, 12},
  {multiplexers[1].pin(12), MIDI_CC::General_Purpose_Controller_1, 13},
  {multiplexers[1].pin(13), MIDI_CC::General_Purpose_Controller_1, 14},
  {multiplexers[1].pin(14), MIDI_CC::General_Purpose_Controller_1, 15},
  {multiplexers[1].pin(15), MIDI_CC::General_Purpose_Controller_1, 16},

  {multiplexers[2].pin(0), MIDI_CC::General_Purpose_Controller_2, 1},
  {multiplexers[2].pin(1), MIDI_CC::General_Purpose_Controller_2, 2},
  {multiplexers[2].pin(2), MIDI_CC::General_Purpose_Controller_2, 3},
  {multiplexers[2].pin(3), MIDI_CC::General_Purpose_Controller_2, 4},
  ...........

  {multiplexers[3].pin(0), MIDI_CC::General_Purpose_Controller_3, 1},
  {multiplexers[3].pin(1), MIDI_CC::General_Purpose_Controller_3, 2},
  {multiplexers[3].pin(2), MIDI_CC::General_Purpose_Controller_3, 3},
  {multiplexers[3].pin(3), MIDI_CC::General_Purpose_Controller_3, 4},
  .......

  {multiplexers[4].pin(0), MIDI_CC::General_Purpose_Controller_4, 1},
  {multiplexers[4].pin(1), MIDI_CC::General_Purpose_Controller_4, 2},
  {multiplexers[4].pin(2), MIDI_CC::General_Purpose_Controller_4, 3},
  {multiplexers[4].pin(3), MIDI_CC::General_Purpose_Controller_4, 4},
  ........
  {multiplexers[5].pin(0), MIDI_CC::General_Purpose_Controller_1_LSB, 1},
  {multiplexers[5].pin(1), MIDI_CC::General_Purpose_Controller_1_LSB, 2},
  {multiplexers[5].pin(2), MIDI_CC::General_Purpose_Controller_1_LSB, 3},
  {multiplexers[5].pin(3), MIDI_CC::General_Purpose_Controller_1_LSB, 4},
  ........
  {multiplexers[6].pin(0), MIDI_CC::General_Purpose_Controller_2_LSB, 1},
  {multiplexers[6].pin(1), MIDI_CC::General_Purpose_Controller_2_LSB, 2},
  {multiplexers[6].pin(2), MIDI_CC::General_Purpose_Controller_2_LSB, 3},
  {multiplexers[6].pin(3), MIDI_CC::General_Purpose_Controller_2_LSB, 4},
 ............

  {multiplexers[7].pin(0), MIDI_CC::General_Purpose_Controller_3_LSB, 1},
  {multiplexers[7].pin(1), MIDI_CC::General_Purpose_Controller_3_LSB, 2},
  {multiplexers[7].pin(2), MIDI_CC::General_Purpose_Controller_3_LSB, 3},
  {multiplexers[7].pin(3), MIDI_CC::General_Purpose_Controller_3_LSB, 4},
 ............
  {multiplexers[8].pin(0), MIDI_CC::Sound_Controller_1, 1},
  {multiplexers[8].pin(1), MIDI_CC::Sound_Controller_1, 2},
  {multiplexers[8].pin(2), MIDI_CC::Sound_Controller_1, 3},
  {multiplexers[8].pin(3), MIDI_CC::Sound_Controller_1, 4},
 ..........
  {multiplexers[9].pin(0), MIDI_CC::Sound_Controller_2, 1},
  {multiplexers[9].pin(1), MIDI_CC::Sound_Controller_2, 2},
  {multiplexers[9].pin(2), MIDI_CC::Sound_Controller_2, 3},
  {multiplexers[9].pin(3), MIDI_CC::Sound_Controller_2, 4},
  ..........
};

void setup() {}

void loop() {
  // Refresh the MIDI controller (check whether the potentiometer's input has changed since last time, if so, send the new value over MIDI)
  MIDI_Controller.refresh();
}

Is there any code or way to solve this problem?

thank you

Maybe add hysteresis ?
See the introductory tutorials. http://forum.arduino.cc/index.php?topic=526806.0

Have a look at software filtering

Also check you have a stable power supply and reference the A/D to this supply . The pots should not be powered from the Arduino. Keep wires short, look at also using a CR network in the input .
Why so many pots ????

Sounds like you need filtering indeed.

Do these values tremble on all pots at the same time? Then it's a reference and/or supply voltage issue.

Otherwise it's general noise: you'll need caps on the centre pin of each of the pots (to stabilise the signal), and maybe a resistor as well to create an RC circuit to stabilise the signal.

For your power supply: assuming you supply 5V to your Arduino, maybe it's a good idea to add a 3.3V regulator to supply power to the pots and the reference voltage for the ADC. Don't connect anything else to that regulator, just the pots. Also use extra filtering caps on the output of the regulator - so not just a 100 nF ceramic + 10 µF electrolytic, double them up: e.g. 10 and 100 nF ceramic, and 1 and 10 µF electrolytic. This as both types and the different values have different filtering characteristics.

What you can do as well: line the box your pots are in with aluminium foil, and ground that. This way you basically shield all the internal wiring from external electric noise.

hammy:
Why so many pots ????

OP mentions midi so probably this is about music. Quite a normal number for a basic mixing table.

Author of the MIDI Controller library here.

The library includes software filtering (just a SMA filter in the current version, EMA in the reworked version I'm currently working on). I found that this is enough for a small number of low-resistance pots without multiplexers.
However, it's not perfect. In fact, I haven't found a single solution yet. Using the 3.3V reference certainly helps, but still.
Hysterisis is not an option, because you can't get to 0% or 100% if you go slowly (as often is the case with audio). You could use functions to 'snap' to the extremes, but it doesn't feel right either.

If anyone has a better solution, or just an idea, feel free to leave a comment.

Thanks,
Pieter

I would suspect the wiring picking up mains hum, and other noise.

How long are the connections between the potentiometer wipers and the input circuitry?

Using screened cable for the wiring might solve the problem.

Hysterisis is not an option, because you can't get to 0% or 100% if you go slowly (as often is the case with audio). You could use functions to 'snap' to the extremes, but it doesn't feel right either.

I’m not sure I understand this because hysteresis does not need to have a timing element to it. How many discrete values must a potentiometer return ? If it is every value from 0 to 1023 then there is no chance to do anything, but if it is say 100 then that should easily be possible. The link in post #1 has a code example for getting 10 values from a linear potentiometer but that could be scaled up.

The problem occurs when there's so much noise that you would have to use a 'margin' that's wider than the resolution. If your resolution were 8 ADC units, for example, and your margin 10 ADC units, it would be impossible to get from output level 1 to 0, because the actual input would have to be less than -2. This also impacts the responsiveness for small adjustments in general, of course, but it's most noticeable at 0.

If you move the potentiometer faster, e.g. if you go from level 2 to 0 in one loop cycle, you can reach zero. That's what I meant when I said that it's only a problem 'if you go slowly'.

The solution would be to lower the resolution, and that's probably what I'll end up doing.
Combined with a LP-filter, 7-bit resolution may be possible, but I'll have to look into it.

Thanks for your comment, I was probably looking at it in the wrong kind of way.

Hi,

What value are your potentiometers?
What is the power supply for your potentiometers.
Have you worked out the load that they represent and id the supply can support them
Have you got 0.1uF capacitors between each wiper and gnd?

How have you physically got your potentiometers wired, do you have bypassing capacitors on the supply at regular intervals?

Tom... :slight_smile:

I haven't seen anyone address the ADC or ask about using the first analog read after switching pins, is the settle time in a library the sketch uses?

You can cut dither by saving a read and not changing that working value until a read comes up that is +/- 3 of that value. The work value does not change until then, it does not 'travel'. Sure, you can't get to any value within the dead zone but you can move the dead zone and get there then.

The first analog read after switching pins is discarded:

Good to hear that the first read is dumped.

ADC will still dither when near a conversion 'edge'. That's why oversampling works.

GoForSmoke:
ADC will still dither when near a conversion 'edge'. That's why oversampling works.

The (running) average of the last 8 samples is used, in an attempt to prevent that .

I wonder how close those wires for all those pots run to each other?

Even with a single 10kΩ potentiometer on the 5V line with only 10 cm of jumper wires, there is a considerable amount of noise.

When I was looking at Terry King's RS485 interface circuitry I saw a good bit of what I'd call pulldown flow that Terry did identify as there for stability. It's like ripples being pulled away on a flowing stream.

Otherwise try shielding the wires. Even grounded foil may make a difference. Paper clips will hold and contact foil, it won't solder.

GoForSmoke:
When I was looking at Terry King's RS485 interface circuitry

Do you mean this interface? Where are the pulldowns you're talking about?

Here:
http://arduino-info.wikispaces.com/RS485-Modules

On the right side there is VCC through 20KR to one data line then through 120R to the next data line then through 20KR to ground.

Serial default/zero state is HIGH, one state is LOW, that's a pullup and pulldown, why I write flow, it's noise resistant.

I produced a 7 bit resolution version of my standard hysteresis template in case it helps in solving the problem here. It produces 128 discrete values (0..127) from analog values in the range 0 to 1023. I can test it with only a rough old preset type potentiometer, but it seems to work nicely with a margin of +/- 2.

This version does not have a table of range endpoints because the intervals between endpoints are all equal. A calculation is used instead. This would make it more practical to define it as a class and have multiple instances.

/*

  Hysteresis

  This code example shows obtaining values 0-127 from a potentiometer wired
  as a voltage divider. These values remain stable even if the potentiometer
  is set on a border point between two values.

  
  6v6gt 13.apr.2018

  ver 0.01 03.02.2018 Original verson with table to represent range end points
  ver 0.02 13.04.2018 Original verson with calculation to determine range end points.

*/




uint8_t getOutputLevel( uint16_t inputLevel ) {
 //
 //  convert an input value into an output value with hysteresis to
 //  avoid instability at cutover points ( eliminate thrashing/flicker etc.)
 //
 //  6v6gt 13.apr.2018 ver 0.02

 // adjust these 4 constants to suit your application

 // ========================================
 // margin sets the 'stickyness' of the hysteresis or the relucatance to leave the current state.
 // It is measured in units of the the input level. As a guide it is a few percent of the
 // difference between two end points. Don't make the margin too wide or ranges may overlap.
 const uint16_t margin = 2 ;   //  +/- 2

 // set the number of output levels. These are numbered starting from 0.
 /*
  * bits
  * resolution      levels
  * 1                    2
  * 2                    4
  * 3                    8 
  * 4                    16
  * 5                    32
  * 6                    64  
  * 7                    128
  * 8                    256    Too high for 10 bit adc
  * 9                    512    Too high for 10 bit adc
  */
 const uint16_t numberOfLevelsOutput = 128 ;  // 128 => 0..127  ( power of 2 ideally  )

 // number of discrete input values.
 // 8 bit ADC = 256, 9 bit ADC = 512, 10 bit ADC = 1024, 11 bit ADC = 2048, 12 bit ADC = 4096
 const uint16_t numberOfInputValues = 1024  ;  //  0..1023 (power of 2 ideally )

 // initial output level (usually zero)
 const  uint16_t initialOutputLevel = 0 ;
 // ========================================

 // the current output level is retained for the next calculation.
 // Note: initial value of a static variable is set at compile time.
 static uint16_t currentOutputLevel = initialOutputLevel ;


 // get lower and upper bounds for currentOutputLevel
 uint16_t lb =   (float) ( (float) numberOfInputValues / numberOfLevelsOutput ) * currentOutputLevel  ;
 if ( currentOutputLevel > 0 ) lb -= margin  ;   // subtract margin

 uint16_t ub =   ( (  (float) ( (float) numberOfInputValues / numberOfLevelsOutput ) * ( currentOutputLevel + 1 )  )  - 1 )  ;
 if ( currentOutputLevel < numberOfLevelsOutput ) ub +=  margin  ;  // add margin
   // now test if input is outside the outer margins for current output value
   // If so, calculate new output level.
 if ( inputLevel < lb || inputLevel > ub ) {
   // determine new output level
   currentOutputLevel =   (  ( (float) inputLevel * (float) numberOfLevelsOutput ) /  numberOfInputValues ) ;
 }
 return currentOutputLevel ;
}




void setup() {
 Serial.begin( 9600 ) ;
}

void loop() {

 Serial.print(  getOutputLevel( analogRead(A0) ) ) ;
 Serial.print("  " ) ;
 Serial.println( analogRead(A0) ) ;

 delay ( 500 ) ;
}

6v6gt:
I produced a 7 bit resolution version of my standard hysteresis template in case it helps in solving the problem here.

If you'd only said that you were going to do that earlier, I just wrote a very similar sketch last week :slight_smile:

Anyway, thanks a lot for the responses!
I've got some other work right now, but I'll look into it further when I find the time.