> 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/analogwrite.md).

# analogWrite()

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

MCU analog *output* pins can be used to author nonbinary voltages in a circuit, acting like rudimentary controllable voltage supplies.

## PWM Outputs

Most MCUs are not capable of directly authoring analog voltage signals, but can achieve a near-equivalent result using an onboard *PWM* generator.

*PWM* stands for *pulse-width-modulation.* Here, the board pulses a digital (i.e. $$0;\text{V}$$ or $$5;\text{V}$$, `LOW` or `HIGH`) signal rapidly, and by varying the duty cycle, changes the effective 'on time'.

To many devices - especially those with input smoothing or which read slowly, like multimeters - this pulsed PWM signal looks just like an analog signal of equivalent proportion - i.e. a 50% duty cycle, $$5;\text{V}$$ amplitude PWM signal provides an 'average voltage' of $$2.5;\text{V}$$.

<figure><img src="/files/qkp4OUPCqTAYNOS2o9yr" alt=""><figcaption></figcaption></figure>

MCUs do this for versatility - it is relatively trivial to convert a PWM signal to a true analog waveform where needed (see [#smoothing](#smoothing "mention")), but hard to do the inverse.

{% hint style="info" %}
:man\_mage: **Important:** Most Arduino-based MCUs have an 8-bit output resolution (i.e. 256 steps). Consequently, the duty cycle of a PWM output can be controlled from $$0%-100%$$ over `0-255` steps.
{% endhint %}

### `pinMode()`

To use an analog output pin, you should first set it to `OUTPUT` mode. While on some MCUs this is not necessary, 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 3 as an output.
  pinMode(3, OUTPUT);
  // Setup the Serial Monitor for later
  Serial.begin(9600);
}
```

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

### `analogWrite()`

After the mode is set, the pin voltage waveform can be set. The `analogWrite()` function expects a pin number and duty cycle (`0-255`) as arguments:

```arduino
void loop() {
  // Write a PWM wave to PIN 3 with ~10% duty cycle
  analogWrite(3,25);
  // Wait for 3 seconds
  delay(3000);
  // Write a PWM wave to PIN 3 with ~50% duty cycle
  analogWrite(3,127);
  // Wait for 3 seconds
  delay(3000);
  // Write a PWM wave to PIN 3 with ~100% duty cycle
  analogWrite(3,250);
  // Wait for 3 seconds
  delay(3000);
}
```

You can `analogWrite()` in the `setup()` function to set 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/analogwrite/>" %}

## Complete Sample Code

{% code overflow="wrap" %}

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

void loop() {
  // Write a PWM wave to PIN 3 with ~10% duty cycle
  analogWrite(3,25);
  // Wait for 3 seconds
  delay(3000);
  // Write a PWM wave to PIN 3 with ~50% duty cycle
  analogWrite(3,127);
  // Wait for 3 seconds
  delay(3000);
  // Write a PWM wave to PIN 3 with ~100% duty cycle
  analogWrite(3,250);
  // Wait for 3 seconds
  delay(3000);
}
```

{% endcode %}

<figure><img src="/files/9XM9xzHbGAM31zWDkYs8" alt=""><figcaption><p>An Arduino creates a pulsed (PWM) signal. The slow-acting multimeter sees this as a steady voltage (with some noise), but the oscilloscope shows the true output signal is a square wave of varying duty cycle.</p></figcaption></figure>

## Pratical Considerations

### Smoothing

A true analog waveform can be generated relatively easily from a PWM signal using a simple [RC low-pass filter](https://en.wikipedia.org/wiki/Low-pass_filter) (i.e. a resistor in series with, and capacitor in parallel with the output):

<figure><img src="/files/pELfrMkdCvZLurg1UVu5" alt=""><figcaption><p>An Arduino running the same code as before, but with an RC filter in-line with the output. The slow-acting multimeter more-or-less reads the same values as before, but the oscilloscope shows the output signal has been smoothed to a reasonably constant output. Note that unlike the previous example the y-axis on the scope is autoscaling as the voltage changes.</p></figcaption></figure>

{% hint style="info" %}
:man\_mage: **Important:** Introducing a low-pass RC filter into your circuit might smooth an output signal, but can also introduce a *delay* and *trim*. You should carefully specify the resistance and capacitance of the filter to achieve a good smoothing while considering these effects.
{% endhint %}
