What does declaring a pin INPUT or OUTPUT actually do?

I'm using the standard 7-segment display and would like to check the status (HIGH or LOW) of a specific segment. This implies that the pin is both OUTPUT (so it can be set to HIGH or LOW) and also INPUT (so a subsequent read can determine its current state)

The code below fails since it returns 1 regardless of the HIGH/LOW state of the pin.

This leaves me with several questions:

  1. What does pinMode (pin, mode) actually do? Is it effectively commentary -- declaring your intention -- or does it actually set the hardware to accept Write but not Read?

  2. Is there a way to do what I'm trying to do? I can track the segment status in the code but that does not the same as actually testing the real status of the segment.

Hardware:
Uno R with the segment display connected to pins 0 through 7 (7 segments plus decimal point).
Pin1 is actually connected to segment B of the display -- the documentation for digitalRead indicates that results are random if pin is not connected.

Attempts:

The initial code set the pin mode to output and then wrote HIGH. The read returned 1 (HIGH) then set the pin LOW but the read continued to return HIGH.

Since the fail could have been reading from an output pin the second attempt resets the pinMode to INPUT prior to the read attempt. The pin still reads HIGH in both cases.

Rather than continue to beat this horse I'm asking if anyone knows. If not I'll continue to test.


#define WaitTime  100

void setup() {
 
int iReadVal = 100;         // Set up return value
delay(WaitTime);
Serial.begin(9600);
delay(WaitTime);
Serial.print("Value of HIGH = ");
Serial.print(HIGH);
Serial.print (" ----  Value of LOW = ");
Serial.println (LOW);
Serial.println ("Setting Pin 1 to output");
pinMode(1, OUTPUT);
delay(WaitTime);
Serial.println (" Setting PIN1 HIGH");
digitalWrite(1, HIGH);
delay (WaitTime);
Serial.println (" Attempting to read Pin1");
delay(WaitTime);
pinMode(1, INPUT);
iReadVal = digitalRead (1);
delay(WaitTime);
Serial.print (" Status of Pin1 = ");
Serial.println (iReadVal);

Serial.println (" ---- Setting Pin1 LOW ");
pinMode(1, OUTPUT);
digitalWrite(1, LOW);
delay (WaitTime);
Serial.println (" Attempting to read Pin1");
delay(WaitTime);
pinMode(1, INPUT);
iReadVal = digitalRead (1);
delay(WaitTime);
Serial.print (" Status of Pin1 = ");
Serial.println (iReadVal);

}

void loop() {}

The output is:

Value of HIGH = 1 ----  Value of LOW = 0
Setting Pin 1 to output
 Setting PIN1 HIGH
 Attempting to read Pin1
 Status of Pin1 = 1
 ---- Setting Pin1 LOW 
 Attempting to read Pin1
 Status of Pin1 = 1

1 Like

Yes, don't use pins 0 or 1 as they are also tied to serial..
Start on pin 2..

good luck.. ~q

2 Likes

In a way. In output mode, you can control the state of the output pin (HIGH or LOW), and read that state back.

In input mode, the voltage on the pin, as set by an external device, determines the state that you read.

The details are fully explained in the microprocessor data sheet.

2 Likes

Acting on qubits' suggestion I changed the code from Pin 1 to Pin 2. The code still fails but now returns LOW in both cases rather than HIGH. I confess to confusion.

Setting Pin 2 to output
 Setting PIN 2 HIGH
 Attempting to read Pin 2
 Status of Pin 2 = 0
 ---- Setting Pin 2 LOW 
 Attempting to read Pin 2
 Status of Pin 2 = 0

Revised Code:


#define WaitTime  100
#define UsePin 2

void setup() {
 
int iReadVal = 100;         // Set up return value
delay(WaitTime);
Serial.begin(9600);
delay(WaitTime);
Serial.print("Value of HIGH = ");
Serial.print(HIGH);
Serial.print (" ----  Value of LOW = ");
Serial.println (LOW);
Serial.println ("Setting Pin 2 to output");
pinMode(1, OUTPUT);
delay(WaitTime);
Serial.println (" Setting PIN 2 HIGH");
digitalWrite(2, HIGH);
delay (WaitTime);
Serial.println (" Attempting to read Pin 2");
delay(WaitTime);
pinMode(2, INPUT);
iReadVal = digitalRead (2);
delay(WaitTime);
Serial.print (" Status of Pin 2 = ");
Serial.println (iReadVal);

Serial.println (" ---- Setting Pin 2 LOW ");
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
delay (WaitTime);
Serial.println (" Attempting to read Pin 2");
delay(WaitTime);
pinMode(2, INPUT);
iReadVal = digitalRead (2);
delay(WaitTime);
Serial.print (" Status of Pin 2 = ");
Serial.println (iReadVal);

}

void loop() {}

You forgot to tell us which Arduino you have (Uno R is ambiguous), and what is connected to it. Please provide all the details required to understand your setup.

This is obviously wrong:

Serial.println ("Setting Pin 2 to output");
pinMode(1, OUTPUT);

um..
you are using this pin as an output you don't need to switch pinMode to digitalRead, leave it as an output..

~q

Sorry -- It is an R3

to toggle an output without caring for it's value..

digitalWrite(2,!digitalRead(2));

You can't use pins 0 and 1 for the display. They are used by the serial port.

I fixed the incorrect reference to PIN 1 and eliminated the pinMode(2, INPUT) and things work correctly.

Setting Pin 2 to output
 Setting PIN 2 HIGH
 Attempting to read Pin 2
 Status of Pin 2 = 1
 ---- Setting Pin 2 LOW 
 Attempting to read Pin 2
 Status of Pin 2 = 0
1 Like

Depends on whether you have it as active high or low.
Either way, segment would light up on one or the other.
Where is the problem?

The display lights correctly -- I'm really playing with the Arduino to learn what it does. The actual question was can I test an output pin to determine its status or do I need to track the status in the program and trust I won't get out of sync? The 7 Segment display is incidental to the process -- I needed to have something connected and that's what's on the breadboard at the moment.

Thank everyone for the help.

Yes.

If the pin status is not what you set (e.g. LOW when it should be HIGH), there is a serious problem that must be fixed immediately, or the Arduino will be destroyed.

Does your circuit include the required current limiting resistors for each display segment?

One of two possible wiring configurations, for a "common anode" display.

But you are the one writing to the pin, so keeping your own track of what you yourself did without "getting out of sync" doesn't seem like a terribly difficult thing to do.

On some other microprocessor you might have to do this.

a7

The circuit does have the current limiting resistors. I'm random but not reckless.

To answer both you and alto777 -- Yes, this is a simple application and tracking the pin status is simple because pin status is only changed by one of two (On and Off) functions. I'm anticipating more complex code with multiple authors (we have a project planned) and I'm definitely in the Reagan camp with "Trust but verify".

I write paranoid code. It includes a narrative of what's going on and routinely tests inputs before acting. Using #ifdef/#endif lets me painlessly remove the code once the project is running correctly and reinstate it should problems develop. I find it easier to include debugging code from the beginning rather than trying to retrospectively insert it when something fails. Toward this end I wanted to know if I could test an OUTPUT pin to determine the status.

In the current application it's swatting flies with a Buick, but knowing what is possible will simplify my life later.

Thanks for the help.
Glenn

Thanks for the reminder that this is open source and the code is visible. I'm used to dealing with "Black Boxes" with thin documentation and I forget that this environment is much more transparent.

The processor allows to use a port pin alternately as input and output. Electrically this is dangerous, if not timed right both ends of the connecting wire may be driven in opposite direction, blowing each other up. But if the pin is switched to input and the connecting wire is not driven by the other side, the value is undetermined.

The ATmega328, and I suppose most microcontrollers, can read the input register even if the pin is programmed as output. In some respect it’s nonsense to read back the value of an output as you did set it in the first place.

The Arduino IDE provides digitalWrite() and digitalRead(), addressing the output register and the input register respectively. Some programmers opt to use the port pin as memory bit instead of using a variable in RAM.

There’s another nasty property of the ATmega328: it uses it’s output register to switch the pull-up resistor on and off when the pin is used as input. In normal use this is no problem, but it is when using the port pin alternately as input and output.

Thank you, I would not have thought to check for a nasty property.

You too can guard against this eventuality, if you must play 'turn around' games with your pins - place a 220 ohm resistor between the two pins that are "sometimes input, sometimes output", and the hardware developer can sleep at night, knowing his "less adroit" software brothers and sisters have no opportunity to ruin his day. The signaling pin-pin will still work reliably when one pin is input, one is output, but output-output can't make smoke.

1 Like

I think you learned new things with this thread.
The most direct answer is

digitalRead(myOutputPin); 

delivers the actual value.

Anyway you should write code and TEST code in a way that you will never be in the situation of not beeing able to understand why an OUTPUT-pin is set HIGH while you expect this OUTPUT-pin to be in state LOW and vice versa.

The best way to do this is to write code that does consequently

  • use parameters
  • uses return-values
  • limits the scope of variables to the smallest scope possible

If a variable is only used in one particular function declare this variable inside this function
If you need the value over multiple function-calls declare it with attribute static

If a variable is unknown in some function because of the limited scope this function is unable to modify this variable. The compiler will complain "out of scope"

Using parameters for everything makes sure you have control over the value
that is used when calling the function.

using return-values makes sure you got the value from this function-call (and the value can't been changed by some other function at least in the moment you "handover" the value to the variable at this line of code).

structure your code into functions where each and every function does one single thing
and the name of the function explains spot-on what this one thing is.

Here is a WOKWI simulation that demonstrates digitalRead on an output pin

best regards Stefan