Arduino DC motor speed and direction control with L298N

How an H-bridge driver takes direction and PWM signals, how analogWrite sets motor speed on an Uno, and a first forward, backward and stop sketch.

Reference
RE-3812
Published
Read
5 min

About the author · Sources, testing and AI policy

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.

IN1IN2Motor A
HIGHLOWForward
LOWHIGHBackward
LOWLOWStopped (free-running)
HIGHHIGHStopped (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

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.

Pass it onWhatsAppLinkedIn

Keep reading

Continue learning

Tutorials

Arduino serial command parsing for robots

Why Bluetooth robots lag, how the Arduino serial timeout works, and a non-blocking command parser with a simple format and a link-loss…

  • Published4 Nov 2026
  • Read4 min

Free: the final-year project pack

A shortlist with BOMs, a report outline that matches the usual chapter scheme, a costing sheet and 40 viva questions. Built for the February–April submission season.

The Build Note

One short email when something is worth your bench time.

A new build sheet, a part price that moved, or a mistake worth avoiding. No daily drip, no recycled news.

One short email when a build or a price is worth your time. Unsubscribe in one click.