Automatically identify if pot or dual switch

I have an ESP32 and a 3 pin connector which is either connected to two switches or to a 3 pin potentiometer. Pin1 is connected to GND and Pin2 is connected to GPIO25.
Pin3 has to be connected dynamically (maybe using transistor, multiplexer or relay) to either GPIO27 (in case of dual switch) or to 3.3V (in case of potentiometer).

What would be the most elegant and simple way of automatically detecting which of these two types is connected and then automatically switching pin3 appropriately?

I'd like to be able to detect it without having to set or change the pot value and without having to press any switches.

The max potentiometer value is not known. It is likely to a 10k, 20k or 25k, but it may also be 50k, 100k or 250k.

To others your description might be clear but it's not to me. Can you please draw what you suggest; all components and all power connections (Vcc/GND).

Sure, I've tried drawing it in Fritzing, does this help as an explanation?


There of course would also have to be some sort of multiplexer, transistor, relay or whatever on order to change the function of pin 3 of the connector. Maybe like this:

  1. For the right hand switch, put a resistor over it.
  2. Connect the input of the board with resistor to Vcc.
  3. You need to use an analogue input and analogRead().

The input will read Vcc if the switch is not connected.
The input will read a medium value if the switch is connected and open (e.g. 10k/10k will create approx 1.5V).
The input will read 0V if the switch is closed.

I don't understand. What do you mean by "put a resistor over it"?
The ESP32 can programmatically set pullup/pulldown resistors and change the function of a GPIO pin from ditigal to analog.

  • Start with pin 3 connected to GPIO27.
  • Using pinMode, turn on INPUT_PULLUP.
  • Do an analogRead on GPIO27.
  • If the result of the analogue read is it's maximum you have a switch (or nothing) connected.
  • If the result is close to zero you have got a button which happens to be pressed
  • If the result is some intermediate value, then you have the potentiometer and pullup resistor forming a potential divider.

wouldn't analogRead() reset the pinMode ?

I didn't think it did (but I could be wrong).

I'll do a test to find out, however I don't have an ESP32 available, so the test would be done on an Uno.

My understanding is that the device can be configured in 2 ways

is that your assumption ?

Test carried out.

Using this code on a Uno R3:

int testPin = A0;
int result = 0;

void setup() {
  pinMode(testPin, INPUT_PULLUP);
  Serial.begin(115200);
} 

void loop() {
  result = analogRead(testPin);
  Serial.println(result);
  delay(1000);
}

I get a count of 1016 or 1017 when the analogue pin is open circuit. (Not the maximum 1023.)
The count drops to 124 when a 10kΩ resistor is connected between the pin and GND.

So the method suggested might work.

Like this

Sterretje,
What if the potentiometer chosen is 10kΩ ?

You wouldn't be able to tell whether a switch with 10kΩ resistor is present, or a 10kΩ potentiometer.

You would have to chose the resistor / potentiometer values so that issue did not occur.

Yes.

@JohnLincoln So did you mean like this?

// Pin definitions
#define RELAY_SIGNAL_PIN 26
#define GPIO_TRS_PIN 27
#define TRS_PIN_2 25

void connect_trs_pin3_to_gpio27() {
  digitalWrite(RELAY_SIGNAL_PIN, LOW); // Connect TRS_PIN_3 to GPIO_TRS_PIN (GPIO 27)
}

void connect_trs_pin3_to_vcc() {
  digitalWrite(RELAY_SIGNAL_PIN, HIGH); // Connect TRS_PIN_3 to ESP_3V3
}

void check_buttons() {
  int button1_state = digitalRead(TRS_PIN_2);
  int button2_state = digitalRead(GPIO_TRS_PIN);

  if (button1_state == LOW && button2_state == LOW) {
    Serial.println("Two buttons detected and pressed.");
  } else if (button1_state == LOW) {
    Serial.println("Button 1 detected and pressed.");
  } else if (button2_state == LOW) {
    Serial.println("Button 2 detected and pressed.");
  } else {
    Serial.println("Buttons detected but not pressed.");
  }
}

void setup() {
  Serial.begin(115200);

  // Setup relay control pin
  pinMode(RELAY_SIGNAL_PIN, OUTPUT);
  connect_trs_pin3_to_gpio27();

  // Setup GPIO pins for detection
  pinMode(GPIO_TRS_PIN, INPUT_PULLUP);
  pinMode(TRS_PIN_2, INPUT_PULLUP);
}

void loop() {
  // Perform an analogRead on GPIO_TRS_PIN (connected to TRS_PIN_3)
  int analog_value = analogRead(GPIO_TRS_PIN);

  // Check the analogRead value
  if (analog_value >= 4095) {
    Serial.println("No potentiometer or buttons detected.");
  } else if (analog_value < 50) {
    check_buttons();
  } else {
    Serial.print("Potentiometer detected with value: ");
    Serial.println(analog_value);
  }

  // Wait before next read
  delay(1000);
}

HI, @felic
What is your project?
Why do you need to have switch or pot inputs?

Thanks Tom.. :smiley: :+1: :coffee: :australia:

The potentiometer is on an other input (based on the first drawing in the opening post); the suggested schematic only applies to the switch that is not replaced by the potentiometer input (the right hand side switch in the original drawing).

Edit
@JohnLincoln
I think that I now see what you mean. So that will not be as simple as I thought.

Just a note — I just did a test on my ESP32 (NodeMCU) and the pullup on pin 25 does not work.

Also it seems that analogRead attaches the pin to ADC channel, which remaps it off the pullup circuit so if you want to perform a digitalRead() after the analogRead() you need to re-issue the pinMode(testPin, INPUT_PULLUP);

It's a live music thing. I have a box containing an ESP32 and the box has a TRS-connector (aka stereo jack) which should allow for connecting a dual footswitch (equivalent to two buttons) or an expression pedal (equivalent to a 3 pin potentiometer).

Example dual footswitch:


Example expression pedal:

Depending on what type of effect you want to control, you need either the one or the other...

@J-M-L I would be totally okay with using any other GPIO pin. I just randomly picked some for visualization.

Let's use gpio 12, 13 and 14 instead. Those support pullup, pulldown, analog and of course digital.

Doesn't the checking need to be done in setup(), so that the rest of your code can do whatever it needs to in loop()?

I think that sterretje's idea would be better, as long as you choose the resistor/potentiometer values so that there is no ambiguity.

My suggested method does not differentiate between buttons connected, and nothing connected.

J-M-L has confirmed that the INPUT_PULLUP doesn't work, so you need to add an external pullup resistor as in sterretjes suggestion.

could you envision this wiring ?

image

that is you don't hardwire to GND or 3.3V but you actually use GPIO pins.

This would let you test various connectivity paths before setting GPIO13 to LOW / OUTPUT and GPIO14 To either an INPUT_PULLUP or OUTPUT HIGH.

1 Like

But then you would have to connect the buttons/potentiometer before powering on the ESP. I'd prefer to be able to do the detection at any point in time.

@J-M-L I don't see how this would work without GND, but if it was possible to read the states of the buttons / the state of the pot this way, I'd be okay with this wiring.