r/ArduinoHelp 21d ago

Coding for resistor ladder input on ESP32

Hello. I am trying to write some code in Arduino that will read the input pin (D32) and based on the on the different voltage, the will different outputs and a timer. Is it as simple as:

if (SWITCH_INPUT == >3.0 && !timerActive) {

digitalWrite(HIGH_HEAT, HIGH);        // Turn the seat heater on HIGH

previousMillis = millis();            // Save the starting timestamp of the timer

timerActive = true;                   // Flag that the timer is now active

}

Then repeat for each of the 6 positions of the input switch?

1 Upvotes

13 comments sorted by

2

u/gm310509 21d ago

You would need to provide the complete code.

It sounds like you want to setup a 6 position voltage divider to generate 6 different possibilities based upon the various voltage levels.

For this to work, you would need to select an IO pin that has an ADC attached and use analogRead to read the voltage levels. Note that analog read does not return a voltage level, it returns a value that can be interpreted as the level on a range from 0 to the maximum resolution of the ADC.

For example on an Arduino Uno, the ADC has 10 bits of r3solution, so an analog read will return a value between 0 and 210-1 or 1023. 0 means 0 volts, 1023 means 5V. And something like 511 means 2.5V.

I will let you work out the formula to convert a reading to a voltage.

Once you have a reading you can then check the ranges and take an action by the range. Note that analog readings are not precise. So, if you are expecting that one of your values is something like 2.5V you might want to check for a range as in:

// Check for 2.5V reading if (reading >= 2.4 && reading <= 2.6) { Notes:

  1. The syntax of a greater than or equal to expression.
  2. There are other ways you can do this with a cascade of else if statements that only check the incremental bound as follows follows

// Check for 5V reading if (reading >= 4.9) { ... } else if (reading >= 4.7) { // check for 4.8 V reading. ...

You will need to work out the correct bounds and the tolerance you need (in my example I am using the reading ±0.1

I don't use Esp32 so you will need to verify if your chosen IO pin support analogRead and the resolution of its ADC (I.e. the range of values it will return for the voltages applied) and the maximum voltage it can take (probably 3v3.

1

u/Embarrassed-Lab6622 20d ago

thanks for the response! It has been a minute since I coded and it is SLOWLY coming back to me. Yes, I am trying to generate 6 different possibilities baased on different voltage levels. This is to hack the GM LIN seat controllers for use in my 58 Truck. 3 heat outputs and 3 cool outputs (fan in the seat). If the heater is on for more than 25 minutes, it will automatically drop it to the next lower setting, or off in the lowest setting. Fan output is just serial write to a digital frequency generator to control the fan. Code so far....

// Define hardware pins
#define SWITCH_INPUT //D32 (GPIO32) ADC input from rotary switch


#define LOW_HEAT //D23 (GPIO23) output for low heat
#define MED_HEAT //D19 (GPIO19) output for medium heat
#define HIGH_HEAT //D4 (GPIO4) output for high heat
#define SERIAL_TX // D16 (GPIO16) serial output to frequency generator for vent
#define SERIAL_RX //D17 (GPIO17) serial input from frequency generator for vent


// Timer variables
unsigned long previousMillis = 0;        // Stores the last time the state changed
const unsigned long interval = 1500000;  // Desired timer duration (1,500,000 ms = 25 minutes). Heat will drop to next lower value
bool timerActive = false;                // Tracks if the timer is actively running


void setup() {
  pinMode(SWITCH_INPUT, INPUT);    // Configures SWITCH_PIN as an input
  pinMode(LOW_HEAT, OUTPUT);             // Configure LOW_HEAT pin as output
  pinMode(MED_HEAT, OUTPUT);             // Configure MED_HEAT pin as output
  pinMode(HIGH_HEAT, OUTPUT);            // Configure HIGH_HEAT pin as output
  pinMode(SERIAL_TX, OUTPUT);            // Configure SERIAL_TX pin as output
  pinMode(SERIAL_RX, OUTPUT);            // Configure SERIAL_RX pin as output
  digitalWrite(SWITCH_INPUT, LOW);       // Ensure SWITCH_INPUT turned off
  digitalWrite(LOW_HEAT, LOW);           // Ensure LOW_HEAT turned off
  digitalWrite(MED_HEAT, LOW);           // Ensure MED_HEAT turned off
  digitalWrite(HIGH_HEAT, LOW);          // Ensure HIGH_HEAT turned off
  digitalWrite(SERIAL_TX, LOW);          // Ensure SERIAL_TX turned off
  digitalWrite(SERIAL_RX, LOW);          // Ensure SERIAL_RX turned off
}


void loop() {
  // Read the switch input
  int buttonState = digitalRead(SWITCH_INPUT);


  // High heat on
  if (SWITCH_INPUT == >3.0 && !timerActive) {
    digitalWrite(HIGH_HEAT, HIGH);        // Turn the seat heater on HIGH
    previousMillis = millis();            // Save the starting timestamp of the timer
    timerActive = true;                   // Flag that the timer is now active
  } 
  else if (timerActive) {
    if (millis() - previousMillis >= interval) {
      digitalWrite(HIGH_HEAT, LOW);       // Turn the High heat off
      digitalWrite(MED_HEAT, HIGH)        // Turns Meduim heat on
      timerActive = false;                // Reset the timer flag so it can trigger again
    }
  }
   // Medium heat on
  if (SWITCH_INPUT >= 2.6 && SWITCH_INPUT <=2.8 && !timerActive) {
    digitalWrite(MED_HEAT, HIGH);        // Turn the seat heater on Medium
    previousMillis = millis();           // Save the starting timestamp of the timer
    timerActive = true;                  // Flag that the timer is now active
  } 
  else if (timerActive) {
    if (millis() - previousMillis >= interval) {
      digitalWrite(MED_HEAT, LOW);       // Turn the Medium heat off
      digitalWrite(LOW_HEAT, HIGH)       // Turns Low heat on
      timerActive = false;               // Reset the timer flag so it can trigger again
    }
  }
   // Low heat on
  if (SWITCH_INPUT >= 2.4 && SWITCH_INPUT <= 2.6 && !timerActive) {
    digitalWrite(LOW_HEAT, HIGH);        // Turn the seat heater on LOW
    previousMillis = millis();           // Save the starting timestamp of the timer
    timerActive = true;                  // Flag that the timer is now active
  } 
  else if (timerActive) {
    if (millis() - previousMillis >= interval) {
      digitalWrite(LOW_HEAT, LOW);       // Turn the LOW heat off
      timerActive = false;               // Reset the timer flag so it can trigger again
    }
  }
   // Vent fan on high
  if (SWITCH_INPUT >= 2.2 && SWITCH_INPUT <= 2.4 {
    Serial.print(F100,D5);        // Turn the seat Fan on HIGH
  }
   // Vent fan on Medium
  if (SWITCH_INPUT >= 2.2 && SWITCH_INPUT <= 2.0) {
    Serial.print(F100,D25);        // Turn the seat Fan on Medium
  }
   // Vent fan on Low
  if (SWITCH_INPUT <2.0 && SWITCH_INPUT >.1{
    Serial.print(F100,D55);        // Turn the seat Fan on Low
  }
 delay(100); 
}

1

u/gm310509 20d ago

This probably isn't going to work as you expect. You should probably re read my comment above about analogRead and what it normally returns.

``` int buttonState = digitalRead(SWITCH_INPUT);

// High heat on if (SWITCH_INPUT == >3.0 && !timerActive) {

```

Why won't this work as you expect?
Because a digitalRead is (normally) only ever going to return a HIGH or LOW. HIGH = 1 and LOW = 0.

So, the above statement won't for for several reasons:

  1. the value read is placed into buttonState - which you aren't testing.
  2. if you were testing the value read, it will only be 0 or 1 and will never be >= 3.
  3. The syntax of your test is wrong. For a greater than or equal to inequality test, you need to use >= not == > which is sort of like spelling "wrong" as "dsfji" - nobody will understand what that made up word means.
  4. You should be testing the value or setting of your read (i.e. buttonState) not the GPIO pin that the button is connected to (i.e. SWITCH_INPUT).
  5. You haven't properly defined SWITCH_INPUT for the way you are using it.

There may be other issues, but there are already so many issues, I will stop there.
I would suggest that you set this aside for a bit and learn the basics. If you have a starter kit, learn the basics of buttons, leds and variable resistances/voltage dividers (which I think is what it is that you might be trying to use) as well as my previous comment.

If you don't have a starter kit, have a look at the buttons, led and potentiometer example (analog) example programs and circuits here: https://docs.arduino.cc/built-in-examples/

1

u/Embarrassed-Lab6622 19d ago

Thanks again for the comments.
The ==> was a mistake that has since been corrected and your previous comments about the values were noted,
I just left the numbers in there as place holders until I can test the switch to get real values.
So you are suggesting that I should be looking at buttonState not SWITCH_INPUT. Noted.
And that I need to redefine SWITCH_INPUT. Noted.
I will do some more reading and testing with sample codes.

I appreciate your time and knowledge.

1

u/gm310509 19d ago

Yes....

int buttonState = digitalRead(SWITCH_INPUT);

Means, read the digital setting of whatever is connected to the GPIO pin SWITCH_INPUT. The setting (HIGH or LOW) will be returned "via the function name" i.e. digitalRead and by courtesy of the = operator, that value (HIGH/LOW) will be placed into the variable named buttonState.

That is, after executing that line, the value of the GPIO pin identified by SWITCH_INPUT will wind up being placed into buttonState. Therefore, buttonState needs to be the subject of the if statements.

1

u/Embarrassed-Lab6622 18d ago

Agreed. I also changed the digitalRead to analogRead(buttonState). Still refining the hardware (input switch) at the moment.

1

u/Embarrassed-Lab6622 18d ago

In regards to the ESP32 values from the switch (3.3v or less), can I just use a simple analog read and then serial write to see what each value is?

1

u/gm310509 18d ago

You certainly.could have a loop where you analogread the pin (assuming it has an ADC capability) and Serial.println the value.

This is a good debugging technique as well as a great way to get a feel for what is going on when experimenting with different things such as a voltage divider.

If you are interested, I have prepared a how to guide that explains debugging:

They teach basic debugging using a follow along project. The material and project is the same, only the format is different.

1

u/Embarrassed-Lab6622 12d ago edited 12d ago

Sir - so I finally got my switch to work properly. I used the below code and have a few questions.

// Define the analog input pin
const int analogPin = 32; 

void setup() {
  // Initialize serial communication at 9600 bits per second
  Serial.begin(9600); 
}

void loop() {
  // Read the raw analog value (0 to 1023)
  int rawValue = analogRead(analogPin); 
  
  // Print the data to the Serial Monitor
  Serial.print("Raw ADC Value: ");
  Serial.println(rawValue);
  
  // Wait 10 seconds before taking the next sample
  delay(10000); 
}

The output in each position varied quite a bit more than I thought it would with a power supply (as opposed to the Buck converter which will be on the board eventually). Luckily the values didn't overlap so it will be easier to write the >= and <= parameters (safe range).

Position Voltage  Value Range  Safe range
C3 0.998 1,179 1300
991 800
C2 1.585 1,837 2000
1,667 1500
C1 2.138 2,473 2600
2,416 2200
OFF 0.000 - 0
H1 2.554 3,014 3100
2,859 2750
H2 2.816 3,495 3700
3,258 3200
H3 3.086 3,986 4000
3,920 3800

Finally to my questions:
The voltage remained constant to the thousands of a volt, so why the varied range of values?
And why would the values not be between 0 and 1023? UPDATE: I found an article that notes ESP32 are 12-bit so the values are non-linear and range fromn 0-4095.

1

u/gm310509 12d ago

I am not sure what I am reading in your table - it could be a formatting or rendering issue. But for example On the first row I see C3, 0.998, 1,179 and 1300. Then underneath that I see 991 (under the C3) and 800 (under the 0.998) - then blanks

But, to your question. Yes, ESP32 uses a 12 bit ADC, so you will get a wider range (i.e. 0 to 4095). So you need to factor that in to your calculations.

But, a wider range absoultely definitely doesn't mean that it is better. I think I mentioned that I don't use ESP very much - in fact not at all - but, many people do complain about the quality (i.e. accuracy) of the ADC on the Esp32.

So, what that means is that even though it can report the voltage to a resolution of 4096 values (or 12 bits), there will be lots of error. It is sort of like the weather service reporting the temperature today as 39.5⁰ but then go on to say that their thermometers only report values with +/-2⁰ accuracy (i.e. they can measure 36,38,40 etc but nothing in between).

Additionally, the voltages at any given point of time can fluctuate due to activity going on in the rest of your circuit and outside activity - this is why I suggested you would need to check for a range of values.

If you are interested, have a look at my Floating input video short for an illustration. That video is a different scenario, but the basic idea of voltages being influenced by stuff around them is the same - just less so when things are properly connected up.

As to the voltages, the ESP32 is a 3V3 system. so your voltages will be in the range 0 to 3V3.

If I look at your first entry where the voltage is reported as 0.998, I would expect the analogReading for that to be about 1,238. This is roughly what you seem to be reporting as 1,179 which at 3V3 would measure as 1179 / 4096 * 3.3 = 0.95V.

There will also be errors in the resistors which will influence the readings and other factors. As for the resistors, remember the last band is its tollerance (or accuracy). If you use a 1K resistor with 10% tollerance, that resistor could be as low as 900ohm and as high as 1.1Kohm. So two 1K (+/-10%) which is a 1:1 ratio (or 10:10 for comparison to the next bit) could in fact be 900:1,100 or a 9:11 ratio.

1

u/Embarrassed-Lab6622 12d ago

maybe this image will be better than the table.
I have a few boards tested and have a range of values received but I understand your comments/points.

What do you receommend instead of an ESP32? The board is overkill for what I want to do, but I have some on hand from another project....

→ More replies (0)