analogRead() to digitalRead() Solution

I'm using a Nano. A0 and A5 can take digital and analog input/output, but found that A6 and A7 only takes analog input/output. I was trying to find how to convert from analogRead() to digitalRead() for pins A6 and A7. I didn't find any answers in the forums but did find a solution on YouTube. So I'm posting it here for anyone who doesn't look at YouTube videos.

Huge credit to Paul McWhorter: https://www.youtube.com/watch?v=5TitZmA66bI

Edit: this doesn't really work like digitalRead() instead 1 being LOW, and 3 being HIGH

1 Analog Pin

  int readPin = A6;
  int readVal;
  int V1 = 0;

void setup() {
  
  pinMode(readPin, INPUT); 
  Serial.begin(115200);
}

void loop() {
  readVal = analogRead(readPin);
  V1 = (5./1023.)*readVal; // Do not remove points
  Serial.print("A6: "); Serial.print(V1);
}

2 Analog Pins

  int readPin = A6;
  int readPin2 = A7;
  int readVal;
  int readVal2;
  int V1 = 0;
  int V2 = 0;

void setup() {
  
  pinMode(readPin, INPUT);
  pinMode(readPin2, INPUT); 
  Serial.begin(115200);
}

void loop() {
  // Delay needed if there's no resistor for A6 and A7
  readVal = analogRead(readPin);
  V1 = (5./1023.)*readVal; // Do not remove points
  Serial.print("A6: "); Serial.print(V1);

  //delay(1000);

  readVal2 = analogRead(readPin2);
  V2 = (5./1023.)*readVal2;
  Serial.print("  A7: "); Serial.println(V2);

  //delay(1000);
}

I don't see this as a replacement for digitalRead, without some thresholding (which should be expressed in raw readings, not "voltages") - all you've posted is how to convert an analogue reading to a voltage*
You really ought to add the caveat that it's around 25 times slower than a real digitalRead; you don't want to raise unattainable expectations.

(readPin and readPin2 ought to be of type "const byte", and "readVal", "readVal2", "V1" nor "V2" require global scope.

*

(5./1023.)*readVal;

really should be 1024. (Hard-hat time!)

1 Like

This is incorrect. digitalRead returns LOW on logical 0 and HIGH on logical 1. TTL levels in terms of Voltage are:
LOW: 0V-0.8V
HIGH: 2V-5V

Your method returns 0 when 0V-0.9999999V and 1 when 1V-5V

As was pointed out, much easier to just check the value read from the analog pin. You could use any value between 0 and 1023, depending on how you want to define the threshold between LOW and HIGH.

int digitalReadAnalog(const int pin) {
  if (analogRead(pin) < 512)
    return LOW;
  else
    return HIGH;
}
1 Like

Does 10bit ADC ever return 1024? It can’t can it? 1024 is not a value 10bit int variable can support, no?

No, it can't.
What's your point?

Thought it was obvious, you only going to get 5 when you multiply 5 by 1, and you only going to get 1 when you divide 1023 by 1023. you never going to get 1 if you divide 1023 by 1024. Any more questions?

But you can never get 5, because 1023 doesn't represent the reference voltage, it represents the reference voltage, minus 1 LSB.

For the full story, see the 328's datasheet, page 256, section 24.7.
They even give a formula.

You're welcome

How about:
(Uncompiled, untested)

// Threshold values taken from the 328 datasheet, section
// 30.2 DC Characteristics, for the typical range of Vcc in the 
// range 2.4 - 5.5V
// other processors / families may need different values.
// Note: This is an awfully slow substitute for digitalRead,
//            and makes no check to see if the pin provided
//            is a legitimate analogue pin.
int digitalReadAnalog(const uint8_t pin) 
{
  int pinVal = analogRead (pin);
  if (pinVal <= (0.3 * 1023))
    return 0;  
  if (pinVal >= (0.6 * 1023))
    return 1;
  return pinVal & 1;  // tongue-in-cheek indeterminate value.
}

It should return previous value until the threshold triggered. better save prev value in static var

The specifications are:
spec

You have a different datasheet than I have :smiley:

Mine's probably more up-to-date than yours; mine says "Microchip" at the bottom of the page, not "Atmel" :wink:
(Same formula, different section number)

The specifications of what?
Why the discussion about TTL?

spec

The electrical spefications/characteristics of the IO pins of ATmega328P MCU and it is for the information of @killzone_kid who has mentioned that VIH = 2V (Post-11) instead of 3V at Vcc = 5V.

The ADC can't ever measure the range 5.0V*(1024/1024) to 5.0V*(1025/1024). That may seem irrelevant, but in fact that is what a reading of 1024 would represent. Consider, that the range 5.0V*(0/1024) to 5.0V*(1/1024) is what is represented by a reading of 0.

The ADC partitions the input range into n partitions where n is the resolution of the ADC. By definition it can not represent either n, or zero.

When you scale an ADC range by a scalar voltage using n, it is correct because it scales a reading of (n-1) to the range Vs*(n-1) to Vs(n). That is because 0 is the 1st, and (n-1) is the nth partition.

For example, an input reading of 1023 is the 1024th partition, and if you calculate the input voltage with 5.0V1023/1024, the result corresponds to any input voltage between 5.0(1023/1024) and 5.0*(1024/1024) which is the specified behaviour of the ADC. Using any other divisor will not.

For what input voltage, a 10-bit ADC will assume 1010100010 when the Full Scale of the ADC is 5V?

ADC do not measure voltages. They measure voltage ranges.

1 Like

You mean that there is no answer to the question of Post-17 when the ADC's value is (theoretically) stable.

Only if you rephrase the question, "For what input voltage range..."