Change functionality of mechanical switches

First project, first fritz.

I have a toy that has two make-break mechanical switches (two pin). Press release the button of switch1 to increase speed a small amount. Press release the button of switch2 to decrease speed a small amount. To get the speed up to 30 for example, press release switch1 button 30 times. To bring speed back down to 0, press release switch2 button 30 times. Each switch makes 5v across its pins when its button is pressed. The two switches share a common ground. The toy internals know to speed up or slow down based on the button/switch that was pressed.

The goal is to use arduino to get those buttons to support press and hold functionality to continuously increase and decrease speed.

For testing, I took the two buttons off the toy and using Arduino I put together a simple two-button, blink-two-led setup. Press and hold button1 and LED1 will blink. Press and hold button2 and LED2 will blink. The thought being that I then replace the two LEDs with the speed up hot/ground and the slow down hot/ground wires of the toy. If Arduino can make the LED blink with a press and hold of the button, it will ‘blink’ the 5v to speed up and slow down the toy. The little arduino only setup works fine. All good on Arduino - press and hold each button and the respective LED blinks.

But it doesn’t work when I replace the LEDs with the wires of the toy. When a single of the switches is connected to Arduino and toy, it works as desired -- pressing and holding increases speed or decreases speed as desired. When both of the switches and their wires from the toy are connected, neither works.

As mentioned, I get what I want with the Arduino using the switches, and LEDs. When I replace LEDs with wires of the toy, nothing.

Any thoughts about where to head next with this are appreciated.

const int button1Pin = 2;     
const int led1Pin =  3;     
const int button2Pin = 7;     
const int led2Pin =  8;     
int button1State = 0;         
int button2State = 0;  

 void setup() {
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
}

void loop() {
  button1State = digitalRead(button1Pin);
  button2State = digitalRead(button2Pin);
  
  if (button1State == HIGH) {
    digitalWrite(led2Pin, LOW);
    digitalWrite(led1Pin, HIGH);
     delay(100);
    digitalWrite(led1Pin, LOW);   
      delay(100);
               
    
    } else if (button2State == HIGH) {
    digitalWrite(led1Pin, LOW);
    digitalWrite(led2Pin, HIGH);
      delay(100);
    digitalWrite(led2Pin, LOW);   
      delay(100);
   
    } else {
    digitalWrite(led1Pin, LOW);
    digitalWrite(led2Pin, LOW);
    }
}

What is the current consumption of "the toy"? 20 mA is the maximum of several Arduino outputs.
How is "the toy" supplied with power?

Check the advice about how to attach info like code and wiring diagrams. We don't want to download, create folders and start Arduino IDE to see Your code.

There's only two buttons or switches on the toy? If there were more (that you didn't tell us about) then I would suspect that the buttons are matrixed like a keyboard.

What is the voltage across each switch when it's not pressed? What is the voltage between the switches? Does that change when one is pressed?

It's 2 x 6V 4.5AH rechargeable batteries. I would have to research more to find current consumption.

There are two other buttons. One is a rocker switch that functions as a master power on/off switch. Nothing works unless the master is on. The other switch is an on/off rocker for a small light.

Each switch shows ~0v when it's not pressed. Also 0v between switches - pressed or not. When a single switch is pressed, it will read ~4.5v; the other switch will continue to read 0v.

Thank you for the time and effort.

darkenney:
Each switch makes 5v across its pins when its button is pressed. The two switches share a common ground.

Is that completely correct? The switches connect to ground - the negative rail?

darkenney:
But it doesn’t work when I replace the LEDs with the wires of the toy. When a single of the switches is connected to Arduino and toy, it works as desired -- pressing and holding increases speed or decreases speed as desired. When both of the switches and their wires from the toy are connected, neither works.


OK, now if the buttons on your toy do switch to ground, that is an important design point - push-buttons - unless in a matrix - should switch to ground, not to the supply rail. You show your buttons connected to the Arduino 5 V which means that you must unnecessarily wire the supply rail to more parts of the circuit than necessary and increase the chance of an accidental short circuit as well as interference pickup. You should always make a practice of connecting the switches to ground and using a pinMode of INPUT_PULLUP; in many or most cases you will not need to provide a pull-up.

Now, you do not actually describe how you connect the Arduino to the buttons on the toy. Needless to say, you must have the Arduino ground connected to the toy battery ground (negative).

What you need to do is to have it so the Arduino pulls the button inputs to ground to emulate the button. To do this, you put a diode between the Arduino output (the diode cathode) and the toy button connection (the diode anode) and write the output LOW to implement the action (having previously set it HIGH before you initialise it as an output). And to avoid the toy feeding current into the Arduino through the diode when the Arduino is OFF, you have to ensure the Arduino is switched on before the toy (or powered from it) and only off after the toy.

Button emulation with optocouplers is the easiest one. Respect the voltage polarity on the buttons, to match the opto transistor polarity, that's the only critical point.

+1 for optocouplers.
Replace the switches by optocouplers, and you're electrically completely isolated from whatever that toy uses.

Thank you for the detailed info. Still trying to get it implemented as described, also ordered a few optocouplers. Will keep at it. Thanks again.

darkenney:
Still trying to get it implemented as described, also ordered a few optocouplers.

Note - do not buy obsolete devices such as 4N25.

Success. With the optocouplers, this became straightforward (even for me). Arduino powers the side with my buttons. When the optocoupler closes, it completes the circuit using just the toy's power wire and ground. Thanks all for the support.

My setup works, but there is an aspect I’m not understanding. For my mechanical button with just two pins, I have one pin of the button connected to Arduino Gnd and the other pin of the button to Arduino pin 2 - pinMode(2, INPUT_PULLUP);

When I do my digitalRead on pin 2, I get LOW when the button is pressed and the code acts on the LOW and all ok.

Here’s my confusion - so what’s the ‘complete circuit’ in this scenario?

darkenney:
Here’s my confusion - so what’s the ‘complete circuit’ in this scenario?

The circuit is from ground, through your button and through the internal pull-up device inside the Arduino, to Vcc.

Ok.... I’m with you there sort of, but when the button is pressed and Input goes LOW doesn’t that break the circuit? And then without the button pressed, there can’t be a completed circuit. So either way, no completed circuit.... maybe I’m being too literal here... thanks for the quick reply and guidance.

An input must be pulled up or down for a valid state. By default it's pulled high by the built-in pullup, which is overridden to low by the pressed switch. Even if the input current is very low, an input pin can sink or source current, just as required.

An Arduino input is usually considered an open circuit. It has a very high input impedance, which for most practical purposes can be considered infinite and the resulting current into the pin zero, just remember that it does take a tiny amount of current, in the order of a few pA. That's also why an unconnected pin is floating, and can read high or low randomly.

The internal pull-up resistor effectively connects it to Vcc when the switch is open, the switch connects it to GND when closed.

darkenney:
Ok.... I’m with you there sort of, but when the button is pressed and Input goes LOW doesn’t that break the circuit? And then without the button pressed, there can’t be a completed circuit. So either way, no completed circuit.... maybe I’m being too literal here... thanks for the quick reply and guidance.

When we are talking about logic, a "circuit" may be no circuit. If you have a torch, if there is a circuit through a closed switch, the torch is ON; if there is no circuit through the switch, the torch is OFF.

The internal pull-up to 5 V is inside the Arduino. It looks mostly like a resistor connected between the pin and 5 V. If you connect the pin to ground, you have a circuit from 5 V through the resistor to ground. Current flows and the voltage across the resistor is the same as across the 5 V supply (or near enough). You have connected the pin to ground so it is at a LOW level.

If you do not connect the pin to ground, then there is no path - no circuit - for current to flow. No current flows. If there is no current, then there is no voltage drop across that internal resistor. If there is no voltage drop, then the two ends must be at the same potential, one at 5 V and the other connected to the input pin. So the input pin is held - by the resistor - to 5 V, it is at a HIGH level.

Thank you all for the info! Doing some testing - why does this scenario result in an occasional LOW?

It could be tough to see - Arduino pin 6 is connected to one end of a length of 22 gauge wire. The length is about 2 feet. Other end is exposed. (Waiting to one day to be connected to a button). I'd think that this should return HIGH (1) 1000% of the time. It doesn't.

I have tried the more obvious variations of this - shorter length of wire, moving to different Arduino pins, changing out Arduino wires, actually having the length of wire connected to a button on one end and into ground on the other, change breadboard columns, all same problem. Even tried swapping out the Uno for a Mega, all give an occasional bad reading. THANKS!

const int read_the_button = 6;   //pin 6 will read when the button is pressed             
int button1State = 0;  //define an intial value for the state of the button

void setup() {
 pinMode(read_the_button, INPUT_PULLUP); //therefore, when button is pressed, pin 6 should  go LOW
 Serial.begin(9600); 
}


void loop() {
  button1State = digitalRead(read_the_button);
 Serial.println( button1State);
  if(button1State == LOW){
  Serial.println( "invisible button magic");
 }

}

Switched digitalRead to analogRead and surprised to see such a wide range of values. Made adjustments, and I seem to be back on track. Until next thing.... Thanks again.

if you analogRead(6) you're reading pin A6. You don't have anything connected there, so you can expect to see a floating pin, values going all over the place from 0 to 1023.

If you digitalRead(6) you're reading the state of pin 6. That wire acts as antenna, and may be picking up enough noise from your environment to occasionally pull low the pin.

By the way, "read_the_button" is a terrible name, that sounds more like a function. It's a constant, so normally written in capitals. Make it something like BUTTON_PIN as that's what it actually is.

I didn’t analogRead pin 6. When I wanted to move to analogRead for troubleshooting, I also switched to pin A0.

When I switched to analogRead and pin A0, I was shocked by the range in values and the amount of environment interference. Still so surprised I’m looking into the environment further.

Yeah, I know variable naming conventions. I should have adjusted for a public post. (Although, read_the_button makes more sense to me because that’s what that pin is actually doing for me - it’s reading the value of the button.)

Another personal convention I have is putting a lowercase f to start all my custom functions - e.g. fdecreaseSpeed. It makes it very easy for me to spot these in a sea of code. Would you like to call it ‘terrible’ now or wait until I post something again down the road?