DC MOTOR SPEED CONTROL USING ARDUINO UNO

DC Motor Speed Control with Encoder Using Arduino UNO – PWM + RPM + LCD | MakeMindz
⚙️ Closed-Loop Motor Control Project

DC Motor Speed Control
with Encoder – Arduino UNO

Control and monitor motor speed in real time using PWM output, encoder pulse feedback, potentiometer input, and RPM display on a 16×2 LCD — the foundation of PID motor control.

🔲 Arduino UNO ⚡ PWM Control 🔄 Encoder Feedback 🔧 2N2222 Transistor 🖥️ 16×2 LCD RPM 🔁 Closed Loop

This project demonstrates a closed-loop DC motor speed control system using Arduino UNO. The user sets desired speed via a potentiometer, the Arduino generates a PWM signal to drive the motor through a 2N2222 transistor, and an encoder feeds back the actual speed — which is calculated as RPM and displayed on a 16×2 LCD.

Simulated in Tinkercad or built on hardware, this system teaches signal conditioning, transistor switching, encoder pulse counting, and RPM calculation — core skills for robotics and automation.

🧩 Components Required

🔲Arduino UNOCentral controller — reads encoder, outputs PWM, calculates RPM
⚙️DC Motor + EncoderMotor provides rotation; encoder generates speed feedback pulses
🖥️16×2 LCDDisplays real-time RPM, set speed and actual speed
🔧PotentiometerSpeed control knob — sends 0–5V analog to Arduino
🔌2N2222 TransistorNPN switch — receives PWM and drives motor current safely
Op-Amp CircuitConditions encoder signals for clean digital pulses to Arduino
📊OscilloscopeMonitors PWM waveform and encoder output for debugging
🔋Power SupplyProvides stable voltage and current for motor operation
Flyback Diode1N4001 — protects transistor from motor back-EMF spikes
🔗ResistorsBase resistor (1kΩ) for transistor + pull-up for encoder signal

🔁 Closed-Loop Control Concept

How Closed-Loop Motor Control Works

🎛️ Potentiometer
Desired Speed
🔲 Arduino UNO
analogRead() → map()
⚡ 2N2222 Transistor
PWM Switching
⚙️ DC Motor
Rotates at speed
🖥️ LCD Display
Shows RPM
🔲 Arduino UNO
RPM = pulses × 60 / PPR
🔄 Encoder
Pulse feedback
⚙️ DC Motor
Physical rotation
🔁 Feedback Loop: Actual Speed compared to Desired Speed → PWM Corrected → Foundation of PID Control

PWM Speed Control

Low Speed

Low duty cycle (~25%)
analogWrite(pin, 64)

Medium Speed

Medium duty cycle (~60%)
analogWrite(pin, 153)

Full Speed

High duty cycle (~95%)
analogWrite(pin, 242)

ℹ️
RPM Calculation Formula

RPM = (pulse_count × 60) / (PPR × elapsed_seconds)
Where PPR = Pulses Per Revolution of your specific encoder (commonly 20, 100, 360 or 1000). Measure elapsed time using millis() every 1 second for stable readings.


🔌 Circuit Diagram

Arduino UNO – DC Motor Speed Control with Encoder – Wiring Diagram Arduino UNO A0 (Potentiometer) D2 (Encoder INT) D9 PWM (Motor) D11 (LCD RS) D12 (LCD EN) D4 (LCD D4) D5 (LCD D5) D6 (LCD D6) D7 (LCD D7) 5V GND Potentiometer Speed Control Knob Middle pin → A0 Outer: 5V & GND DC Motor + Encoder Motor Encoder Pulse out →D2 2N2222 NPN Transistor Base → 1kΩ → D9 (PWM) Collector → Motor (–) Emitter → GND 16×2 LCD Display Set: 180 RPM Actual: 177 RPM RS=D11 · EN=D12 · D4=D4 · D5=D5 · D6=D6 · D7=D7 VSS=GND · VDD=5V · VO=Potentiometer wiper Flyback Diode 1N4001 across motor terminals Cathode → Motor+ · Anode → Motor– Op-Amp (LM358) Conditions encoder signal Ensures clean pulses to D2 Amplifies weak Hall effect signal Oscilloscope Monitor PWM on D9 Monitor encoder pulses on D2 Debug & tune system performance WIRE LEGEND: Potentiometer (A0) Encoder (D2) PWM Motor (D9) LCD Data 5V Power GND 1kΩ base resistor for 2N2222 · 1N4001 flyback diode across motor

📋 Pin Connection Table

ComponentComponent PinArduino PinWireNotes
PotentiometerMiddle (Wiper)A0YellowAnalog speed input 0–5V
PotentiometerPin 15VRedOne outer terminal to 5V
PotentiometerPin 3GNDBlackOther outer terminal to GND
EncoderSignal OutD2GreenInterrupt pin for pulse counting
EncoderVCC5VRedEncoder power
EncoderGNDGNDBlackCommon ground
2N2222 TransistorBaseD9 (via 1kΩ)OrangePWM signal through 1kΩ resistor
2N2222 TransistorEmitterGNDBlackCommon ground
DC MotorTerminal (+)Power Supply +RedPositive motor terminal
DC MotorTerminal (–)2N2222 CollectorBlackTransistor controls motor current
Flyback Diode (1N4001)CathodeMotor (+)OrangeProtects transistor from back-EMF
Flyback Diode (1N4001)AnodeMotor (–)OrangeAcross motor terminals
16×2 LCDRSD11BlueRegister select
16×2 LCDEND12BlueEnable
16×2 LCDD4–D7D4–D7Blue4-bit data bus
16×2 LCDVSSGNDBlackLCD ground
16×2 LCDVDD5VRedLCD power
16×2 LCDVOPot wiperYellowContrast via 10kΩ potentiometer
⚠️
Always use a Flyback Diode!

DC motors generate voltage spikes (back-EMF) when switching off. Always place a 1N4001 diode across the motor terminals (cathode to +, anode to –) to protect the 2N2222 transistor from damage.

📝 Step-by-Step Instructions

1

Install LiquidCrystal Library

The LiquidCrystal and Servo libraries are built into the Arduino IDE. Go to Sketch → Include Library → LiquidCrystal to confirm it's available. No additional install needed.

2

Wire the Potentiometer (Speed Input)

  • Pot left outer pin → 5V
  • Pot right outer pin → GND
  • Pot middle wiper pin → Arduino A0
  • This gives 0–1023 range from analogRead(A0)
3

Wire the 2N2222 Transistor Motor Driver

  • Transistor Base → 1kΩ resistor → Arduino D9
  • Transistor Collector → Motor (–) terminal
  • Transistor Emitter → GND
  • Motor (+) terminal → External power supply (+)
  • Place 1N4001 diode across motor terminals (cathode to +)
4

Wire the Encoder

  • Encoder signal output → Arduino D2 (interrupt pin)
  • Encoder VCC → 5V, GND → GND
  • If signal is weak/noisy, use an op-amp (LM358) as a comparator to clean the pulse
  • Note your encoder's PPR (Pulses Per Revolution) value for the RPM formula
5

Wire the 16×2 LCD

  • LCD RS → D11, EN → D12, D4 → D4, D5 → D5, D6 → D6, D7 → D7
  • LCD VSS → GND, VDD → 5V
  • LCD VO → middle pin of 10kΩ potentiometer (for contrast)
  • Pot outer pins to 5V and GND
6

Set PPR in the Code

Find your encoder's PPR (Pulses Per Revolution) in its datasheet. Common values: 20 PPR (cheap DC motors), 100 PPR, 360 PPR (precision). Update const int PPR = 20; in the code to match your encoder.

7

Upload and Test

  • Select Tools → Board → Arduino UNO, choose COM port
  • Upload the sketch — LCD should display "Set: 0 RPM / Actual: 0 RPM"
  • Turn potentiometer slowly — motor speed should change and LCD RPM should update
  • Connect oscilloscope to D9 to observe the PWM waveform changing with pot
  • Connect oscilloscope to D2 to see encoder pulses at different speeds

💻 Arduino Code

ARDUINO C++  ·  DCMotorSpeedControl.ino
/*
 * DC Motor Speed Control with Encoder Feedback
 * Arduino UNO + 2N2222 Transistor + Encoder + 16x2 LCD
 *
 * Potentiometer → A0   (speed setpoint)
 * Encoder Signal → D2  (interrupt for pulse counting)
 * PWM Motor Drive → D9 (through 1kΩ → 2N2222 base)
 * LCD: RS=D11, EN=D12, D4=D4, D5=D5, D6=D6, D7=D7
 *
 * IMPORTANT: Add 1N4001 flyback diode across motor terminals
 *
 * Tutorial: https://www.makemindz.com
 */

#include <LiquidCrystal.h>

// LCD: RS, EN, D4, D5, D6, D7
LiquidCrystal lcd(11, 12, 4, 5, 6, 7);

// Pin definitions
const int potPin      = A0;  // Potentiometer input
const int motorPin    = 9;   // PWM output to 2N2222 base
const int encoderPin  = 2;   // Encoder interrupt pin

// Encoder settings — update PPR for your specific encoder
const int  PPR          = 20;   // Pulses Per Revolution
volatile long pulseCount = 0;   // Incremented by interrupt

// Timing
unsigned long lastTime = 0;
const unsigned long interval = 1000;  // Calculate RPM every 1 second

int actualRPM = 0;
int pwmValue  = 0;

// Interrupt Service Routine — called on each encoder pulse
void countPulse() {
  pulseCount++;
}

void setup() {
  lcd.begin(16, 2);
  lcd.print("DC Motor Control");
  lcd.setCursor(0, 1);
  lcd.print(" Initialising...");
  delay(2000);

  pinMode(motorPin, OUTPUT);
  pinMode(encoderPin, INPUT_PULLUP);

  // Attach interrupt on D2 — RISING edge = one encoder pulse
  attachInterrupt(digitalPinToInterrupt(encoderPin), countPulse, RISING);

  lastTime = millis();
  Serial.begin(9600);
}

void loop() {
  // Read potentiometer and map to PWM range
  int potValue = analogRead(potPin);         // 0–1023
  pwmValue = map(potValue, 0, 1023, 0, 255); // Map to 0–255

  // Calculate desired RPM for display (pot position estimate)
  int setRPM = map(potValue, 0, 1023, 0, 300);

  // Drive motor via transistor with PWM
  analogWrite(motorPin, pwmValue);

  // Calculate RPM every 1 second
  unsigned long currentTime = millis();
  if (currentTime - lastTime >= interval) {
    // Disable interrupt briefly to safely read pulseCount
    detachInterrupt(digitalPinToInterrupt(encoderPin));
    long count = pulseCount;
    pulseCount = 0;
    attachInterrupt(digitalPinToInterrupt(encoderPin), countPulse, RISING);

    // RPM = (pulses per second × 60) / PPR
    actualRPM = (count * 60) / PPR;
    lastTime = currentTime;

    // Update LCD display
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Set: ");
    lcd.print(setRPM);
    lcd.print(" RPM   ");
    lcd.setCursor(0, 1);
    lcd.print("Act: ");
    lcd.print(actualRPM);
    lcd.print(" RPM   ");

    // Serial output for debugging / oscilloscope correlation
    Serial.print("PWM: "); Serial.print(pwmValue);
    Serial.print(" | RPM: "); Serial.println(actualRPM);
  }
}

📐 diagram.json (Wokwi Simulation)

ℹ️
Using this in Wokwi

Go to wokwi.com → New Project → Arduino UNO. Replace diagram.json with this content and paste your sketch code. Turn the potentiometer in simulation to vary the PWM. Use the Serial Monitor to watch real-time RPM values.

diagram.json  ·  Wokwi DC Motor Speed Control
{
  "version": 1,
  "author": "MakeMindz",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-arduino-uno",
      "id": "uno", "top": 80, "left": 180, "attrs": {}
    },
    {
      "type": "wokwi-potentiometer",
      "id": "pot", "top": -80, "left": -160,
      "attrs": { "value": "10000", "label": "Speed Control" }
    },
    {
      "type": "wokwi-dc-motor",
      "id": "motor", "top": 80, "left": -200, "attrs": {}
    },
    {
      "type": "wokwi-npn-transistor",
      "id": "q1", "top": 240, "left": -80,
      "attrs": { "type": "2N2222" }
    },
    {
      "type": "wokwi-resistor",
      "id": "r1", "top": 240, "left": -180,
      "attrs": { "value": "1000", "label": "1k Base" }
    },
    {
      "type": "wokwi-diode",
      "id": "d1", "top": 80, "left": -140,
      "attrs": { "label": "1N4001 Flyback" }
    },
    {
      "type": "wokwi-lcd1602",
      "id": "lcd", "top": -100, "left": 440, "attrs": {}
    },
    {
      "type": "wokwi-potentiometer",
      "id": "pot2", "top": 80, "left": 440,
      "attrs": { "value": "10000", "label": "LCD Contrast" }
    }
  ],
  "connections": [
    [ "pot:SIG",    "uno:A0",    "yellow", ["h0"] ],
    [ "pot:VCC",    "uno:5V",    "red",    ["h0"] ],
    [ "pot:GND",    "uno:GND.1", "black",  ["h0"] ],
    [ "motor:A",    "uno:5V",    "red",    ["h0"] ],
    [ "motor:B",    "q1:C",      "black",  ["h0"] ],
    [ "q1:B",       "r1:2",      "orange", ["h0"] ],
    [ "r1:1",       "uno:9",     "orange", ["h0"] ],
    [ "q1:E",       "uno:GND.2", "black",  ["h0"] ],
    [ "d1:A",       "motor:B",   "orange", ["h0"] ],
    [ "d1:K",       "motor:A",   "orange", ["h0"] ],
    [ "motor:ENC",  "uno:2",     "green",  ["h0"] ],
    [ "lcd:RS",     "uno:11",    "blue",   ["h0"] ],
    [ "lcd:EN",     "uno:12",    "blue",   ["h0"] ],
    [ "lcd:D4",     "uno:4",     "blue",   ["h0"] ],
    [ "lcd:D5",     "uno:5",     "blue",   ["h0"] ],
    [ "lcd:D6",     "uno:6",     "blue",   ["h0"] ],
    [ "lcd:D7",     "uno:7",     "blue",   ["h0"] ],
    [ "lcd:VSS",    "uno:GND.3", "black",  ["h0"] ],
    [ "lcd:VDD",    "uno:5V",    "red",    ["h0"] ],
    [ "lcd:VO",     "pot2:SIG",  "yellow", ["h0"] ],
    [ "pot2:VCC",   "uno:5V",    "red",    ["h0"] ],
    [ "pot2:GND",   "uno:GND.4", "black",  ["h0"] ]
  ],
  "dependencies": {}
}

🚀 Try the Live Simulations

Simulate the full motor speed control system — turn the virtual potentiometer to change PWM duty cycle and watch the RPM update on the LCD display!

Key Features

🔁
Closed-Loop Control

Encoder feedback compares actual vs desired speed — foundation of PID systems

PWM Speed Control

Smooth motor speed variation from 0–100% using 8-bit PWM on D9

🔄
Real-Time RPM Display

LCD updates every second with actual measured RPM from encoder pulses

🔧
Transistor Driver Stage

2N2222 safely handles motor current — Arduino GPIO protected from high currents

🛡️
Back-EMF Protection

1N4001 flyback diode prevents voltage spikes from damaging the transistor

📊
Oscilloscope Integration

Monitor PWM waveform and encoder pulses for real-world signal analysis

🏭 Applications

🤖 Robotics Drive Systems 🏭 Conveyor Belt Control ⚙️ Industrial Automation 🔩 CNC Machine Spindles 🎓 Mechatronics Education 📊 Speed Monitoring Systems 💻 Embedded Systems Training 🔬 PID Control Learning

© 2026 MakeMindz · DC Motor Speed Control with Encoder – Arduino UNO Tutorial · All rights reserved

Comments

try for free