Go Down

Topic: Reading and writing to a single digital pin (Read 5511 times) previous topic - next topic

000

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..

Code: [Select]

/*
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.

Code: [Select]
/*
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 : http://arduino.cc/forum/index.php/topic,148314.msg1116872.html#msg1116872

Krodal

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 ?

Code: [Select]

// 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);
}


PaulS

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.

Code: [Select]
  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.

UKHeliBob

Putting aside the complication of the electrical connections could that others have pointed out, could
Quote
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 ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Shpaget

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

UKHeliBob

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
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

000

Thanx for all your replies :)

@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 :)

@PaulS
Code: [Select]
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.
Quote
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.

Quote
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
Quote
Why go through all the trouble with the software when you can do this?

For obvious reasons of hardware requirement.

UKHeliBob



Quote
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.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

000

Quote
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?

GoForSmoke

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
http://www.arduino.cc/en/Reference/PortManipulation

and get... on an UNO I use 6 pins per port, the pin map explains why best:
http://arduino.cc/en/Hacking/Atmega168Hardware

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.



Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

000

@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?

GoForSmoke

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.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

PeterH


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.
I only provide help via the forum - please do not contact me for private consultancy.

000

@GoForSmoke 
Thanks for the tips. but don't think I can apply any of that here.
@PeterH
Quote
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??

PeterH


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?
I only provide help via the forum - please do not contact me for private consultancy.

Go Up