33

I have a very simple test sketch in which I'm trying to set a pin to HIGH and then read its state with digitalRead. Here is my sketch.

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    delay(1000);

    pinMode(3, OUTPUT);
    digitalWrite(3, HIGH);
    delay(1000);

    pinMode(3, INPUT);
    Serial.println(digitalRead(3));
}

Serial monitor result:

0
0
0
0

I have come to understand that changing the pinMode will stop it from being HIGH. So setting a pin to HIGH in OUTPUT mode and then changing to INPUT mode will change it to LOW. So the digitalRead will always return 0. If I don't change the pinMode it won't be able to read the pin. So how can I read the current setting of a pin that is in OUTPUT mode without losing the value?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bazzz
  • 26,427
  • 12
  • 52
  • 69
  • 1
    I think best practice is to keep track of the pin states, if needed, using variables in your program. I assumed this was for efficiency reasons. – Zaz Nov 23 '15 at 23:09

11 Answers11

37

In this case you just want to access the data register itself.

PORTB and PORTD registers contain the pin data you are looking for. I finally got access to an Arduino to figure it out. You want to use bitRead(PORTD, pin).

Serial.println(bitRead(PORTD,3)); //Reads bit 3 of register PORTD which contains the current state (high/low) of pin 3.

Reference Bit Read Operation for more information.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MikeRags
  • 402
  • 3
  • 4
  • This indeed sounds promising. I'll have a look at this later today, when I'm back home from work. Thanks for your answer. – Bazzz May 30 '11 at 07:01
  • unfortunately I didn't manage to get it working. `Serial.println(PORTD.3);` doesn't compile so I tried `Serial.println(PORTD);`, unfortunately this either produces an empty line when all pins are LOW, or a line with one | (I think pipe) character, when pin 2,3,4,5,6 are HIGH. I haven't tried other combinations of pins HIGH and LOW yet. – Bazzz May 30 '11 at 19:10
  • I believe the 8 bits of output from PORTD are being interpreted as one character in the Serial println. Is there a way to cast/convert the output of PORTD into an array of booleans? Then I can use this array to poll the individual pin states. – Bazzz May 31 '11 at 05:57
  • Bazzz I updated the answer above. You want to use bitRead( PORTD,3). To poll the status of pin 3. I have confirmed this works on an Arduino – MikeRags May 31 '11 at 13:59
  • This only works for those Arduino variants where pin 3 is actually mapped to bit 3 of Port D. – Udo Klein Sep 16 '13 at 10:57
  • It should be noted that PORTD maps to digital pins 0-7, while PORTB maps to digital pins 8-13, as explained in this reference: http://www.arduino.cc/en/Reference/PortManipulation – Eric Nov 25 '14 at 00:28
  • It also should be noted that direct port manipulation breaks the Arduino abstraction and will not work for most "compatible" platforms, including Arduino Due. Port manipulaiton should only be used under extreme performance pressure. Otherwise this should be avoided. – Udo Klein May 21 '15 at 05:01
35

Your sketch should be

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    delay(1000);

    pinMode(3, OUTPUT);
    digitalWrite(3, HIGH);
    delay(1000);

    // pinMode(3, INPUT); // get rid of this line
    Serial.println(digitalRead(3));
}

That's all. Then it reads the pin's state which in your case is "HIGH". If you set the pinMode to input it will read the input depending on what is connected. If you are writing "HIGH" to an input pin the internal pullup will be activated. It does not matter if you write HIGH before setting it to input mode or after setting it to input mode. Unless of course you are driving a load that is to high for the output pin (e.g. a switch to ground). Then this would probably kill the pin.

If you have written a low and set the pin to low it might float which may lead to any kind of unpredictable behaviour.

Udo Klein
  • 6,784
  • 1
  • 36
  • 61
  • Simple and works perfectly. Since I was wondering: this works also fine with pin13 (the onboard led) – Niko Nov 27 '15 at 09:20
  • Much simpler than the accepted answer. Note however that this only works on AVR-based Arduinos, does not work on Zeros or Dues (which are ARM-based). HTH – Jerzyna Apr 17 '16 at 11:53
  • 2
    You mean the accepted answer does not work on ARM based Arduinos. Of course not. My answer does. – Udo Klein Apr 20 '16 at 07:01
  • It's unfortunate that this behavior is not documented in the Arduino language reference – Stephen C Feb 12 '18 at 22:48
  • I would argue that it actually is documented. However the documentation does not explicitly state that this works in any pin mode. On the other side it also does not even give the closest hint that it might not work. If you really think the documentation should be improved: this is an open source project. Just contribute a sentence to the documentation. – Udo Klein Feb 14 '18 at 06:09
4

Didn't like any of the previous answers, because they would not be cross-arduino-platform compatible. You need to access through the pin reference tables. The following expression does the trick.

bool value = (0!=(*portOutputRegister( digitalPinToPort(pin) ) & digitalPinToBitMask(pin)));

Let me break that down for better understanding

digitalPinToPort(pin) look up you the gpio bank [port] that the pin is assigned to on your selected hardware

portOutputRegister(...) gives you a pointer to the port containing the value you are looking for. * dereferences the pointer and gives the full value of all 8 pins assigned to that port. It is not yet uniquely useful, but the bit you are looking for is in there.

&digitalPinToBitMask(pin) selects only the bit you are interested in for the pin, all other bits will be zero.

0!= tests to see if the resulting expression is zero, or something else. If it is zero, then your output is zero on that pin. Otherwise the output is one.

Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123
  • perfect solution. That really returns the "intendet" port level and not the actual port level! (digital read may detect a low if the gpio is turned on - depending on the load that puls the level down) – dognose May 26 '23 at 16:07
3

Keep your pinMode() selection in the setup() function, and try the digitalWrite() and digitalRead() functions.

setup() will be executed when controller starts and loop() will be the function which keep executing.

int pin22 = 22;
void setup()
{
  Serial.begin(9600);
  pinMode(pin22,output);
}

void loop()
{
  digitalWrite(pin22,HIGH);
  digitalRead(pin22);
  digitalWrite(pin22,LOW);
  digitalRead(pin22);
}
Greenonline
  • 1,330
  • 8
  • 23
  • 31
AMPS
  • 319
  • 3
  • 11
3
digitalWrite(3,HIGH);
digitalRead(3);
Mark Parnell
  • 9,175
  • 9
  • 31
  • 36
msj003
  • 96
  • 7
2

Why do you want to do that? If you are doing this to validate that the pin is really high, this will not confirm it to you, because maybe there is a short circuit on the high pin from the external circuit, the best way is to create a feedback through another pin; configure another pin as input, and connect the output pin to the new input pin, and read its value. Reading the internal register will always return for you what the controller is trying to put on the pin, not the actual pin value.

Karim
  • 1,526
  • 4
  • 13
  • 16
  • 2
    I do it all the time. Otherwise you need a status variable to remember the pin status. But with status variables you never are sure. Maybe the pin is really HIGH, maybe not. You may have forgotten to change the variable in some part of your code. Bottom line: you better check the pin directly. –  Jun 15 '17 at 16:33
0

I wrote a routine for flashing four different LEDs for different purposes but I also wanted to retain their initial state before I flash them, as their steady state also tells me something is occurring in my code, so here is my Flash code, you call it by sending the pin number, the number of times to flash it and how long to flash it for.

inline void Flash (byte pinNum, byte times, byte flashSpeed)
  {
    bool state;                     // Local var for State of pin
    state = digitalRead(pinNum);    // Read the current state as set elsewhere
    int x;                          // Local var for repeat flash
    for (x = 0; x < times; x++)
      {
        digitalWrite(pinNum, HIGH); // Turn on LED
        delay(flashSpeed);
        digitalWrite(pinNum, LOW);  // Turn off LED
        delay(flashSpeed * 2);      //  leave off twice as long as on
      }                             //  due to persistence of Vision   
    digitalWrite(pinNum, state);    // Restore the original state of the LED
  }
KeyWizard
  • 11
  • 1
0

Keep a separate boolean map of the output pin states.

If a microcontroller GPIO pin is set as an input, then its value, when read, depends on what it's connected to externally. That's kind of the point.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Martin James
  • 24,453
  • 3
  • 36
  • 60
  • indeed the boolean map is a feasible idea, but I feel that it might be able to get out of sync with reality. Also suppose I have a led at pin 3 and I use `digitalWrite(3, HIGH);` the led remains on forever. I assume Arduino has an internal array of settings per pin to know whether to keep the led on or not. I would like to reference that internal array, if possible, instead of keeping my own array. – Bazzz May 28 '11 at 18:56
0

Are you trying to set the default input to HIGH?
If so you are looking to activate the pull-up register:

void setup() 
{
    Serial.begin(9600);
}

void loop() 
{
    delay(1000);

    pinMode(3,INPUT);         // default mode is INPUT  
    digitalWrite(3, HIGH);    // Turn on the internal pull-up resistor, default state is HIGH  

    delay(1000);
    Serial.println(digitalRead(3));
}

Excerpt from DigitalWrite:

If the pin is configured as an INPUT, writing a HIGH value with digitalWrite() will enable an internal 20K pullup resistor.

ssapkota
  • 3,262
  • 19
  • 30
  • 1
    thank you for your answer, but I'm not trying to set the default input to HIGH, sorry. I'm trying to read the current state of the pin when it is in OUTPUT mode. – Bazzz May 28 '11 at 18:58
  • Anyway, Why do you need to read on OUTPUT pin? In output Mode, you are meant to write on it. – ssapkota May 29 '11 at 05:22
  • suppose I have a led on pin 3, I would like to ask Arduino whether the led is on or off. – Bazzz May 29 '11 at 08:04
  • In that case, I guess you have already got the answer from @Martin. – ssapkota May 29 '11 at 09:16
  • @ssapkote, I don't completely agree, in Martin's answer I ask my own array of booleans whether I previously set the boolean to true. Frankly, I would like to ask Arduino whether it is ACTUALLY feeding my led. – Bazzz May 29 '11 at 19:08
-1

ALways keep in mind. If you are trying to Configure anything ,Just keep it in setup file. Since setup file get executed once , If you are setting In loop . it execute continuous.and try to keep it remain it start state.That is active low state

AMPS
  • 319
  • 3
  • 11
-2

You can try:

int Pin22 = 22;
int valuePin22 = 0;

void setup() {

    pinMode(Pin22, OUTPUT);
    digitalWrite(Pin22, LOW);

}

void loop() {

    digitalWrite(Pin22, HIGH)
    valuePin22 = 1;
    Serial.println(valuePin22);
    delay(100);

    digitalWrite(Pin22, LOW)
    valuePin22 = 0;
    Serial.println(valuePin22);
    delay(1000)

}
novecapa
  • 135
  • 1
  • 5