A digital output pin has exactly two states, so it cannot produce half a volt of brightness. What it can do is switch very fast — thousands of times per second — and spend a controllable fraction of each cycle high. Average that over time and you get an effective voltage anywhere between 0 and 5 V. That technique is pulse width modulation, and it is how a digital device dims a lamp or slows a motor.
analogWrite(pin, value) takes 0 to 255, where 0 is always off, 255 is always on, and 128 is about 50% duty. The pin still only ever outputs 0 V or 5 V — a fast oscilloscope would show a square wave, not a steady level. It works because an LED's afterglow and your eye, or a motor's inertia, do the averaging for you.| Arduino C | What it does |
|---|---|
analogWrite(9, 0); | 0% duty — fully off |
analogWrite(9, 64); | About 25% duty, averaging 1.25 V |
analogWrite(9, 128); | About 50% duty, averaging 2.5 V |
analogWrite(9, 255); | 100% duty — fully on |
analogWrite(9, map(raw, 0, 1023, 0, 255)); | Drive PWM from an analog sensor reading |
Driving a DC motor
A motor cannot be connected to a pin. It draws hundreds of milliamps against the pin's 40 mA limit, and it is an inductive load: when current stops, the collapsing magnetic field generates a reverse voltage spike that can be many times the supply voltage. Two components solve both problems — a transistor to carry the current, and a flyback diode to absorb the spike.
- The Arduino pin connects through a resistor (about 1 kΩ) to the base of an NPN transistor — this limits base current to a few milliamps.
- The motor connects between a separate supply's positive rail and the transistor's collector.
- The transistor's emitter goes to ground.
- A flyback diode goes across the motor, reverse-biased — cathode to the positive side — so it does nothing normally and conducts the spike away when the motor switches off.
- The Arduino's ground and the motor supply's ground must be connected together, or the transistor has no shared reference and nothing works.
Reversing direction: the H-bridge
A single transistor can turn a motor on and off but not reverse it, because the current can only flow one way. An H-bridge is four switches arranged around the motor so that closing one diagonal pair drives it forwards and closing the other pair drives it backwards. Ready-made driver chips — L293D, L298N, DRV8833 — contain the bridge and the flyback diodes in one package, and are what you should actually use.
Servos
A hobby servo is not controlled by duty cycle — it is controlled by pulse width. It expects a pulse every 20 ms whose width encodes the target angle: 1.0 ms for 0°, 1.5 ms for 90°, 2.0 ms for 180°. Inside, a small closed-loop controller compares the commanded position with a potentiometer reading the actual shaft position and drives its motor until they match. That is why a servo holds its angle against a load, and why it is a genuine closed-loop system in miniature.
| Arduino C | What it does |
|---|---|
#include <Servo.h> | Include the servo library |
Servo arm; | Create a servo object |
arm.attach(9); | In setup: assign it to pin 9 |
arm.write(90); | Move to 90° — the library generates the pulse train |
arm.write(map(raw, 0, 1023, 0, 180)); | Drive the servo from a potentiometer |
Open and closed loop control
- Sends a command and assumes it worked
- No sensor measuring the result
- Simple, cheap, predictable
- A toaster timer, a plain DC motor run for 3 seconds
- Measures the result and corrects the command
- Requires a sensor on the output
- More complex, but handles disturbance and wear
- A thermostat, cruise control, a servo, a line-following robot
The practical test is simple: does anything measure whether the command actually worked? "Run the motor at 70% for two seconds" is open loop, and the distance travelled changes with battery voltage, load and floor surface. "Run the motor until the encoder counts 500 pulses" is closed loop, and it travels the same distance every time regardless. Feedback costs a sensor and some code, and buys you consistency.