In recent weeks I tried to solve an old problem, a problem that haunts me for some time. I want to use a regular, inexpensive, common, ordinary potentiometer with an ADC. Also an inexpensive, common, ordinary ADC that we can find in almost all microcontrollers these days. And doesn’t matter if we are talking about 8, 16 or 32 bit MCUs…

And I do not want to go crazy. If you tried something like that you know what I mean…

Because I want **stable** ADC readings with potentiometer. Stable… ie when I do not move the potentiometer knob, the value must to be steady, without the slightest oscillation, (even +/-1). Even if this task seem to be very simple, when we get down to facts, we see that (almost)nothing fits with the theory.

There is no point to review in detail all attempts to solve once and for all this issue. Instead, I will try to summarize my whole experience(and experiments) on this field.

I started with the “classical” schematic for reading a potentiometer.

### Hardware measures

**Good filtration of power supply.**I’m not going to put a schematic here, because it depends on actual power source. The idea is that should be well filtered and stabilized.**Good filtration of AVcc supply.**All microcontrollers that have ADC module also have a pin called AVcc or AVcc (or AVdd ?). It is the power for the ADC (Analog to Digital Converter) and is and it is placed separately to be filtered separately. C2 can be main decoupling capacitor for the MCU, so for AVcc can be used only C1 and L.**Capacitor on VREF pin.**A capacitor put on VREF (Voltage reference) it is also a technique to reduce ADC noise.**Potentiometer capacitor.**A capacitor with value 1..10uF will stabilize readings also.

### Software measures

I made an extensive research about “software ADC filtering”, and I tried various techniques, algorithms and ideas. I must say that I have not found even one solution that works as expected. Finally I decided to try a combination of two algorithms. It’s obvious that at first I tried them separately, but I noticed that work very well together, especially for this goal (stable ADC readings with potentiometers).

**“Olympic average“**– I met this term in various discussions and I decided to document and try it myself.

12345678910111213141516171819unsigned int olympicAverage(unsigned int analogPin){unsigned int max_value = 0;unsigned int min_value =1024; // for 12 bit ADC min_val=4096;// min_value is initialised with maximum value of the adc +1// in that way is replaced at first iteration with real readingunsigned int sum_value = 0;unsigned int sensor_value;for (int i=0;i<10; i++) {sensor_value=analogRead(analogPin);sum_value=sum_value+sensor_value;if (sensor_value > max_value) max_value = sensor_value;if (sensor_value < min_value) min_value = sensor_value;}sum_value = sum_value - max_value;sum_value = sum_value - min_value;return (sum_value >> 3); // eq sum_value/8}**Exponential Moving Average**– this kind of average have the characteristic to “lock” on value. This formula is taken from wikipedia and we will adapt to our goal. We will “translate” this formula to C code as follows (I chose alpha = 0.1 trough some experiments):

12345float alpha_ema = 0.1; //EMA alpha is 0.1 = 1/10int s_ema = 0; //actual value of the Exponential Moving Averageunsigned int sensor1_Value;s_ema = (alpha_ema*sensor1_Value) + ((1-alpha_ema)*s_ema);

1234int s_ema = 0; //actual value of the Exponential Moving Averageunsigned int sensor1_Value;s_ema = (sensor1_Value/10) + ((s_ema*9)/10); //calculate the Exponential Moving Average**Putting all together**

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960unsigned int olympicAverage(unsigned int analogPin);// --------- Global Variablesfloat alpha_ema = 0.1; //EMA alpha is 0.1 = 1/10int s_ema = 0; //actual value of the Exponential Moving Averageint old_value=0;int new_value=0;#define Pot1_analogPin 0 // analog pin 0void setup() {Serial.begin(38400);s_ema = olympicAverage(Pot1_analogPin);}void loop() {unsigned int sensor1_Value = olympicAverage(Pot1_analogPin); //read analog pin//calculate the Exponential Moving Average//s_ema = (alpha_ema*sensor1_Value) + ((1-alpha_ema)*s_ema); //floats_ema = (sensor1_Value/10) + ((s_ema*9)/10); //integer// EMA value is maped on 0-127 domain from MIDI standard// attention at value 1011 - this is maximum s_ema can reach//with integers calculationnew_value= map (s_ema,0,1011,0,127);if (new_value != old_value){old_value=new_value;Serial.println(old_value);}}/* Olympic Averagehttps://en.wikipedia.org/wiki/Truncated_mean */unsigned int olympicAverage(unsigned int analogPin){unsigned int max_value = 0;unsigned int min_value =1024; // for 12 bit ADC min_val=4096;// min_value is initialised with maximum value of the adc +1// in that way is replaced at first iteration with real readingunsigned int sum_value = 0;unsigned int sensor_value;for (int i=0;i<10; i++){sensor_value=analogRead(analogPin);sum_value=sum_value+sensor_value;if (sensor_value > max_value) max_value = sensor_value;if (sensor_value < min_value) min_value = sensor_value;}sum_value = sum_value - max_value;sum_value = sum_value - min_value;return (sum_value >> 3); // eq sum_value/8}

### Conclusions:

The method shows a clear reduction in resolution, but we should not worry at all. No one has such mechanical accuracy so can’t exploit more than 100-150 virtual subdivisions of this kind of analog potentiometer.

Even if the code presented here is for Arduino, it is obvious that it can be used with a C or C++ compiler for a different microcontroller. I started experiments with a STM32F103 (blue pill) and after some progress I switch to AVR because I had this development board made/designed by me, so I was sure of filtering Vdd, AVdd and ARef:

### Some practical and economic considerations:

These experiments were started with the thought of making a MIDI controller. Thus appeared the need to use many potentiometers like 16 or 32 or even more. And so we need to use not-so-expensive potentiometer. (In fact I use the most cheaper I can found 🙂 ).

If more precision is neded we can be use a multi-turn potentiometer. I have not tried this. Maybe we can go up with precision and keep more bits to work with. I do not think it would be practical for a MIDI controller, but for other applications (with fewer potentiometers) it can be something interesting.

Or maybe this extended accuracy can be achieved more easily with a rotary encoder. For a MIDI controller I got very good results with rotary encoders. But this is another story … that you can even find in this site …