High voltage drop on Nano outputs caused by sketch

I'm attempting to make a controller for a DSP processor that wants to see it's preset selection pins pulled low. FWIW, they are pulled up to 5V by 100k resistors.
My sketch uses one button to select between the 8 presets and another button to toggle between the selected preset and preset #1 which is configured as a bypass; no change to the audio. For bench testing I have LEDs connected to the outputs with a single 300 Ohm dropping resistor to 5V as only one output will be on at a time. The sketch works, but the voltage drop measured at the Nano outputs is much too high; 800mV and up. The drop also increases at each output in sequence by 350mV. The drop at the last output is 3.44V which puts it very close to not triggering the preset selection. Very strange.
Even stranger, using the exact same hardware and output configuration, but a different sketch, (pretty much a one button per preset selection) the voltage drop at each output is an identical 250mV.
So my question is, what's wrong with my sketch and what about it causes the odd voltage drops? Thank you in advance for your inputs/guidance.

// RPM_footswitch_x8_v2_F
// mchambers 6/19/2025
// for Nano
// a sequential counter that drives RPM preset control inputs, with bypass function (preset1)
// Sketch works but voltage drop on outputs is too high and increases from D9 to D2
// D9=0.8V, D8=1.13V, D7=1.45V, D6=1.81V, D5=2.27V, D4=2.66V, D3=3.04V, D2=3.44V
// Can the problem be saving the last bypass/select state? I don't think they need to be saved.
// Removing the last state save makes it almost impossible to get one preset increment; switch bounce
// Increasing the delay to 200 fixed the one increment issue
// The Vdrop is better: 1V to 3V range; but still terrible. Should be 0.25V or less
// Removing the "if xxxState == LOW" shifts the Vdrop: 0.8V to 3.5V = back to square one
// As the Select switch is pressed, the selected output has less voltage drop for an instant; WTF?

// Constants won't change:
const int bypass = A0;
const int select = A1;
const int preset1 = 9;
const int preset2 = 8;
const int preset3 = 7;
const int preset4 = 6;
const int preset5 = 5;
const int preset6 = 4;
const int preset7 = 3;
const int preset8 = 2;
byte presetPin[] = {2, 3, 4, 5, 6, 7, 8, 9};

// Variables will change:
int bypassPushCounter = 0;   // counter for the number of Bypass button presses
int bypassState = HIGH;      // current state of the Bypass button
int lastBypassState = HIGH;  // previous state of the Bypass button
int selectPushCounter = 1;   // counter for the number of Select button presses
int selectState = HIGH;      // current state of the Select button
int lastSelectState = HIGH;  // previous state of the Select button
int lastPreset = preset1;

void setup() {
  pinMode(bypass, INPUT_PULLUP);
  pinMode(select, INPUT_PULLUP);
  pinMode(preset1, OUTPUT);
  pinMode(preset2, OUTPUT);
  pinMode(preset3, OUTPUT);
  pinMode(preset4, OUTPUT);
  pinMode(preset5, OUTPUT);
  pinMode(preset6, OUTPUT);
  pinMode(preset7, OUTPUT);
  pinMode(preset8, OUTPUT);
}
void presetOffAll() {
  for (int i = 0 ; i < sizeof(presetPin); i++) {
    digitalWrite(presetPin[i], HIGH);
  }
}
void loop() {

  // read the Bypass switch:
  bypassState = digitalRead(bypass);
  if (bypassState != lastBypassState) {
    if (bypassState == LOW) {
      bypassPushCounter++;
    }
    // save the current Bypass state as the last state, for the next time through the loop
    lastBypassState = bypassState;

    // Delay a little bit to avoid bouncing
    delay(200);
  }
  if (bypassPushCounter == 1) { // Bypass mode
    digitalWrite(lastPreset, HIGH);
    digitalWrite(preset1, LOW);
  }
  if (bypassPushCounter == 2) { // non Bypass mode
    digitalWrite(preset1, HIGH);
    digitalWrite(lastPreset, LOW);
  }
  if (bypassPushCounter > 2) {
    bypassPushCounter = 1;
    digitalWrite(lastPreset, HIGH);
    digitalWrite(preset1, LOW);
  }

  // read the Select switch:
  selectState = digitalRead(select);
  if (selectState != lastSelectState) {
    if (selectState == LOW) {
      selectPushCounter++;
    }
    // save the current Select state as the last state, for the next time through the loop
    lastSelectState = selectState;

    // Delay a little bit to avoid bouncing
    delay(200);
  }
  if (selectPushCounter == 1) {
    presetOffAll();
    digitalWrite(preset1, LOW);
    lastPreset = preset1;
  }
  if (selectPushCounter == 2) {
    presetOffAll();
    digitalWrite(preset2, LOW);
    lastPreset = preset2;
  }
  if (selectPushCounter == 3) {
    presetOffAll();
    digitalWrite(preset3, LOW);
    lastPreset = preset3;
  }
  if (selectPushCounter == 4) {
    presetOffAll();
    digitalWrite(preset4, LOW);
    lastPreset = preset4;
  }
  if (selectPushCounter == 5) {
    presetOffAll();
    digitalWrite(preset5, LOW);
    lastPreset = preset5;
  }
  if (selectPushCounter == 6) {
    presetOffAll();
    digitalWrite(preset6, LOW);
    lastPreset = preset6;
  }
  if (selectPushCounter == 7) {
    presetOffAll();
    digitalWrite(preset7, LOW);
    lastPreset = preset7;
  }
  if (selectPushCounter == 8) {
    presetOffAll();
    digitalWrite(preset8, LOW);
    lastPreset = preset8;
  }
  if (selectPushCounter > 8) {
    presetOffAll();
    selectPushCounter = 1;
    digitalWrite(preset1, LOW);
    lastPreset = preset1;
  }
}

Please post that one for comparison.

Which "sequence"?
What's the voltage at the resistor?

    // Delay a little bit to avoid bouncing
    delay(200);
  }

Try moving that } to the bottom of loop().

If this is "regular" Nano with the ATmega chip, the datasheet says output-high should be at least 4.2V with a 5V supply, at 20mA and 85 degrees C. (It drops to 4.1V at 105 degrees).

Output-low is 1V or less.

Connected to an input that's pulled-up to 5V I wouldn't expect any voltage drop (or any current flow).

Since the outputs are driven high or low you don't need pull-ups but they won't hurt. Inputs can float so sometimes they need pull-ups depending on what's driving them.

Which "Nano"? There are around six of them.

The OP is quite confusing in labeling pins and signals as inputs or outputs. The setup() code reveals the really used setting.

Here is the other sketch.

// RPM_footswitch_x8_B
// machambers 5/18/2024
// for Arduino Nano
// negative logic design; 0/low/false = On
// Added initialization section
// tested good 5/18/2024

// Constants won't change
int switch_1_5 = A0;
int switch_2_6 = A1;
int switch_3_7 = A2;
int switch_4_8 = A3;
int switch_b1 = A4;
int switch_b2 = A5;
int outLED1 = 2;
int outLED2 = 3;
int outLED3 = 4;
int outLED4 = 5;
int outLED5 = 6;
int outLED6 = 7;
int outLED7 = 8;
int outLED8 = 9;
int bankLED1 = 10;
int bankLED2 = 11;

// Variables will change
int Status = 1;
int delTime = 200;
int bank1 = true;
int bank2 = true;
byte ledPin[] = {2, 3, 4, 5, 6, 7, 8, 9}; // list of preset led pins

void setup() {
  pinMode(switch_1_5, INPUT_PULLUP);
  pinMode(switch_2_6, INPUT_PULLUP);
  pinMode(switch_3_7, INPUT_PULLUP);
  pinMode(switch_4_8, INPUT_PULLUP);
  pinMode(switch_b1, INPUT_PULLUP);
  pinMode(switch_b2, INPUT_PULLUP);
  pinMode(outLED1, OUTPUT);
  pinMode(outLED2, OUTPUT);
  pinMode(outLED3, OUTPUT);
  pinMode(outLED4, OUTPUT);
  pinMode(outLED5, OUTPUT);
  pinMode(outLED6, OUTPUT);
  pinMode(outLED7, OUTPUT);
  pinMode(outLED8, OUTPUT);
  pinMode(bankLED1, OUTPUT);
  pinMode(bankLED2, OUTPUT);
}
void ledOffAll() {
  for (int i = 0 ; i < sizeof(ledPin); i++) {
    digitalWrite(ledPin[i], true);
  }
}
void loop() {
  if (Status == 1) {
    bank1 = false;
    digitalWrite(bankLED1, false);
    digitalWrite(bankLED2, true);
    ledOffAll();
    digitalWrite(outLED1, false);
    Status = 0;
  }
  if (digitalRead(switch_b1) == false) {
    bank1 = false;
    bank2 = true;
    digitalWrite(bankLED1, false);
    digitalWrite(bankLED2, true);
    delay(delTime);
  }
  if (digitalRead(switch_b2) == false) {
    bank1 = true;
    bank2 = false;
    digitalWrite(bankLED1, true);
    digitalWrite(bankLED2, false);
    delay(delTime);
  }
  if (digitalRead(switch_1_5) == false && bank1 == false) {
    ledOffAll();
    digitalWrite(outLED1, false);
    delay(delTime);
  }
  if (digitalRead(switch_1_5) == false && bank2 == false) {
    ledOffAll();
    digitalWrite(outLED5, false);
    delay(delTime);
  }
  if (digitalRead(switch_2_6) == false && bank1 == false) {
    ledOffAll();
    digitalWrite(outLED2, false);
    delay(delTime);
  }
  if (digitalRead(switch_2_6) == false && bank2 == false) {
    ledOffAll();
    digitalWrite(outLED6, false);
    delay(delTime);
  }
  if (digitalRead(switch_3_7) == false && bank1 == false) {
    ledOffAll();
    digitalWrite(outLED3, false);
    delay(delTime);
  }
  if (digitalRead(switch_3_7) == false && bank2 == false) {
    ledOffAll();
    digitalWrite(outLED7, false);
    delay(delTime);
  }
  if (digitalRead(switch_4_8) == false && bank1 == false) {
    ledOffAll();
    digitalWrite(outLED4, false);
    delay(delTime);
  }
  if (digitalRead(switch_4_8) == false && bank2 == false) {
    ledOffAll();
    digitalWrite(outLED8, false);
    delay(delTime);
  }
}

The sequence of presets selected: D9, D8, D7, D6, D5, D4, D3, D2.
With D9 selected, the voltage at the LED side of the resistor is 2.55V.
With D2 selected, the voltage at the LED side of the resistor is 4.03V.

The pull-up on the outputs is just to control the current through the LEDs.
The output are driven low as that's what's required to drive the DSP box control pins.

Bare-bones clone with ATmega 328P and CH340 USB, nothing else.

Try this

// RPM_footswitch_x8_v2_F
// mchambers 6/19/2025
// for Nano
// a sequential counter that drives RPM preset control inputs, with bypass function (preset1)
// Sketch works but voltage drop on outputs is too high and increases from D9 to D2
// D9=0.8V, D8=1.13V, D7=1.45V, D6=1.81V, D5=2.27V, D4=2.66V, D3=3.04V, D2=3.44V
// Can the problem be saving the last bypass/select state? I don't think they need to be saved.
// Removing the last state save makes it almost impossible to get one preset increment; switch bounce
// Increasing the delay to 200 fixed the one increment issue
// The Vdrop is better: 1V to 3V range; but still terrible. Should be 0.25V or less
// Removing the "if xxxState == LOW" shifts the Vdrop: 0.8V to 3.5V = back to square one
// As the Select switch is pressed, the selected output has less voltage drop for an instant; WTF?

// Constants won't change:
const int bypass = A0;
const int select = A1;
const int preset1 = 9;
const int preset2 = 8;
const int preset3 = 7;
const int preset4 = 6;
const int preset5 = 5;
const int preset6 = 4;
const int preset7 = 3;
const int preset8 = 2;
byte presetPin[] = {2, 3, 4, 5, 6, 7, 8, 9};

// Variables will change:
int bypassPushCounter = 0;   // counter for the number of Bypass button presses
int bypassState = HIGH;      // current state of the Bypass button
int lastBypassState = HIGH;  // previous state of the Bypass button
int selectPushCounter = 1;   // counter for the number of Select button presses
int selectState = HIGH;      // current state of the Select button
int lastSelectState = HIGH;  // previous state of the Select button
int lastPreset = preset1;

void setup() {
  pinMode(bypass, INPUT_PULLUP);
  pinMode(select, INPUT_PULLUP);
  pinMode(preset1, OUTPUT);
  pinMode(preset2, OUTPUT);
  pinMode(preset3, OUTPUT);
  pinMode(preset4, OUTPUT);
  pinMode(preset5, OUTPUT);
  pinMode(preset6, OUTPUT);
  pinMode(preset7, OUTPUT);
  pinMode(preset8, OUTPUT);
}
void presetOffAll() {
  for (int i = 0 ; i < sizeof(presetPin); i++) {
    digitalWrite(presetPin[i], HIGH);
  }
}
void loop() {

  // read the Bypass switch:
  bypassState = digitalRead(bypass);
  if (bypassState != lastBypassState) {
    if (bypassState == LOW) {
      bypassPushCounter++;
    }
    // save the current Bypass state as the last state, for the next time through the loop
    lastBypassState = bypassState;

    // Delay a little bit to avoid bouncing
    delay(200);
  
  if (bypassPushCounter == 1) { // Bypass mode
    digitalWrite(lastPreset, HIGH);
    digitalWrite(preset1, LOW);
  }
  if (bypassPushCounter == 2) { // non Bypass mode
    digitalWrite(preset1, HIGH);
    digitalWrite(lastPreset, LOW);
  }
  if (bypassPushCounter > 2) {
    bypassPushCounter = 1;
    digitalWrite(lastPreset, HIGH);
    digitalWrite(preset1, LOW);
  }
 }

  // read the Select switch:
  selectState = digitalRead(select);
  if (selectState != lastSelectState) {
    if (selectState == LOW) {
      selectPushCounter++;
    }
    // save the current Select state as the last state, for the next time through the loop
    lastSelectState = selectState;

    // Delay a little bit to avoid bouncing
    delay(200);
  
  if (selectPushCounter == 1) {
    presetOffAll();
    digitalWrite(preset1, LOW);
    lastPreset = preset1;
  }
  if (selectPushCounter == 2) {
    presetOffAll();
    digitalWrite(preset2, LOW);
    lastPreset = preset2;
  }
  if (selectPushCounter == 3) {
    presetOffAll();
    digitalWrite(preset3, LOW);
    lastPreset = preset3;
  }
  if (selectPushCounter == 4) {
    presetOffAll();
    digitalWrite(preset4, LOW);
    lastPreset = preset4;
  }
  if (selectPushCounter == 5) {
    presetOffAll();
    digitalWrite(preset5, LOW);
    lastPreset = preset5;
  }
  if (selectPushCounter == 6) {
    presetOffAll();
    digitalWrite(preset6, LOW);
    lastPreset = preset6;
  }
  if (selectPushCounter == 7) {
    presetOffAll();
    digitalWrite(preset7, LOW);
    lastPreset = preset7;
  }
  if (selectPushCounter == 8) {
    presetOffAll();
    digitalWrite(preset8, LOW);
    lastPreset = preset8;
  }
  if (selectPushCounter > 8) {
    presetOffAll();
    selectPushCounter = 1;
    digitalWrite(preset1, LOW);
    lastPreset = preset1;
  }
 }
}

Needs auto-formatting, but I'm on my phone right now.

The sketch now starts with all of the LEDs on, but that's fixable.
The good part is that the voltage drops are now all about equal at 180mV.
Can you explain what moving the } does and why it affects the voltage drops?

Glad it seems to have fixed the problem.

If I'm right, the voltage drops were not real. They look real because you are using, I assume, a multimeter.

If you looked at the voltages with an oscilloscope, I suspect you would not see the voltages you measured with the multimeter. You would see that the voltage was steady but switching on and off at high speed, and with different duty cycles for the different settings. This would look to a multimeter like different voltages.

Moving the } stopped the voltage switching on and off, making it steady with only that 180mV drop due to the LED current.

There's something wrong with your circuit. it does not match your description.

The last line of my notes in the broken sketch notes that the LEDs would turn-on then dim slightly; must have been the oscillation/PWM starting. Time to dig the o'scope out.
Thank you very much for your help.

1 Like

A picture is worth a thousand words.
RPM Footswitch x8 v2 schematic 00c.pdf (15.0 KB)

You can drag-and-drop a picture into a reply window; a lot more convenient for most of us than opening a pdf.

It clearly says that multiple outputs have to be LOW for a varying resistor voltage. Fix your code.

Thanks, I'll try to remember to try that next time.