I PM'd 6v6gt on the matter of using this idea to make a 40 step switch.
My slide faders were delivered, according to UPS! Sadly they weren't delivered to me, so somewhere a nice shipment of parts is probably confusing someone.
But. I did modify the code for 40 positions and test it with a rotary potentiometer - it works very well. I have no doubt that I will be able to get a stable equivalent to the 40 position slide switch I seek to simulate.
I timed the function and analog read with what seemed would be worst case values, virtually twisting the knob from 0 to full - I got 90 uS average time to read and evaluate.
Then, as much as I love tables, I thought I could replace the table with a calculation. I used an function with one floating point multiply operation as a replacement to the table, that is all endPointTable[ ] became endPointTable( ), shoulda called it endPointFunction( ) I suppose.
I timed this and got 414 uS average time. Not too bad, and I prolly could call it a day - my project's main loop will be 100 Hz / 10 milliseconds and not much has to be done, so I have the time.
I cut some of the calls in the "search" loop and the time dropped to 240 uS. I did not try to eliminate all the calls to my function as it looked a bit tricky with the integer / floating math - perhaps a mixed point thing would mean we wouldn't need the table (or function) in the search loop at all.
Instead I replaced what is essentially a linear search with a binary search. That made the time is 120 uS. It eliminates the table at the expense of what is probably a bit more code, I did not measure that.
during dinner (!) I had a brain wave and realized the mixed point math could be fairly straight ahead. Here's the modified sketch for a 40-step analog input using no floating point and no table, seems to work. I did lose the ability to have different sizes for the regions that the table allows, which might be useful at the ends of travel. Each of my steps is 1/40th of the total. I went back to the original linear search as it is necessary for how it tracks along the segments.
It makes using a different number of steps a bit easier (should # define NUMBER_OF_STEPS or pass it as a variable) and the hysteresis margin is independent of that number. By my measurements it is about 65 uS, a bit faster than the original after it was changed to 40 steps.
This math will break when we ask for more than 64 steps.
Sorry it isn't too pretty. I'm quite aware that I may have overlooked something. When I get the slide faders I'll see if they work well and report.
I am still kicking around ideas for handling at least 8 and maybe as many as 11 "switches", the big part of that problem is needing 8-11 analog to digital conversion paths.
I think hysteresis is an important fundamental idea that "everyone" should know about. Thanks 6v6gt for jump-starting this!
/*
Hysteresis
This code example shows obtaining values 0-9 from a potentiometer wired
as a voltage divider to analog pin A0. These values remain stable even if the potentiometer
is set on a border point between two values.
The same principle could be used to set the brightness of a display
dependent on the ambient light, but free from flicker or switching a heater
on based on a thermostat etc.
6v6gt 03.feb.2018
modifications alto777 for 40-step slide fader "switch", no table.
*/
# define test 0 /* 1 = test potentiometer, 0 = time the read/adjust process */
uint16_t getOutputLevel( uint16_t inputLevel ) {
const uint16_t margin = 400 ; // +/- 10
const uint16_t numberOfLevelsOutput = 40 ; // 0..39
const uint16_t initialOutputLevel = 0 ;
static uint16_t currentOutputLevel = initialOutputLevel ;
uint16_t lb = currentOutputLevel * 1023;
uint16_t ub = lb;
if ( currentOutputLevel > 0 ) lb -= margin ; // subtract margin
if ( currentOutputLevel < numberOfLevelsOutput ) ub += margin ; // add margin
// now test if input is between the outer margins for current output value
if ( inputLevel < lb || inputLevel > ub ) {
uint16_t i, b1;
b1 = 1023;
for ( i = 0 ; i < numberOfLevelsOutput ; i++ ) {
if (inputLevel <= b1) break ;
b1 += 1023;
}
currentOutputLevel = i ;
}
return currentOutputLevel ;
}
void setup() {
unsigned char looper;
long microTimer;
Serial.begin( 9600 );
if (!test) { /* read but ignore A0, use worst case values */
looper = 20;
while (--looper) {
microTimer = micros();
analogRead(A0);
getOutputLevel(0);
analogRead(A0);
getOutputLevel(40 * 1023);
Serial.print((micros() - microTimer) / 2);
Serial.println(" microseconds per ");
}
}
}
void loop0() {}
void loop() {
if (test) {
Serial.print( analogRead(A0) ) ;
Serial.print(" " ) ;
Serial.println( getOutputLevel( analogRead(A0) * 40 ) ) ;
delay ( 50 ) ;
}
}
alto777