Analog Input with rotary switch

Hello,

I'm using a 10 slot rotary switch and breakout board from SparkFun. https://learn.sparkfun.com/tutorials/rotary-switch-potentiometer-hookup-guide

I've wired it up and tested resistance. All wiring and soldering working well.

I have a teensy 4.0. I plug the CCW to ground on the teensy, W to port 17 (aka A3), and CW to 5v. I simplified the code from Sparkfun (see below) to simply report the slot to the serial terminal. The problem is, I'm getting very inconsistent results:
Position 1: val = 0
Position 2: val = 1
Position 3: val = 3
Position 4: val = 4
Position 5: val = 6
Position 6: val = 8
Position 7: val = 9
Position 8: val = 9
Position 9: val = 9
Position 10: val = 9


But, if I plug into an Arduino Uno, using the same CCW to ground, W to A3, and CW to 5v, it works perfectly.
Position 1: val = 0
Position 2: val = 1
Position 3: val = 2
Position 4: val = 3
Position 5: val = 4
Position 6: val = 5
Position 7: val = 6
Position 8: val = 7
Position 9: val = 8
Position 10: val = 9

What is the difference between analog input ports on the Teensy 4.0 vs Arduino Uno?

Thanks.

Code:
/* Test rotary switch
// modified from https://github.com/sparkfun/Rotary_Switch_Potentiometer

Demonstrates using the Rotary Switch Potentiometer breakout board 
with a microcontroller, to build a 10 position selector switch.

The Rotary Switch Potentiometer is a breakout board that adds 9 resistors to a
10 position rotary switch, to make a custom-taper, stepped potentiometer.  This
example uses 9 10KOhm resistors, and connects the rotary switch potentiometer
to an analog input. 

The Rotary Switch Potentiometer board was populated with 10K resistors in 
every position.  It was connected to the RedBoard as follows:

RedBoard pin : Rotary Switch Potentiometer Pin
----------------------------------------------
GND          : CCW
A3 aka 17    : W
5V           : CW

*/

#define BAUDRATE 115200
#define ROTARY_PIN 3 //A3, analog 3, aka pin 17 on Teensy 4.0

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("Begin Test Rotary Switch");
}

void loop() {
  uint16_t input;
  uint16_t val;

  // read the ADC
  input = analogRead(ROTARY_PIN);

  // Translate ADC value from 0-1023 to 0-9.
  // This implements the proportion
  // input/1023 = val/9.
  // One "step" of the pot is about 113 ADC counts.
  // We're adding 65 (1/2 of 113) to the input value, so that the 
  // input is in the middle of the window, rather than right at the edge, so values 
  // are stable and solid.
  val = (input+56)*9/1023;

  Serial.println(val);
}
 
Do I need to use an ADC library? https://github.com/pedvide/ADC

I modified the code as follows, but no change in behavior.

Code:
/* Test rotary switch
// modified from https://github.com/sparkfun/Rotary_Switch_Potentiometer

Demonstrates using the Rotary Switch Potentiometer breakout board 
with a microcontroller, to build a 10 position selector switch.

The Rotary Switch Potentiometer is a breakout board that adds 9 resistors to a
10 position rotary switch, to make a custom-taper, stepped potentiometer.  This
example uses 9 10KOhm resistors, and connects the rotary switch potentiometer
to an analog input. 

The Rotary Switch Potentiometer board was populated with 10K resistors in 
every position.  It was connected to the RedBoard as follows:

RedBoard pin : Rotary Switch Potentiometer Pin
----------------------------------------------
GND          : CCW
A3 aka 17    : W
5V           : CW

*/
#include <ADC.h>

#define BAUDRATE 115200
#define ROTARY_PIN A3 //A3, analog 3, aka pin 17 on Teensy 4.0

ADC *adc = new ADC(); // adc object

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("Begin Test Rotary Switch");
}

void loop() {
  uint16_t input;
  uint16_t val;

  // read the ADC
  //input = analogRead(ROTARY_PIN);
  input = adc->analogRead(ROTARY_PIN);

  // Translate ADC value from 0-1023 to 0-9.
  // This implements the proportion
  // input/1023 = val/9.
  // One "step" of the pot is about 113 ADC counts.
  // We're adding 65 (1/2 of 113) to the input value, so that the 
  // input is in the middle of the window, rather than right at the edge, so values 
  // are stable and solid.
  val = (input+56)*9/1023;

  Serial.println(val);
}
 
Hi

I have not used the ADC on the teensy, but Teensy is a 3.3V device and Uno a 5V device. What do you get if you attach the CW to 3.3V and not 5V ?
At 5V I think you will get 3.3V between position 6 and positions 7 so ADC at full scale then.
 
Also be carefull as teensy 4 is not 5V tolerant. From the spec page

"Analog Range
The analog input range is fixed at 0 to 3.3V. On Teensy 4.0, the analogReference() function has no effect. The analog pins are not 5V tolerant. Do not drive any analog pin higher than 3.3 volts."
 
That was written for Teensy 2 and 2++ which were 5v MCU's.
The web page should have a warning, that 3.3v should be used for Teensy 1.36 and 4.x.
@Paul could you have a look at this. it's NOT the first time that this page has been referenced with regards to 4.x.
 
Duh. The teensy itself has 3v output. Using that I get:

Position 1: val = 0
Position 2: val = 1
Position 3: val = 2
Position 4: val = 3
Position 5: val = 3
Position 6: val = 4
Position 7: val = 6
Position 8: val = 7
Position 9: val = 8
Position 10: val = 9

Not sure what's happening in position 5, 6, and 7 with number skipping, but that gives me 9 usable slots. I can work with that.
 
Not sure what's happening in position 5, 6, and 7 with number skipping, but that gives me 9 usable slots. I can work with that.

It would be interesting to look at the actual values you are getting from readAnalog() by replacing the Serial.println(val) statement with:

Code:
  Serial.printf( "%1hd  %1hd\n", input, val );
 
No problem. here is a sample of the serial monitor. I ticked the stops at fairly regular intervals.

Code:
0  0
0  0
1  0
0  0
0  0
106  1
106  1
106  1
106  1
106  1
106  1
106  1
106  1
106  1
106  1
201  2
202  2
202  2
202  2
202  2
202  2
202  2
202  2
203  2
203  2
299  3
299  3
300  3
299  3
298  3
299  3
299  3
299  3
299  3
299  3
299  3
299  3
391  3
392  3
391  3
392  3
391  3
392  3
391  3
391  3
392  3
391  3
392  3
490  4
491  4
490  4
490  4
490  4
490  4
490  4
490  4
490  4
490  4
490  4
490  4
726  6
725  6
725  6
725  6
726  6
725  6
726  6
725  6
726  6
726  6
725  6
725  6
726  6
819  7
820  7
820  7
820  7
819  7
820  7
820  7
821  7
820  7
820  7
820  7
821  7
820  7
917  8
917  8
916  8
917  8
917  8
917  8
917  8
917  8
917  8
916  8
916  8
917  8
917  8
917  8
917  8
1022  9
1023  9
1022  9
1023  9
1022  9
1022  9
1023  9
1022  9
1023  9
1023  9
1022  9
1023  9
1022  9
1023  9
1023  9
1023  9
1022  9
1022  9
1023  9
1023  9
 
Here is a summary of your values. The first 5 values (109,203,299,392,490) are much closer to steps of 1/10 of the 1023 max than 1/9. That's why you don't get 1,2,3,4,5. After 490, there is big jump to 726, and then on the last 4 steps (726,820,917,1023), you are getting close to the expected values, so you do get 6,7,8,9. There seems to be something amiss with the resistance values. Maybe check your soldering?

Code:
106  1
203  2
299  3
392  3
490  4
726  6
820  7
917  8
1023  9
 
The soldering looks ok. But I had another switch kit sitting around, so I soldered it fresh with new resistors. All good soldering.

I still see a skip in resistance values in the new kit. I modified the code to accomodate the difference with a massive if/else statement. See here:

Code:
/* Test rotary switch
// modified from https://github.com/sparkfun/Rotary_Switch_Potentiometer

Demonstrates using the Rotary Switch Potentiometer breakout board 
with a microcontroller, to build a 10 position selector switch.

The Rotary Switch Potentiometer is a breakout board that adds 9 resistors to a
10 position rotary switch, to make a custom-taper, stepped potentiometer.  This
example uses 9 10KOhm resistors, and connects the rotary switch potentiometer
to an analog input. 

The Rotary Switch Potentiometer board was populated with 10K resistors in 
every position.  It was connected to the RedBoard as follows:

RedBoard pin : Rotary Switch Potentiometer Pin
----------------------------------------------
GND          : CCW
A3 aka 17    : W
3.3V         : CW    // NOTE USE 3.3v NOT 5v !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

*/

#define BAUDRATE 115200
#define ROTARY_PIN A3 //A3, analog 3, aka pin 17 on Teensy 4.0

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("Begin Test Rotary Switch");
}

void loop() {
  uint16_t input;
  uint16_t val = 0;

  // read the ADC
  input = analogRead(ROTARY_PIN);

  // assign val based on input
  if ( (input >= 0) && (input <= 75) ){
    val = 0;
  } else if ( (input >= 76) && (input <= 151) ) {
    val = 1;
  } else if ( (input >= 152) && (input <= 252) ) {
    val = 2;
  } else if ( (input >= 253) && (input <= 328) ) {
    val = 3;
  } else if ( (input >= 329) && (input <= 429) ) {
    val = 4;
  } else if ( (input >= 430) && (input <= 530) ) {
    val = 5;
  } else if ( (input >= 531) && (input <= 781) ) {
    val = 6;
  } else if ( (input >= 782) && (input <= 857) ) {
    val = 7;
  } else if ( (input >= 858) && (input <= 933) ) {
    val = 8;
  } else if ( (input >= 934) && (input <= 1034) ) {
    val = 9;
  } 

  //Serial.println(val);
  Serial.printf( "%1hd  %1hd\n", input, val );

  delay(250);
}

Now it works when I turn the knob up, when going down it gets wierd in 4,5, and 6. I wonder if the knobs themselves are shorting and poor quality?

Code:
Input	Val	Difference from previous
0	0	0
107	1	107
203	2	96
297	3	94
390	4	93
487	5	97
725	6	238
820	7	95
917	8	97
1023	9	106
916	8	-107
819	7	-97
725	6	-94
630	6	-95
530	5	-100
296	3	-234
204	2	-92
106	1	-98
1	0	-105
 
This is strange. Note that the big jump does not occur at the same switch position on the way down as on the way up. Instead it occurs on the 7th step in both directions. Seems like the hardware doesn't work in the way I would assume. Probably a good idea to measure the resistance in each position.
 
This is strange. Note that the big jump does not occur at the same switch position on the way down as on the way up. Instead it occurs on the 7th step in both directions. Seems like the hardware doesn't work in the way I would assume. Probably a good idea to measure the resistance in each position.

The pin probably has bus-hold enabled.

See this thread:
https://forum.pjrc.com/threads/69671-Teensy-4-0-4-1-web-pages-need-a-warning-about-INPUT_DISABLE-on-Analog-Inputs?highlight=bus-keeper
 
That's it. Whooo hoo. Thanks.

I added this to startup():
pinMode(17, INPUT_DISABLE);

And I changed back to the math calculation instead of big if/else statement. And changed the offset from 56 to 48 to get the rounding right.

Final code here. It works perfectly. Thank you all.

Code:
/* Test rotary switch
// modified from https://github.com/sparkfun/Rotary_Switch_Potentiometer

Demonstrates using the Rotary Switch Potentiometer breakout board 
with a microcontroller, to build a 10 position selector switch.

The Rotary Switch Potentiometer is a breakout board that adds 9 resistors to a
10 position rotary switch, to make a custom-taper, stepped potentiometer.  This
example uses 9 10KOhm resistors, and connects the rotary switch potentiometer
to an analog input. 

The Rotary Switch Potentiometer board was populated with 10K resistors in 
every position.  It was connected to the RedBoard as follows:

RedBoard pin : Rotary Switch Potentiometer Pin
----------------------------------------------
GND          : CCW
A3 aka 17    : W
3.3V         : CW    // NOTE USE 3.3v NOT 5v !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

*/

#define BAUDRATE 115200
#define ROTARY_PIN A3 //A3, analog 3, aka pin 17 on Teensy 4.0
#define ROTARY_DIGITAL_PIN 17 // the digital pin to disable, so only analog works on that pin

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("Begin Test Rotary Switch");
  pinMode(ROTARY_DIGITAL_PIN, INPUT_DISABLE); // disable digital input, but keeps analog
}

void loop() {
  uint16_t input;
  uint16_t val;

  // read the analog input
  input = analogRead(ROTARY_PIN);

  // Translate ADC value from 0-1023 to 0-9.
  // This implements the proportion
  // input/1023 = val/9.
  // add 48 so we don't land on edges of rounding
  val = (input+48)*9/1023;

  Serial.printf( "%1hd  %1hd\n", input, val );

  delay(250);
}

I owe you all a whiskey.
 
Back
Top