> For the complete documentation index, see [llms.txt](https://monasheng.gitbook.io/zerotohero/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://monasheng.gitbook.io/zerotohero/arduino-zero-to-hero/core-skills/input-output-pins/analog-pins/analogread.md).

# analogRead()

{% embed url="<https://youtu.be/3hiZhaZ5j3o>" %}

MCU analog *input* pins can be used to read variable voltages in a circuit, acting like rudimentary, discrete oscilloscopes.

## Analog to Digital Converters and Resolution

MCUs typically achieve this using a built-in ['analog to digital' converter](https://learn.sparkfun.com/tutorials/analog-to-digital-conversion/all) circuit, or *ADC*. ADCs have a *resolution*, meaning that they can only identify finite, discrete steps between `LOW` and `HIGH`. Voltages between discrete steps are essentially rounded to the nearest ADC step before output.

ADC resolution is normally talked about in terms of *bits* - i.e. binary states. A pretty bad ADC might be e.g. 2 bit - i.e. capable of representing $$2^2=4$$ unique steps over it's input range.

<figure><img src="/files/rTZtqFxY2rE8xThuyz8L" alt=""><figcaption><p>With only <span class="math">2^2=4</span> steps of resolution, the underlying input voltage trace (blue) is approximated poorly by the stepped/discretised ADC input (purple).</p></figcaption></figure>

The ADCs on most Arduino MCUs have 10-bit resolution, meaning they can identify $$2^{10}=1024$$ voltage steps in their $$0-5;\text{V}$$ input range - a very respectable level of precision!

<figure><img src="/files/YVy9PmJW3pHaunkWE79h" alt=""><figcaption><p>With  <span class="math">2^{10}=1024</span> steps of resolution, the underlying input voltage trace (blue) is approximated well by the stepped/discretised ADC input (purple), though a close analysis reveals this input is still stepped.</p></figcaption></figure>

### `pinMode()`

To use an analog input pin for measurement, you should first set it to `INPUT` mode. While on some MCUs, pins will default to `INPUT` mode, it is best practice to be explicit in your code.

Mode definition is typically achieved in the `setup()`  function, as it only needs to be done once per boot. The `pinMode()` function expects a pin number and mode as arguments:

```arduino
void setup() {
  // Set PIN A0 as an input.
  pinMode(A0, INPUT);
  // Setup the Serial Monitor for later
  Serial.begin(9600);
}
```

{% embed url="<https://www.arduino.cc/reference/en/language/functions/digital-io/pinmode/>" %}

### `analogRead()`

After the mode is set, the pin voltage can be read. The `analogRead()` function expects a pin number as the only argument:

```arduino
void loop() {
  // Read the state of PIN A0, and print this to the serial monitor
  Serial.println(analogRead(A0));
  // Wait for 0.25 seconds
  delay(250);
}
```

You can `analogRead()` in the `setup()` function to query the initial/boot state of a pin, but this is usually done programmatically in the `loop()` function - often as a function of time/on a cycle.

{% embed url="<https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/>" %}

{% hint style="info" %}
:man\_mage: **Important:** The `analogRead()` function returns a raw ADC value, which depends on the resolution of your MCU. It **does not** return a measured voltage! For the Arduino Mega, this ADC value ranges between `0-1023`.
{% endhint %}

## Complete Sample Code

{% code overflow="wrap" %}

```arduino
void setup() {
  // Set PIN A0 as an input.
  pinMode(A0, INPUT);
  // Setup the Serial Monitor for later
  Serial.begin(9600);
}

void loop() {
  // Read the state of PIN A0, and print this to the serial monitor
  Serial.println(analogRead(A0));
  // Wait for 0.25 seconds
  delay(250);
}
```

{% endcode %}

<figure><img src="/files/ydnH6n35Uz4wyMq7ZKx9" alt=""><figcaption><p>A potentiometer (blue) provides a proportional output voltage on it's centre pin. This proportional output varies the voltages on the left- and right-hand-side pin voltages (GND and 5 V respectively in this case), depending on how far the knob is turned.</p></figcaption></figure>

## Converting to Voltage

`analogRead()` returns the raw ADC value, which maps between `HIGH` and `LOW` depending on the resolution of the board. To convert from an ADC value to a voltage, you can use the following formula:

$$
V\_\text{in}=\texttt{adcIn}\times \frac{V\_\text{nom}}{\texttt{res}}
$$

Where:

* $$V\_\text{in}$$ is the voltage seen by the input pin,
* $$\texttt{adcIn}$$ is the measured ADC value,
* $$V\_\text{nom}$$ is the operating voltage range of the input pin (e.g. $$5;\text{V}$$ for most Arduino boards), and,
* $$\texttt{res}$$ is the operating resolution of the MCU ADC (e.g. $$2^{10}=1024$$ for most Arduino boards).

| Board        | Vnom             | res                              | Practical resolution |
| ------------ | ---------------- | -------------------------------- | -------------------- |
| Arduino Mega | $$5;\text{V}$$   | $$\texttt{10 bit: }2^{10}=1024$$ | $$4.9;\text{mV}$$    |
| Teensy 4.0   | $$3.3;\text{V}$$ | $$\texttt{10 bit: }2^{10}=1024$$ | $$3.2;\text{mV}$$    |
| STM 32       | $$3.3;\text{V}$$ | $$\texttt{12 bit: }2^{12}=4096$$ | $$1.2;\text{mV}$$    |

```arduino
void setup() {
  // Set PIN A0 as an input.
  pinMode(A0, INPUT);
  // Setup the Serial Monitor for later
  Serial.begin(9600);
}

void loop() {
  // Read the state of PIN A0 and put it in a variable
  int adcIn = analogRead(A0);
  // Define the board parameters
  float vNom = 5.0;
  float res = 1024.0;
  // Calculate the voltage
  float Vin = adcIn * vNom/res;
  // Print this to the serial monitor
  Serial.println(Vin);
  // Wait for 0.25 seconds
  delay(250);
}
```

<figure><img src="/files/yYP1fZFrFsq16cHGo6rO" alt=""><figcaption><p>By applying the appropriate scale, we can force the Serial Monitor to display the actual potentiometer voltage.</p></figcaption></figure>
