Reading and writing to a single digital pin

Hi,
I am trying to read and write to a single digital pin. Is it something which is possible with a full success rate? I am trying to read a switch output and drive an LED via the same pin. (Schematic attached)
It seemed working with one unit (switch + LED) on a single pin. Code which I used is given below. Tried to comment wherever possible in the code based on my understanding. What it did does is that reads the switch and turns on the LED for 2sec and turns it off and loops..

/*
Single Digital pin Read and Write
*/

// Pushbutton 1 end to 5V, other end to digital pin(7)
// Same digital pin(7) connected to 10k to ground
// in parallel to 10k connect led positive + 1k resistor to ground

int pushButton = 7;


void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // Enable pushbutton's pins internal pull up resistor(20k) to 5V:
  pinMode(pushButton,INPUT_PULLUP);
    // Same can be achieved by the following two lines
       // pinMode(pushButton, INPUT);
       // digitalWrite(pushButton,HIGH);
}


void loop() {
  
  int buttonState = digitalRead(pushButton);  // Read the push button pin. Usually its zero, when pressed it goes to HIGH or 1
  Serial.println(buttonState);  // Printing on serial monitor the status
  if(buttonState==1)  // When button is pressed
  {
    pinMode(pushButton, OUTPUT);  // Changing to OUTPUT mode creates low impedance path from pin (and deactivates the pullup) it gives +5V which makes LED glow.
    delay(2000);
    pinMode(pushButton,INPUT_PULLUP);  // Turn on the pullup again, thereby turning off the LED.
      //  OR
      //    pinMode(pushButton, INPUT);
      //    digitalWrite(pushButton,HIGH);
  }  
  delay(50);        
}

But is it suppossed work like this? Because when I tried to do it with multiple units(switch + LED) on 2 different pins it was not working. What I wanted to do was when a press the switch that unit need to light up turning out the any other LEDs if they were ON. Here is a crude code I tried and it wasnt working properly.

/*
Multiple Digital pin Read and Write
*/

// Pushbutton 1 end to 5V, other end to digital pin(7)
// Same digital pin(7) connected to 10k to ground
// in parallel to 10k connect led positive + 1k resistor to ground
//Same with digital pin (8)

int pushButton_1 = 8;
int pushButton_2 = 7;

int buttonState_1, buttonState_2;

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // Enable pushbutton's pins internal pull up resistor(20k) to 5V:
  pinMode(pushButton_1,INPUT_PULLUP);
  pinMode(pushButton_2,INPUT_PULLUP);
    // Same can be achieved by the following two lines
       // pinMode(pushButton, INPUT);
       // digitalWrite(pushButton,HIGH);
}

// the loop routine runs over and over again forever:
void loop() {
  
  buttonState_1 = digitalRead(pushButton_1);  // Read the push button pin. Usually its zero, when pressed it goes to HIGH or 1
  buttonState_2 = digitalRead(pushButton_2);
  Serial.print("buttonState_1 = "); Serial.println(buttonState_1);  // Printing on serial monitor the status
  Serial.print("buttonState_2 = "); Serial.println(buttonState_2);
  if(buttonState_1==1)  // When button is pressed
  {
    //digitalWrite(pushButton_2,LOW);
    pinMode(pushButton_2,INPUT_PULLUP);
    pinMode(pushButton_1, OUTPUT);  // Changing to OUTPUT mode creates low impedance path from pin (and deactivates the pullup) it gives +5V which makes LED glow.
    

  }  
  if(buttonState_2==1)
  {
    //digitalWrite(pushButton_1,LOW);
    pinMode(pushButton_1,INPUT_PULLUP);
    pinMode(pushButton_2, OUTPUT);
    
  }
  delay(50);        
}

Can anyone please help me figure out the problem? Is it a code issue or a schematic issue or is it just plain impossible do with arduino?

New code and circuit here : Reading and writing to a single digital pin - #16 by system - Programming Questions - Arduino Forum

I get a little lost reading your code.
Why do enable the internal pull-up resistor, and have an external pull-down resistor. That doesn't make sense.
Can you make two functions ? One to turn the led on and off, and another to read the switch ?

// example code, not tested.

int ledIsOn = false;

// Function Led.
//    Usage: Led(true); to turn led on
//               Led(false); to turn led off
void Led( int On) 
{
  if( On) 
  {
    // Set output high, before pin is made output.
    // If the output turns low, it could shortcut if button is pressed.
    digitalWrite( pushButton, HIGH);
    pinMode( pushButton, OUTPUT);
    // write once more to be sure.
    digitalWrite( pushButton, HIGH);

    ledIsOn = true;       // remember state of pin
  }
  else
  {
    // Can't make the output pin low, 
    // that would shortcut if the button is pressed.
    // Return the pin to input state, without internal pull-up.
    // The led will turn off.
    pinMode( pushButton, INPUT);

    ledIsOn = false;       // remember state of pin
  }
}


// Function Switch.
//    Usage: return value is true of switch is pressed.
int Switch( void) 
{
  int val;

  if( ledIsOn) 
  {
    // The pin is in output state, we have to change that
    // to read the switch.
    pinMode( pushButton, INPUT);
    delay( 1);           // wait, due to the capacitance of the circuit.
    val = digitalRead( pushButton);
    Led( true);          // turn led on again.
  }
  else
  {
    val = digitalRead( pushButton);
  }
  return( val);
}

If you have the internal pullup resistor enabled, you should NOT have an external resistor. One side of the switch goes to the digital pin, and the other side goes to ground.

  int buttonState = digitalRead(pushButton);  // Read the push button pin. Usually its zero, when pressed it goes to HIGH or 1

Not with a pullup resistor. The pin is HIGH when the switch is not pressed and LOW when pressed.

Putting aside the complication of the electrical connections could that others have pointed out, could

What it did does is that reads the switch and turns on the LED for 2sec and turns it off and loops..

have anything to do with the delay(2000) in the loop() function and the switching of the pinMode ?

Are you so short of pins that you need to connect the switch and the LED to the same pin ?

Why go through all the trouble with the software when you can do this?

Why go through all the trouble with hardware when you can do it in software ?

How many components would you need to flash 10 LEDs using that hardware method ?
Answer 60

How many components would you need to flash 10 LEDs using an Arduino and software ?
Answer 21

Thanx for all your replies :slight_smile:

@Krodal
I thought of a circuit that could work and this was what that came to my mind at that moment.Hence the internal pullup. Any other circuit to wire this on to a single pin is most welcome.
Will check out your code soon. A bit busy today. Thanx :slight_smile:

@PaulS

 int buttonState = digitalRead(pushButton);  // Read the push button pin. Usually its zero, when pressed it goes to HIGH or 1

Shouldnt it work like this? because I think the internal resistor is atleast 20k or more. (Could not find the exact value from datasheet) so it will be like when pull up is enabled. Shouldnt only a maximum of 5/3 = 1.66 V come across the 10k external pull down resistor? which I believe should not cause the digitalRead to read it as an input 1...

@UKHeliBob
The first code I posted is apparently working fine. Only the second code gives me problems.

have anything to do with the delay(2000) in the loop() function and the switching of the pinMode ?

Cant say I havent thought of this but 2sec for switching is too much I guess. Or Am I wrong. Cant seem to figure out how to resolve the issue if thats the case.

Are you so short of pins that you need to connect the switch and the LED to the same pin ?

Well I am not actually. I would like reduce the wires going to arduino and save pins if its possible. If this doesnt work out I can always go back to 2 pins for a unit but I really would like to get this one working.

@Shpaget

Why go through all the trouble with the software when you can do this?

For obvious reasons of hardware requirement.

000:

have anything to do with the delay(2000) in the loop() function and the switching of the pinMode ?

Cant say I havent thought of this but 2sec for switching is too much I guess. Or Am I wrong. Cant seem to figure out how to resolve the issue if thats the case.

Well, I bet if you reduce the delay to 1 second then the LED will stay on for 1 second, thus proving the link between the two. To me it seems obvious that setting a pin to INPUT (PULLUP or not) should affect what it is doing at the time.

Well, I bet if you reduce the delay to 1 second then the LED will stay on for 1 second, thus proving the link between the two.

Well that would obviously work right? I can change the delay and make it glow for any amount of time. How will that ensure the switching speed is met or not?

I got to agree. Using delay() is shooting yourself in the foot. Learn Blink Without Delay.

You can read the port bits using bitRead(). If it's a lot the same bit then this is a good choice.
http://arduino.cc/en/Reference/BitRead

You can read a whole port

and get... on an UNO I use 6 pins per port, the pin map explains why best:

the crystal uses Port B pins 6 and 7. Port C pin 6 is reset. Port D pins 0 and 1 are UNO RX and TX. So I don't aim at more than 6 without resorting to shift registers, and then I can have a great many pins that I can read or write using only 4 Arduino pins plus power and ground, and external power for the chips, they can drive leds if you want, but don't forget the resistors!
I got 8-bit bi-directional shift registers, can select which direction serial <---> parallel the data flows, from Futurlec for maybe a dollar each, maybe less.
Shift registers on SPI can run in 1 or 2 meg/sec bursts. Changing 32 bits/pins at that speed don't take long. And because the register has a latch you read all the pins simultaneous until next latch.

Or...

You can read the port into a variable and read the low bit, shift right, repeat X times and there's your bits. What you do with them, do it right inside the read-shift-repeat cycle. You can run it in microseconds, I bet less than 100 usec if the what to do is kept short. Analog read takes 104 usec.

@GoForSmoke
Will read up on that when I get home.
So is the hardware wired up properly to work? and its just the code issue? To be more specific, the timing issue?

If you want to do many things at once then you have to push each task a quick step along when it has a turn so that no task holds others up. By quick I mean preferably under 100 microseconds but sometimes analog read is necessary. A delay(1) is 10 times that long, not that you'd notice.

Each sub task should run as a separate section in loop() and have certain conditions ( if's ) that code runs on any particular pass through loop() the program is making.

One condition is that a timer has run out. I put them up at the top of loop() in order of the most critical first. If the program uses millis() then I stick the time checks inside an if() to see if millis() changed since last time the time checks were run which will be most of the loop()'s.

Another is Serial.available(). Serial usually comes in 1 in 100's to 1000's of times through loop(). A complete message may take many milliseconds. I process my text as it comes in. Converting digits to numeric variables and matching command codes can be done before the full message arrives. I keep track of the parsing through a state variable and each serial text char is handled according to the state. That handling may change the state as well.
States may include waiting, command-input, number-input and count variables may get used.

If a sensor pin lights up maybe set a state that runs a matching section of loop() code.

000:
Shouldnt it work like this? because I think the internal resistor is atleast 20k or more. (Could not find the exact value from datasheet) so it will be like when pull up is enabled. Shouldnt only a maximum of 5/3 = 1.66 V come across the 10k external pull down resistor? which I believe should not cause the digitalRead to read it as an input 1...

Your theory about the external pull-down resistor being a low enough value to pull the input voltage down against the pull-up resistor seems reasonable. However, the effect would be that when the switch was closed and the external pull-down resistor was connected, the voltage at the Arduino pin would drop causing the digitalRead() result to change from HIGH (switch open) to LOW (switch closed). That's the reverse of what you said.

@GoForSmoke
Thanks for the tips. but don't think I can apply any of that here.
@PeterH

However, the effect would be that when the switch was closed and the external pull-down resistor was connected, the voltage at the Arduino pin would drop causing the digitalRead() result to change from HIGH (switch open) to LOW (switch closed). That's the reverse of what you said.

Here is my understanding of the circuit. When I push the button, the 10k resistor will get 5V even if Pullup enabled. right? which will cause the digitalRead to read this as high. right??

000:
Here is my understanding of the circuit. When I push the button, the 10k resistor will get 5V even if Pullup enabled. right? which will cause the digitalRead to read this as high. right??

Sorry, I needed to look at the drawing more carefully. I think you're right, although I have no idea why you're using such a convoluted design.

Wouldn't it be simpler to enable the internal pullup, connect the switch between the pin and ground, and connect the LED+series resister between 5V and the pin? Having pullup and pulldown resisters plus loads in parallel makes it much harder to predict the behaviour. At the end of the day, does digitalRead() actually return the values you expect when the switch is open and closed?

Thanks @PeterH
Your circuit looks less messy anyways :smiley: and it should work. Rewired it like that. Attached schematic.

This circuit works just fine for 1 unit connected to 1 pin. But when I connect 2 units in different pins it doesnt work(same as the case with my previous design). So I think it should be a problem with code.
What I am trying to do when I press button_1, only the LED connected to that must glow(rest must turn off if already on)
and for button_2 press, only the LED connected to that must glow(rest must turn off if already on)

int button_1 = 7 , button_2 = 12;
int buttonState_1, buttonState_2;
void setup()
{
  Serial.begin(9600);
  pinMode(button_1,INPUT_PULLUP);  // Enabling internal pullups
  pinMode(button_2,INPUT_PULLUP);  
}
void loop()
{
  // Reading button states
  buttonState_1 = digitalRead(button_1);
  buttonState_2 = digitalRead(button_2);

  // Printing for Debugging
  Serial.print("buttonState_1 = "); 
  Serial.println(buttonState_1);  
  Serial.print("buttonState_2 = "); 
  Serial.println(buttonState_2);

  if(buttonState_1 == 0)   // Button 1 is pressed. Switch shorted with ground
  {
    // If this button is pressed, the rest of the buttons (button 2 in trial case) should go off
    pinMode(button_2,INPUT);
    digitalWrite(button_2,HIGH); // these two statements must ideally turn off the LED in other pins or does it?
    
    pinMode(button_1, OUTPUT); // Change from Input to Output Mode
    digitalWrite(button_1,LOW);  // Write Low in the pin so that pin continues to glow even after button press is released 
  }

  if(buttonState_2 == 0)   // Button 2 is pressed. Switch shorted with ground
  {
    // If this button is pressed, the rest of the buttons (button 1 in trial case) should go off
    pinMode(button_1,INPUT);
    digitalWrite(button_1,HIGH); // these two statements must ideally turn off the LED in other pins or does it?
    
    pinMode(button_2, OUTPUT); // Change from Input to Output Mode
    digitalWrite(button_2,LOW);  // Write Low in the pin so that pin continues to glow even after button press is released 
  }
  delay(50); 
}

Here is the output results I get(buttons connected pins 7(button_1) and 12(button_2))

case (1):
when button_1 is pressed, LED 1 turns on and stays turned on.
After that if button_2 is pressed, LED 2 turns on and stays turned on and LED_1 turns off.
If I press button_1 again. LED 1 turns on only for the time I press it and turns off when I release the button. and LED_2 does not turn off

case(2):
when button_2 is pressed LED 2 turns on and stays turned on.
If I press button_1 again. LED 1 turns on only for the time I press it and turns off when I release the button. and LED_2 does not turn off

So problem i guess starts when LED 2 turns on. It never turns off. (Its not a problem with my pins because I have tried changing them and still it works the same)

Can someone help figure out whats wrong here?

I think you need to keep track of the previous state of the buttons, and do things only if the current state is not the same as the previous state. As that code is now, the switch may appear pressed for many iterations of loop.

Why are you hung up on using a pin for both input and output? Is it that you don't have enough pins? How many inputs and how many outputs do you need?

As that code is now, the switch may appear pressed for many iterations of loop.

Even though this is the case here, shouldnt actually turn off LED 2 ?

Why are you hung up on using a pin for both input and output? Is it that you don't have enough pins? How many inputs and how many outputs do you need?

I am planning to implement 20 LED + button combos. So if I can make i work fine with a single pin I would be saving 20pins in my MEGA and more importantly reduce the number of wires that go into Arduino MEGA. So if there is no way I can get this method working then I would switch to the usual model of using 2 pins for each module.

Even though this is the case here, shouldnt actually turn off LED 2 ?

It seems like it should. Add some Serial.print() statements to find out why it doesn't.

Perhaps the thing that you need to do is turn the other pin(s) off, first, and then change them to input. Toggling the state of an input pin only turns on and off the pullup resistor, not the pin.

  if(buttonState_1 == 0)   // Button 1 is pressed. Switch shorted with ground

It's better to use the constants HIGH and LOW for switch state comparisons.

 if(buttonState_1 == 0)   // Button 1 is pressed. Switch shorted with ground
  {
    // If this button is pressed, the rest of the buttons (button 2 in trial case) should go off
    pinMode(button_2,INPUT);
    digitalWrite(button_2,HIGH); // these two statements must ideally turn off the LED in other pins or does it?
    
    pinMode(button_1, OUTPUT); // Change from Input to Output Mode
    digitalWrite(button_1,LOW);  // Write Low in the pin so that pin continues to glow even after button press is released 
  }

Its entering this if statement but not actually executing first 2 statements. (Or rather I cant see the effect happening anyway)

Perhaps the thing that you need to do is turn the other pin(s) off, first, and then change them to input. Toggling the state of an input pin only turns on and off the pullup resistor, not the pin.

Tried that already with a digitalWrite(button_2,HIGH); like

 if(buttonState_1 == 0)   // Button 1 is pressed. Switch shorted with ground
  {
    digitalWrite(button_2,HIGH);
    // If this button is pressed, the rest of the buttons (button 2 in trial case) should go off
    pinMode(button_2,INPUT);
    digitalWrite(button_2,HIGH); // these two statements must ideally turn off the LED in other pins or does it?
    
    pinMode(button_1, OUTPUT); // Change from Input to Output Mode
    digitalWrite(button_1,LOW);  // Write Low in the pin so that pin continues to glow even after button press is released 
  }

It didnt cause any change in the output...