An Arduino pin cannot drive a motor directly. It sends two kinds of signal to a motor driver: a direction signal and a PWM signal for speed. This guide explains how a dual H-bridge driver such as the L298N takes those signals, how analogWrite() sets speed, and gives a sketch that runs a motor forward, backward and stopped.
Status: written from the Arduino reference and vendor guides for the L298N module. The sketch is an untested outline and there are no measured speeds or currents of our own.
What the driver does
An H-bridge lets current flow through the motor in either direction. A module like the L298N has two bridges, so it drives two motors. For each motor there are two direction inputs (IN1 and IN2 for motor A) and one enable input (ENA) that gates the power. Setting IN1 high and IN2 low spins the motor one way, the opposite setting spins it the other way, and both equal stops it. A PWM signal on the enable pin controls how much of the time the motor is powered, which sets the speed.
| IN1 | IN2 | Motor A |
|---|---|---|
| HIGH | LOW | Forward |
| LOW | HIGH | Backward |
| LOW | LOW | Stopped (free-running) |
| HIGH | HIGH | Stopped (braking) |
If your motor runs the wrong way, swap the two motor wires or swap the logic, no code change elsewhere is needed.
How analogWrite() sets speed
analogWrite(pin, value) takes a value from 0 (always off) to 255 (always on). On an Uno the PWM pins are 3, 5, 6, 9, 10 and 11, and the official reference gives the default frequency as about 490 Hz, or about 980 Hz on pins 5 and 6. Use one of those pins for the enable line. The reference also notes that pins 5 and 6 can behave oddly at low duty values because they share a timer with millis() and delay(), so a value of 0 may not turn the output fully off. If you hear a whine at these frequencies, see the PWM whine fix.
Duty cycle is not the same as speed. A small motor often will not start until the duty is high enough to overcome friction, so expect a dead zone at low values that you find by experiment.
Wiring in outline
- Arduino pins 9 (ENA), 7 (IN1) and 8 (IN2) to the driver. Pin 9 is PWM-capable on an Uno.
- Motor to the OUT1 and OUT2 terminals.
- Motor battery to the driver’s power terminal, with the battery negative joined to the Arduino ground. A shared ground is required for the signals to mean anything.
- Remove the ENA jumper so the PWM pin controls the enable line; with the jumper on, the enable pin is tied to 5 V and the motor runs at full speed.
- Check your module’s guide for the on-board 5 V regulator jumper. Vendor guides say to take it off above 12 V and to feed the 5 V pin externally; limits quoted vary between 6 and 7 V at the low end, so read yours.
The component details are on the L298N motor driver page, and the pin numbers are in the Uno pinout guide.
A first sketch
// Untested outline for one motor on an L298N.
const int ENA = 9; // PWM pin
const int IN1 = 7;
const int IN2 = 8;
void setMotor(int speed) { // -255 to 255
speed = constrain(speed, -255, 255);
if (speed > 0) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
} else if (speed < 0) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
} else {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
}
analogWrite(ENA, abs(speed));
}
void setup() {
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
}
void loop() {
setMotor(150); delay(2000); // forward
setMotor(0); delay(500);
setMotor(-150); delay(2000); // backward
setMotor(0); delay(500);
}The value 150 is a placeholder; choose one that suits your motor and battery. Reversing the direction straight from full speed puts a large current spike through the driver, so stop briefly in between as the sketch does. The delay() calls are fine for a bench test; in a real robot replace them with timing that does not block the loop.
Why the motor is slower than expected
- Voltage drop in the driver. Bipolar drivers like the L298 lose part of the supply voltage, so the motor sees less than the battery. Compare the driver pages, L298N vs TB6612FNG, which shows the efficient alternative.
- A weak or low battery. See the robot battery guide.
- The wrong motor for the load. See the motor selection guide.
- The two motors differ, so the robot curves. See the motor mismatch fix.
A test plan
- Test with the wheels off the ground and the battery connected.
- Step the value from 0 up in steps of 25 and note where the motor first starts turning.
- Confirm forward, backward and stop are correct, then swap wires if a direction is reversed.
- Touch the driver’s heatsink after a minute of running; if it is very hot, check the current against the driver rating.
- Write down your start value, your battery voltage and what you measured. Those are your own results.
Sources: Arduino reference for analogWrite(); vendor user guides for the L298N module jumpers. Last reviewed November 2026. Written, checked and maintained by Jignesh Panchal.