I have a potentiometer connected to an ADC input of an Arduino Leonardo. The ADC resolution is 10-bit (0..1024), while I need just 7-bit (0..127).

I use a simple filter to reduce the noise and then a `map` to cut the unused bits:

``````#define ADC_CH                18

uint16_t value;

``````

I show `value` on an LCD. It's very stable, but it may happen that if the adc readings are in the nearby of two values, there is nothing that could prevent a change in the final value, even if the noise is of just few LSBs.

Is there a simple way to implement an hysteresis for each low-res value?

In this way the change between N and N+1 happens on a different ADC reading than between N and N-1, improving the noise rejection without increasing the filter delay (that would only increase the change interval).

When you reduce the resolution from 10 bits to 7 bits, every possible output corresponds to an interval of inputs. If you add some hysteresis, then those intervals should overlap. Below is a representation of the input intervals corresponding to outputs 0, 1,… 6, for an hysteresis width of 4:

``````input: 0    5   10   15   20   25   30   35   40   45   50   55   60
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴
├─────0────┤
├───────1──────┤
├───────2──────┤
├───────3──────┤
├───────4──────┤
├───────5──────┤
├───────6──────┤
``````

To implement this in code, you have to remember the last output, and change it only if the input lies outside the interval assigned to this output. Here is an example implementation:

``````const int hysteresis = 4;  // tune to taste

/* Remove 3 bits of resolution while adding some hysteresis. */
{
static int value;  // last output
if (adc < (value<<3) - hysteresis) {
value = (adc + hysteresis) >> 3;
} else if (adc >= ((value+1)<<3) + hysteresis) {
value = (adc - hysteresis) >> 3;
}
return value;
}
``````

Note that a `static` local variable keeps its value between successive calls to the function.

• I'm not supposed to do this but anyway: excellent answer! Nice graphic, well explained. :) Commented May 9, 2023 at 6:04
• Your code works perfectly and it fits exactly the example in my question. Anyway, is there a more general approach? For example, what if I want to `map` the ADC input to [min, max] (always < 1024) ?
– Mark
Commented May 12, 2023 at 18:13
• @Mark: Then you would replace the shifts (which are basically optimized multiplications and divisions) by arbitrary `map()`s. You may then want to do some tests in order to see how the rounding errors introduced by the map interfere with the hysteresis. Commented May 12, 2023 at 18:42