Contact Sales & After-Sales Service

Contact & Quotation

  • Inquire: Call 0086-755-23203480, or reach out via the form below/your sales contact to discuss our design, manufacturing, and assembly capabilities.
  • Quote: Email your PCB files to Sales@pcbsync.com (Preferred for large files) or submit online. We will contact you promptly. Please ensure your email is correct.
Drag & Drop Files, Choose Files to Upload You can upload up to 3 files.

Notes:
For PCB fabrication, we require PCB design file in Gerber RS-274X format (most preferred), *.PCB/DDB (Protel, inform your program version) format or *.BRD (Eagle) format. For PCB assembly, we require PCB design file in above mentioned format, drilling file and BOM. Click to download BOM template To avoid file missing, please include all files into one folder and compress it into .zip or .rar format.

Arduino PWM Motor Speed Control: Complete Guide – From Basics to Advanced Applications

After designing motor control circuits for industrial automation, robotics, and consumer electronics for over twelve years, I’ve implemented Arduino PWM motor speed control in hundreds of products. While the basic concept seems straightforward—vary the pulse width to change motor speed—the devil is in the details. Understanding how PWM actually works at the hardware level, selecting appropriate driver circuits, and avoiding common pitfalls separates functional prototypes from reliable production systems.

In this comprehensive guide, I’ll share practical insights from real-world implementations, including driver selection, proper wiring techniques, code optimization, and troubleshooting strategies. Whether you’re building your first Arduino robot or designing commercial motor control systems, this tutorial provides the foundation for successful PWM motor control.

Understanding PWM Fundamentals for Motor Control

What is PWM and Why It Works for Motors

Pulse Width Modulation (PWM) is a technique that creates variable average voltage through rapid switching between fully ON and fully OFF states. Instead of varying actual voltage levels (which wastes energy as heat in linear regulators), PWM delivers full voltage in controlled bursts.

DC motors respond to the average voltage they receive. When you apply a 50% duty cycle PWM signal at 12V, the motor experiences an effective 6V average, running at approximately half speed. The beauty of this approach is efficiency—the transistor switches are either fully conducting (minimal voltage drop) or completely off (no current flow), minimizing power loss.

Key PWM Parameters:

ParameterDefinitionTypical RangeImpact on Motors
FrequencyHow many on/off cycles per second100Hz – 40kHzToo low: audible whine<br>Too high: switching losses
Duty CyclePercentage of time signal is HIGH0% – 100%Directly controls average voltage
ResolutionNumber of discrete duty cycle levels8-bit (256 levels)<br>10-bit (1024 levels)Smoothness of speed control

Arduino PWM Motor Speed Control Architecture

Arduino boards generate PWM using hardware timers that automatically toggle pins at precise intervals. On Arduino Uno, six pins (3, 5, 6, 9, 10, 11) support PWM output through three independent timers.

Arduino Uno PWM Pin Configuration:

Pin(s)TimerDefault FrequencyNotes
5, 6Timer0980Hz (976.56Hz)Also controls millis() and delay()
9, 10Timer1490Hz (490.20Hz)16-bit timer, can support servos
3, 11Timer2490Hz (490.20Hz)Independent from Timer0

Important: Modifying Timer0 frequency affects millis(), delay(), and other timing functions. Always use Timer1 or Timer2 for custom PWM frequencies.

How Motors Respond to PWM

DC motors contain electromagnetic coils with significant inductance. This electrical property acts as a low-pass filter, smoothing the rapid PWM pulses into relatively steady current flow. The motor’s mechanical inertia further smooths the rotation, preventing it from starting and stopping with each pulse.

Motor Characteristics That Affect PWM Performance:

  1. Inductance: Higher inductance smooths current better, allows lower PWM frequencies
  2. Back-EMF: Generates voltage opposing applied voltage, varies with speed
  3. Stall Current: Maximum current at zero speed, can be 5-10× running current
  4. Torque-Speed Curve: Torque decreases as speed increases
  5. Thermal Limits: Continuous operation vs. intermittent duty ratings

Essential Hardware for Arduino PWM Motor Speed Control

Why You Cannot Drive Motors Directly

Arduino digital pins can source approximately 20-40mA at 5V. Even small hobby motors draw 100-500mA, with larger motors consuming several amperes. Attempting direct connection causes:

  1. Immediate Arduino damage from overcurrent
  2. Voltage drops that reset the microcontroller
  3. Back-EMF voltage spikes when motor de-energizes
  4. Insufficient torque due to voltage/current limitations

Solution: Use a motor driver that switches high current using Arduino’s low-power PWM signal.

Motor Driver Selection Guide

Option 1: Single Transistor (Simple, Unidirectional)

For basic speed control in one direction only:

ComponentSpecificationsUse CaseCost
NPN Transistor2N2222, TIP120, TIP122Small motors (<500mA)$0.10-0.50
N-Channel MOSFETIRF540N, IRLZ44NMedium motors (1-5A)$0.50-1.50
Logic-Level MOSFETIRLZ44N, IRL540NArduino direct drive$0.75-2.00

Wiring Example (N-Channel MOSFET):

Motor (+) → External Power Supply (+)

Motor (-) → MOSFET Drain

MOSFET Source → GND (Common with Arduino GND)

MOSFET Gate → Arduino PWM Pin (via 220Ω resistor)

Arduino GND → Power Supply GND (CRITICAL)

Option 2: H-Bridge (Bidirectional Control)

For speed AND direction control:

Driver ICMax CurrentVoltage RangeChannelsPriceFeatures
L293D600mA4.5-36V2 motors$1-2Built-in protection diodes
L298N2A5-46V2 motors$2-4Dual full-bridge, heatsink included
TB6612FNG1.2A4.5-13.5V2 motors$3-5More efficient than L293D
VNH2SP3030A5.5-16V1 motor$8-12High current applications
BTS796043A5.5-27V1 motor$5-10Extreme current capacity

L298N Module Benefits:

  • Onboard voltage regulator for Arduino power
  • Enable pins for PWM speed control
  • Direction control via logic pins
  • Protection diodes integrated
  • Screw terminals for easy connections

Power Supply Considerations

Motor power requirements often exceed Arduino capabilities significantly.

Power Supply Sizing:

Required Current = Motor Stall Current × 1.5 (safety factor)

Required Voltage = Motor Rated Voltage + Driver Drop (1-3V)

Example: 12V motor rated 1A running current, 3A stall current:

  • Supply Current: 3A × 1.5 = 4.5A minimum
  • Supply Voltage: 12V + 2V = 14V recommended

Critical Design Rules:

  1. Common Ground: Arduino GND must connect to motor power supply GND
  2. Separate Supplies: Don’t power motors from Arduino’s 5V regulator
  3. Decoupling Capacitors: 100µF electrolytic + 0.1µF ceramic near motor terminals
  4. Current Capacity: Account for starting surge (2-5× running current)

Arduino PWM Motor Speed Control Programming

Basic Speed Control with analogWrite()

The simplest Arduino PWM motor speed control uses the built-in analogWrite() function:

// Basic Motor Speed Control – Single Direction

const int motorPWM = 9;  // PWM pin

void setup() {

  pinMode(motorPWM, OUTPUT);

}

void loop() {

  // Gradually increase speed

  for(int speed = 0; speed <= 255; speed++) {

    analogWrite(motorPWM, speed);

    delay(20);  // Smooth acceleration

  }

  delay(2000);  // Run at full speed

  // Gradually decrease speed

  for(int speed = 255; speed >= 0; speed–) {

    analogWrite(motorPWM, speed);

    delay(20);

  }

  delay(2000);  // Stopped

}

Understanding analogWrite() Values:

  • analogWrite(pin, 0) → 0% duty cycle (motor stopped)
  • analogWrite(pin, 128) → 50% duty cycle (~half speed)
  • analogWrite(pin, 255) → 100% duty cycle (full speed)

Potentiometer-Controlled Speed

Real-world applications typically need user speed control:

// Potentiometer Speed Control with Serial Feedback

const int motorPWM = 9;

const int potPin = A0;

void setup() {

  pinMode(motorPWM, OUTPUT);

  Serial.begin(9600);

}

void loop() {

  // Read potentiometer (0-1023)

  int potValue = analogRead(potPin);

  // Map to PWM range (0-255)

  int motorSpeed = map(potValue, 0, 1023, 0, 255);

  // Apply speed to motor

  analogWrite(motorPWM, motorSpeed);

  // Display feedback

  Serial.print(“Pot: “);

  Serial.print(potValue);

  Serial.print(” | Speed: “);

  Serial.print(motorSpeed);

  Serial.print(” | Duty: “);

  Serial.print((motorSpeed * 100) / 255);

  Serial.println(“%”);

  delay(100);  // Prevent serial spam

}

L298N Motor Driver Control

For full bidirectional control with the L298N module:

// L298N Motor Control – Speed and Direction

const int ENA = 9;   // PWM speed control

const int IN1 = 7;   // Direction control

const int IN2 = 6;   // Direction control

const int potPin = A0;

void setup() {

  pinMode(ENA, OUTPUT);

  pinMode(IN1, OUTPUT);

  pinMode(IN2, OUTPUT);

  Serial.begin(9600);

}

void loop() {

  int potValue = analogRead(potPin);

  if(potValue < 462) {

    // Reverse direction (0-461)

    digitalWrite(IN1, LOW);

    digitalWrite(IN2, HIGH);

    int speed = map(potValue, 0, 461, 255, 0);  // Reverse mapping

    analogWrite(ENA, speed);

    Serial.print(“REVERSE | Speed: “);

    Serial.println(speed);

  } else if(potValue > 562) {

    // Forward direction (563-1023)

    digitalWrite(IN1, HIGH);

    digitalWrite(IN2, LOW);

    int speed = map(potValue, 563, 1023, 0, 255);

    analogWrite(ENA, speed);

    Serial.print(“FORWARD | Speed: “);

    Serial.println(speed);

  } else {

    // Dead zone (462-562) – motor stopped

    digitalWrite(IN1, LOW);

    digitalWrite(IN2, LOW);

    analogWrite(ENA, 0);

    Serial.println(“STOPPED”);

  }

  delay(100);

}

Dead Zone Concept: The middle potentiometer position (approximately 512) creates a neutral zone where the motor stops. This prevents jerky transitions when passing through zero speed.

Advanced PWM Techniques

Adjusting PWM Frequency

Default Arduino PWM frequencies (490Hz/980Hz) work for most applications but can cause issues:

Problems with Default Frequencies:

  • Audible whining from motor windings
  • Interference with other circuits
  • Insufficient for high-speed switching applications

Changing Timer1 Frequency (Pins 9, 10):

void setup() {

  // Change Timer1 frequency (pins 9 and 10)

  // Default: TCCR1B = 0x03 (490Hz)

  // 31.37kHz (nearly silent operation)

  TCCR1B = (TCCR1B & 0xF8) | 0x01;

  pinMode(9, OUTPUT);

}

void loop() {

  analogWrite(9, 128);  // 50% duty cycle at 31.37kHz

}

Available Timer1 Frequencies:

DivisorCodeFrequencyBest For
10x0131.37kHzSilent operation, small motors
80x023.92kHzReduced noise
640x03490HzDefault, general use
2560x04122HzHigh-inductance motors
10240x0530HzVery slow switching

Implementing Soft Start

Instant application of full power causes mechanical stress and current spikes. Soft start gradually accelerates:

void softStart(int targetSpeed, int rampTime) {

  int steps = 100;  // Number of acceleration steps

  int delayTime = rampTime / steps;

  for(int speed = 0; speed <= targetSpeed; speed += (targetSpeed / steps)) {

    analogWrite(motorPWM, speed);

    delay(delayTime);

  }

  analogWrite(motorPWM, targetSpeed);  // Ensure exact final speed

}

void loop() {

  softStart(200, 2000);  // Accelerate to speed 200 over 2 seconds

  delay(5000);           // Run

  softStart(0, 1000);    // Decelerate over 1 second

  delay(2000);

}

Current Monitoring

Monitoring motor current enables overcurrent protection and load detection:

// Using ACS712 Current Sensor (5A version)

const int currentSensorPin = A1;

const float mVperAmp = 185;  // 185mV per Amp for 5A version

const float ACSoffset = 2500;  // 2.5V at zero current

float readMotorCurrent() {

  int rawValue = analogRead(currentSensorPin);

  float voltage = (rawValue / 1024.0) * 5000;  // Convert to mV

  float current = ((voltage – ACSoffset) / mVperAmp);

  return current;

}

void loop() {

  analogWrite(motorPWM, 200);

  float current = readMotorCurrent();

  Serial.print(“Motor Current: “);

  Serial.print(current, 2);

  Serial.println(” A”);

  // Overcurrent protection

  if(current > 3.0) {

    analogWrite(motorPWM, 0);  // Emergency stop

    Serial.println(“OVERCURRENT – MOTOR STOPPED”);

    while(1);  // Halt program

  }

  delay(100);

}

Real-World Applications

Robotic Vehicle Speed Control

Arduino PWM motor speed control forms the foundation of most DIY robots:

Differential Drive Robot:

  • Left motor: Controls left wheel speed/direction
  • Right motor: Controls right wheel speed/direction
  • Forward: Both motors forward, equal speed
  • Turning: Differential speeds or opposite directions

Fan Speed Control

Computer cooling fans respond excellently to PWM control:

Advantages:

  • Silent operation (no voltage drop inefficiency)
  • Extended fan life (reduced wear at lower speeds)
  • Temperature-responsive cooling

// Temperature-Controlled Fan

#include <DHT.h>

#define DHTPIN 2

#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

const int fanPWM = 9;

void setup() {

  pinMode(fanPWM, OUTPUT);

  dht.begin();

}

void loop() {

  float temp = dht.readTemperature();

  int fanSpeed;

  if(temp < 25) {

    fanSpeed = 0;  // Off below 25°C

  } else if(temp < 35) {

    fanSpeed = map(temp, 25, 35, 50, 150);  // Gradual increase

  } else {

    fanSpeed = 255;  // Full speed above 35°C

  }

  analogWrite(fanPWM, fanSpeed);

  delay(2000);

}

Conveyor Belt Control

Industrial automation applications benefit from precise speed control:

Requirements:

  • Consistent speed regardless of load variations
  • Emergency stop capability
  • Adjustable speed for different products

Essential Resources and Downloads

Official Documentation

Arduino PWM Reference:

Motor Driver Datasheets:

Useful Libraries

PWM Control Libraries:

Library NamePurposeDownload
TimerOneAdvanced Timer1 PWM controlArduino Library Manager
PWM LibraryMulti-pin PWM with frequency controlArduino Library Manager
FlexiTimer2Timer2-based PWMGitHub

Online Calculators

  1. PWM Duty Cycle Calculator: Converts voltage to PWM value
  2. Timer Prescaler Calculator: Determines frequency from register settings
  3. Current Sense Resistor Calculator: Sizes shunt resistors for monitoring
  4. Motor Power Calculator: Estimates battery runtime

Frequently Asked Questions

1. Why does my motor make a high-pitched whining noise?

The whining sound comes from motor windings vibrating at the PWM frequency—typically 490Hz or 980Hz on Arduino, which falls within the audible range. This is normal but annoying. Solutions include: (1) Increase PWM frequency above 20kHz (human hearing limit) by modifying timer prescalers. Use TCCR1B = (TCCR1B & 0xF8) | 0x01; for 31kHz on pins 9 and 10. (2) Use a motor driver with built-in frequency control like TB6612FNG. (3) Add mechanical damping with rubber motor mounts. (4) Accept the noise—it won’t damage the motor and many commercial products have audible PWM. The frequency that causes least noise varies by motor construction, so experimentation may be needed.

2. My motor doesn’t respond smoothly at low PWM values. Why?

DC motors have a minimum voltage threshold below which they cannot overcome internal friction and produce torque. This “dead zone” typically occurs at PWM values roughly 0-40 (out of 255). Below this threshold, the motor draws current but doesn’t rotate. Solutions include: (1) Implement a minimum speed threshold in code—map your control input to skip the dead zone, for example map(input, 0, 1023, 50, 255). (2) Use a gear reduction to increase torque at low speeds. (3) Ensure proper lubrication and minimal mechanical binding. (4) Accept the limitation—for precise low-speed control, consider stepper motors instead of DC motors with PWM. The dead zone varies significantly between motor types; high-quality brushless motors have smaller dead zones than cheap brush motors.

3. Can I connect multiple motors to the same PWM pin?

Technically yes, but practically problematic. Multiple motors connected in parallel to one PWM pin will: (1) Draw combined current that likely exceeds driver capacity—a driver rated 2A cannot safely drive two 1.5A motors. (2) Run at identical speeds since they share the same control signal—you cannot independently control them. (3) Create unequal loads if motors have different characteristics, causing one to work harder. For proper multi-motor control: (1) Use separate driver channels for each motor, even if they’ll run at the same speed—this allows individual current limiting. (2) Use a multi-channel driver like L298N (controls two motors) or shield designs supporting 4+ motors. (3) Control each motor with its own PWM pin for independent speed control. If motors truly must run identically and combined current is acceptable, use a higher-rated driver to safely handle the total load.

4. How do I prevent voltage spikes from damaging my Arduino?

Motor-generated voltage spikes occur when current suddenly stops, causing inductance to generate high voltage (back-EMF). Protection requires: (1) Always use drivers with integrated flyback diodes (L293D, L298N have these built-in). For discrete transistor circuits, add a diode across the motor terminals with cathode (+) to motor positive. (2) Add decoupling capacitors: 100µF electrolytic across motor power supply, 0.1µF ceramic near motor driver pins. (3) Ensure common ground between Arduino and motor power supply—floating grounds worsen noise coupling. (4) Use optoisolators to completely isolate Arduino from motor circuits in critical applications. (5) Add TVS (Transient Voltage Suppressor) diodes across power rails for additional protection. The key principle: provide a path for inductive current to circulate rather than seeking ground through Arduino pins.

5. Why does my motor speed vary with load?

DC motors naturally slow down under increasing load—this is fundamental to their operation. Without feedback control, Arduino PWM motor speed control is “open-loop,” meaning it sets voltage but doesn’t monitor actual speed. When load increases: (1) Motor draws more current, causing voltage drop in wiring and driver. (2) Mechanical resistance absorbs more power, reducing rotational speed. (3) Back-EMF decreases with slower rotation, allowing higher current but not compensating for load. Solutions for speed stability: (1) Implement closed-loop control using encoders to measure actual speed and adjust PWM to maintain setpoint. (2) Use higher voltage power supplies—12V motors run more consistently than 5V motors under varying load. (3) Select motors with higher torque rating than minimum required. (4) Add current monitoring and increase PWM when current exceeds threshold (simple load compensation). For critical speed regulation, consider stepper motors or servo motors with built-in position feedback.

Conclusion

Arduino PWM motor speed control represents one of the most accessible yet powerful techniques in embedded systems. From simple fan controllers to complex robotic vehicles, understanding PWM fundamentals and proper implementation separates functional prototypes from reliable systems.

The key takeaways from this comprehensive guide emphasize hardware selection matching your motor specifications, proper power supply design with common ground connections, and appropriate driver circuits to protect Arduino while delivering necessary current. Software implementation using analogWrite() provides immediate functionality, while advanced techniques like frequency adjustment and soft start enhance performance.

Remember that PWM control is inherently open-loop—the Arduino sets a duty cycle but doesn’t verify actual motor speed unless you add encoder feedback. This limitation means speed will vary with load, voltage fluctuations, and motor characteristics. For applications requiring precise speed regulation, consider implementing closed-loop control or selecting motors with integrated feedback.

Start with simple single-direction control using a MOSFET to understand basic principles. Progress to H-bridge drivers like the L298N for bidirectional control. Experiment with frequency adjustment to eliminate motor whine. Implement soft start for mechanical longevity. Add current sensing for protection and load detection.

The beauty of Arduino PWM motor speed control lies in its scalability—the same principles apply whether controlling a 5V hobby motor in an educational robot or managing multiple 24V industrial motors in production equipment. Master these fundamentals, and you’ll have the foundation for virtually any DC motor control application you can imagine.

Leave a Reply

Your email address will not be published. Required fields are marked *

Contact Sales & After-Sales Service

Contact & Quotation

  • Inquire: Call 0086-755-23203480, or reach out via the form below/your sales contact to discuss our design, manufacturing, and assembly capabilities.

  • Quote: Email your PCB files to Sales@pcbsync.com (Preferred for large files) or submit online. We will contact you promptly. Please ensure your email is correct.

Drag & Drop Files, Choose Files to Upload You can upload up to 3 files.

Notes:
For PCB fabrication, we require PCB design file in Gerber RS-274X format (most preferred), *.PCB/DDB (Protel, inform your program version) format or *.BRD (Eagle) format. For PCB assembly, we require PCB design file in above mentioned format, drilling file and BOM. Click to download BOM template To avoid file missing, please include all files into one folder and compress it into .zip or .rar format.