DC Motor (Transistor Drive)
A DC motor cannot be driven directly from an Arduino digital pin — the pin can only source ≈ 40 mA at 5V, while a small DC motor draws 100–500 mA under load and generates voltage spikes during commutation. The solution is a transistor switch (BJT or MOSFET) that uses the Arduino’s low-current signal to control a separate high-current supply. This tutorial covers one-direction speed control via PWM with a flyback diode for back-EMF protection.
For this interfacing you need the following components:
- Arduino board (Uno, Nano, Mega, etc.)
- Small DC motor (3–9V, 100–500 mA stall current)
- NPN transistor (2N2222, TIP120, or BC547 for very small motors)
- 1N4007 flyback diode (or 1N4148 for small motors)
- 1 kΩ base resistor (for BJT) or 10 kΩ gate resistor (for MOSFET)
- External power supply (battery pack or lab supply matching motor voltage)
- Breadboard and jumper wires
- USB cable to connect Arduino to your computer
Schematic
BJT (2N2222) — one-direction speed control
+Motor VCC (3–9V)
|
+----+----+
| |
MOTOR 1N4007
| | (cathode to +V)
| |
+----+----+
|
Collector
|
2N2222 (NPN)
|
Emitter
|
GND
Arduino Pin 9 ---/\/\/\--- Base
1 kΩ
When the Arduino pin goes HIGH, the transistor saturates and the motor runs. PWM on pin 9 controls speed.
MOSFET (IRLZ44N logic-level) — more efficient for larger motors
+Motor VCC
|
+----+----+
| |
MOTOR 1N4007
| |
+----+----+
|
Drain
|
IRLZ44N (N-channel logic-level MOSFET)
|
Source
|
GND
Arduino Pin 9 ---/\/\/\--- Gate
10 kΩ
|
GND (10 kΩ gate pulldown)
The 10 kΩ gate-to-GND resistor ensures the MOSFET is off during Arduino boot.
Pin Map
| Component | Arduino Pin |
|---|---|
| Motor control (PWM) | 9 |
| Motor power (external) | Battery + |
| GND (common) | Arduino GND + Battery - |
The Arduino and the motor must share a common GND for the transistor switch to work.
Install necessary Library
No library is required. Speed control uses analogWrite() (PWM).
Code with complete explanation
This sketch ramps the motor speed up and down using PWM and reads the current direction from a button.
#define MOTOR_PIN 9
#define BTN_PIN 2
int speed = 0;
int step = 5;
void setup()
{
Serial.begin(9600);
pinMode(MOTOR_PIN, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP);
Serial.println("DC Motor PWM Control");
}
void loop()
{
// Button reverses direction (changes ramp direction)
if (digitalRead(BTN_PIN) == LOW)
{
step = -step;
delay(200);
}
// Ramp speed
speed += step;
if (speed >= 255)
{
speed = 255;
step = -step; // Reverse ramp
Serial.println("Full speed — slowing down");
}
else if (speed <= 0)
{
speed = 0;
step = -step; // Reverse ramp
Serial.println("Stopped — speeding up");
}
analogWrite(MOTOR_PIN, speed);
Serial.print("Speed: ");
Serial.println(speed);
delay(30);
}
Fixed speed test
void loop()
{
// Run at 50 % duty cycle
analogWrite(MOTOR_PIN, 128);
delay(5000);
// Run at 75 %
analogWrite(MOTOR_PIN, 191);
delay(5000);
// Stop
analogWrite(MOTOR_PIN, 0);
delay(3000);
}
Code breakdown
analogWrite(pin, value)— outputs a PWM signal (0–255) on pin 9 (or pins 3, 5, 6, 10, 11 on Uno). A 0% duty cycle = motor off, 100% = full speed.- The transistor acts as a switch: PWM HIGH → transistor saturated → motor connected to GND → current flows.
- The flyback diode (1N4007) is connected reverse-biased across the motor terminals. When the transistor switches off, the motor’s inductive kickback current circulates through the diode instead of arcing across the transistor.
- The base resistor (1 kΩ for BJT) limits the base current to ≈ 4 mA when the Arduino pin is HIGH (5V), keeping the transistor in saturation without overloading the pin.
Bidirectional control (H-bridge required)
For forward/reverse control, a single transistor is insufficient — an H-bridge (L293D, L298N, or discrete transistors) is needed:
// H-bridge pins
#define MOTOR_IN1 8
#define MOTOR_IN2 9
#define MOTOR_EN 10
void setMotor(int speed) // -255..+255
{
if (speed > 0)
{
digitalWrite(MOTOR_IN1, HIGH);
digitalWrite(MOTOR_IN2, LOW);
analogWrite(MOTOR_EN, speed);
}
else if (speed < 0)
{
digitalWrite(MOTOR_IN1, LOW);
digitalWrite(MOTOR_IN2, HIGH);
analogWrite(MOTOR_EN, -speed);
}
else
{
digitalWrite(MOTOR_IN1, LOW);
digitalWrite(MOTOR_IN2, LOW);
analogWrite(MOTOR_EN, 0);
}
}
Steps to perform this interfacing
- Build the transistor circuit on a breadboard as shown.
- Connect a common GND between the Arduino and the external motor power supply.
- Do NOT connect the motor to the Arduino’s 5V pin — use an external supply.
- Copy the code into the Arduino IDE.
- Select the correct board and port (
Tools > BoardandTools > Port). - Upload the sketch to the Arduino.
- Open the Serial Monitor (
Tools > Serial Monitor, set baud rate to 9600). - The motor speed ramps up from 0 to 255, then down, repeating.
- Press the button (pin 2 to GND) to reverse the ramp direction.
- Observe that the motor stops cleanly and does not cause the Arduino to reset.
Caution
- Flyback diode is mandatory: Without the 1N4007 (or Schottky) diode across the motor terminals, the inductive voltage spike when the transistor turns off can exceed 50V — destroying the transistor instantly. The diode must be connected reverse-biased (cathode to motor +V, anode to motor GND side). If the motor runs but the transistor gets hot or fails immediately, the diode is likely missing or connected backwards.
- Transistor current rating: A 2N2222 is rated for 600 mA collector current (800 mA peak) — adequate for small toy motors. For motors drawing > 500 mA, use a TIP120 Darlington pair (5A rated) or a logic-level MOSFET like IRLZ44N (30+A). The TIP120 has a higher saturation voltage (≈ 1V) than a MOSFET, causing more heat dissipation at high currents.
- Base resistor calculation: For a BJT with a gain of ≈ 100, the base current should be ≈ 1/10 of the collector current (forced beta). For a 200 mA motor: I_b = 20 mA, R_b = (5V - 0.7V) / 0.02A ≈ 220 Ω. For the 2N2222 with a 1 kΩ resistor: I_b ≈ 4.3 mA, max collector current ≈ 430 mA — within limits for most small motors.
- Common ground required: The transistor switches the motor’s current path to GND. If the Arduino and the motor power supply do not share a common GND, the base-to-emitter circuit is incomplete and the transistor will not turn on. Always connect Arduino GND to the motor power supply’s negative terminal.
- PWM frequency: The Arduino’s default PWM frequency on pin 9 is ≈ 490 Hz (pins 5 and 6 are ≈ 980 Hz). At low PWM values, the motor may audibly whine at this frequency if the mechanical load is light. Changing
TCCR1Bprescaler can shift the frequency to ≈ 31 kHz (inaudible) but affectsmillis()timing. - Stall current: When the motor shaft is mechanically prevented from turning (stall), the current can increase 5–10× the running current. A 200 mA motor may draw 1.5–2A when stalled. Ensure your transistor, power supply, and wiring can handle stall current for at least a few seconds. For protection, add a PTC resettable fuse or a current-sense resistor with software shutdown.
- Motor noise: Brushed DC motors generate electrical noise (sparking at the brushes) that can couple back into the Arduino’s 5V rail, causing resets or sensor glitches. Add a 100 µF electrolytic capacitor + 100 nF ceramic capacitor across the motor terminals (between motor +V and motor GND) to suppress this noise.