digitalRead() return value, please advise variable type

hi all

Question:
What is the variable type returned by the digitalRead() function?

digitalRead()
[Digital I/O]
Description
Reads the value from a specified digital pin, either HIGH or LOW.

Syntax
digitalRead(pin)

Parameters
pin: the Arduino pin number you want to read

Returns
HIGH or LOW

example shows function return value variable as an integer?

int ledPin = 13;  // LED connected to digital pin 13
int inPin = 7;    // pushbutton connected to digital pin 7
int val = 0;      // variable to store the read value

void setup() {
  pinMode(ledPin, OUTPUT);  // sets the digital pin 13 as output
  pinMode(inPin, INPUT);    // sets the digital pin 7 as input
}

void loop() {
  val = digitalRead(inPin);   // read the input pin
  digitalWrite(ledPin, val);  // sets the LED to the button's value
}

Note

Use ‘type’ byte (same as uint8_t)

It returns an int. Here is the source code:

int digitalRead(uint8_t pin)
{

It depends on the clothes that you wear.
If you like loose oversided clothes, then use int.
If you like slim Italian fit clothes, then use byte.

They are in the "Arduino.h" file. For an Arduino Uno that is this: ArduinoCore-avr/Arduino.h at master · arduino/ArduinoCore-avr · GitHub.

int digitalRead(uint8_t pin);
void digitalWrite(uint8_t pin, uint8_t val);

It returns an int, but if you use it for digitalWrite(), then it might just as well be a byte because the parameter 'val' is HIGH or LOW and that is a byte.

It depends also on the reason you are asking... I decided a literal answer would suffice.

To make things worse, on the megaavr core (used for the Nano Every and UNO WiFi Rev 2), digitalRead() returns an enum, PinStatus. That caused all sorts of compatibility problems. Note that only the LOW and HIGH would be applicable to digitalRead(), the rest are used elsewhere.

 typedef enum { 
   LOW     = 0, 
   HIGH    = 1, 
   CHANGE  = 2, 
   FALLING = 3, 
   RISING  = 4, 
 } PinStatus; 



PinStatus digitalRead(pin_size_t pinNumber);

Can you explain that a bit more? I don't see how a pin can have a status of change, falling or rising. Also, falling and rising are also change, so which do you get? Doesn't make sense.

PerryBebbington:
Can you explain that a bit more? I don't see how a pin can have a status of change, falling or rising. Also, falling and rising are also change, so which do you get? Doesn't make sense.

I think those are used for attachInterrupt(), and would never be returned from digitalRead(). What really broke a lot of library code was using PinStatus for digitalWrite(), so that HIGH and LOW would work, but 0 and 1 would not.

The type returned is not specified in the documentation.
It is essentially opaque and not guaranteed to be any particular type.

The only thing you can do that will ensure it works and is portable across IDE versions, and platforms is to use it as it is documented.

That means you can only compare the return against HIGH or LOW.

Do not assume that the return value is a particular type nor attempt to assign the return value to a particular type.
Do not look at the underlying code implementation and use the type specified in the code as that is abusing the API by using information that is outside the formal documentation and is not guaranteed to work across all implementations.

Just compare the return value to HIGH or LOW. That is the only thing that is assured to work.

Yeah it sucks, but that is the way it is.

In your specific case you could do this:

void loop() {
  digitalWrite(ledPin, digitalRead(inPin));  // sets the LED to the button's value
}

This is allowed since the return value of digitalRead() is HIGH or LOW and the parameter to digitalWrite() is also HIGH or LOW so they are guaranteed to be compatible.

--- bill

PerryBebbington:
Can you explain that a bit more? I don't see how a pin can have a status of change, falling or rising. Also, falling and rising are also change, so which do you get? Doesn't make sense.

digitalRead() will only return HIGH or LOW.

digitalRead() is allowed to use any type and any values for HIGH and LOW since the documentation never specifies their type or values.
i.e. HIGH could be 42 and low could 1 and still be conformant to the digitalRead() documentation.

Many users make assumptions that the return value is an integer type and that HIGH is 1 and LOW is 0, possibly after even looking at the code for a particular implementation, but there is no requirement for the values of HIGH and LOW to be anything.

What we see in the megaavr core is an implementation that made a different choice for the type and value of HIGH and LOW and just happened to combine their definitions with some other symbols.
While it may not be what some people expect, it is still conformant with the digitalRead() documentation.

This is why there should be no assumptions about what the type of values of HIGH and LOW are.

In fact an implementation could chose to make LOW 0 and HIGH 255 and on digitalWrite() any value between 1 and 254 could be PWM output on the pin.
That implementation would still be compliant and fully backward compatible with the current digitalRead() and digitalWrite() documentation.

The proper way to write your code is to conform to the official API documentation which means making no assumptions about the type or specific values of HIGH or LOW.
If you don't make assumptions that are outside the official documentation, the code will be portable on all Arduino platforms and will have no issues with the megaavr core implementation.

--- bill

Thanks for the explanation.

Is this reliable:

If (digitalRead(somePin)) ...

I would expect that to be true if the pin is high. What you have said casts doubt on that.

PerryBebbington:
Thanks for the explanation.

Is this reliable:

If (digitalRead(somePin)) ...

I would expect that to be true if the pin is high. What you have said casts doubt on that.

bperrybap is of course quite right - it's foolish to rely on what you know about how something is implemented and the strictly correct way to do that is to compare the result to HIGH.

However, in practical terms I would always expect that to work and if it didn't I would suspect that I had a corrupted IDE or toolchain before I would conclude that the definitions of HIGH and LOW had changed.

PerryBebbington:
Thanks for the explanation.

Is this reliable:

If (digitalRead(somePin)) ...

I would expect that to be true if the pin is high. What you have said casts doubt on that.

You have assumed that digitalRead() is required to return a non zero value when a pin is high.
Even if you looked at the code for a specific platform to see that it does, the API documentation makes no such guarantee so a platform implementer does not have to implement it this way.
As such, code that makes that assumption is not guaranteed to be portable across all implementations.

It will likely work, but it isn't guaranteed to work, since is not conforming to the documentation which simply says that digitalRead() returns HIGH or LOW and is silent on anything else such as the type or value of those symbols.

The proper way to ensure full portability be:

If (digitalRead(somePin) == HIGH) ...

It can be even more tricky for digitalWrite()

Suppose you pass in a non zero value to digitalWrite() but it is not the specific value of HIGH.
Depending on how the code is implemented, it may or may not work as you intended to set the pin high.
For example, suppose you have some code that uses bits in a lookup table to set the state of a pin where 1 bits set the pin high and zero bits set the pin low.

To "optimize" the code, you simply mask the value from the bit table down to the desired bit and pass that masked value as the value parameter to digitalWrite()
digitalWrite() will receive a zero when the bit is not set, and some power of 2 value when a bit is set.

If the digitalWrite() code is implemented like this:

        if (val == LOW)
                // set pin low
        else
                // set pin high

it will work.

If it happens to be implemented like this:

        if (val == HIGH)
                // set pin low
        else
                // set pin high

If HIGH does not match the value of your non-zero value, you will get a low pin for all non-zero values other than the one that matches HIGH.

This "mess" was created by some sloppiness from the arduino.cc team in their APIs and API semantics.
From the very earliest days, they were not very good at defining the APIs and corresponding documentation.

Most peoples assumption is that the digital i/o functions like digitalRead() and digitalWrite() operate based on zero vs non-zero values and that HIGH and LOW are simply convenience symbols and so lots and lots of code as been written with that assumption (which according to the documentation is not guaranteed to be correct)

This all came to a head with the megaavr platform which decided to take advantage of creating types for the HIGH and LOW symbols for type checking of the parameter. While it is allowed, I'm not sure that the type checking is worth it at this point given all the existing code that was improperly written that breaks when this is done.
In fact in the megaavr platform they ended up creating some compatibility function overloads that will allow existing code that abused the API to continue to work.
So at this point, having HIGH and LOW as enums is pretty much pointless.

Given the incorrect assumptions that so many people have made and written code around those assumptions over the years, my recommendation would be just give up and re-document digitalRead() and digitalWrite() to work the way people have assumed they work. i.e. zero means low and non-zero means high.

This would not break any existing code and would ensure that all platforms implement it consistently, which is not assured at this point.
But as of today, the only way to ensure portability is to not assume anything about the symbols HIGH and LOW.
i.e. write code that never takes short cuts and always compares against those values or always passes in one of those values.

--- bill

Thank you Bill.
++Karma;

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.