The L293D is a classic dual H-bridge motor driver IC capable of driving two DC motors independently at up to 600mA continuous current per channel (1.2A peak). When paired with an Arduino, it provides a straightforward way to control motor direction and speed via PWM without risking the microcontroller's GPIO pins. However, its internal bipolar Darlington transistor architecture introduces a significant voltage drop that trips up many beginners.
This guide provides the exact wiring, a data-driven comparison to modern alternatives, and fully compilable code with serial error handling to get your l293d and arduino project running reliably on the bench.
L293D vs L298N vs DRV8833: Spec-Sheet Reality
Before wiring up the breadboard, it is critical to understand where the L293D sits in the current landscape of motor drivers. While it is a staple in educational kits, its internal voltage drop makes it inefficient for low-voltage battery projects. Below is a data-dense comparison to help you decide if the L293D is the right choice for your specific voltage and current requirements.
| Parameter | L293D (DIP-16) | L298N (Multiwatt15) | DRV8833 (Modern Alt) |
|---|---|---|---|
| Continuous Current / Channel | 600 mA | 2.0 A | 1.5 A |
| Peak Current / Channel | 1.2 A | 3.0 A | 2.0 A |
| Motor Voltage Range (VCC2) | 4.5V to 36V | 5V to 46V | 2.7V to 10.8V |
| Internal Voltage Drop | ~1.4V (up to 2V) | ~2.0V (up to 3V) | ~0.4V (MOSFET based) |
| Built-in Flyback Diodes | Yes (Internal) | No (External needed) | Yes (Internal) |
| Typical IC Price (2026) | $1.50 - $2.50 | $3.00 - $4.50 | $1.80 - $2.80 |
Parts List and Exact Pin Mapping
This build assumes you are using the standard Arduino Uno R3 (ATmega328P) and a bare Texas Instruments L293DNE (or equivalent SN754410NE) DIP-16 IC. If you are using a pre-soldered L293D motor shield, the pin mappings will differ based on the shield's specific jumper configuration.
Required Components
- Microcontroller: Arduino Uno R3 (ATmega328P)
- Motor Driver: TI L293DNE (DIP-16 package)
- Motors: 2x 3-6V DC TT Gearmotors (yellow hobby motors)
- Power Supply (Logic): Arduino USB (5V)
- Power Supply (Motors): 4x AA Battery Holder (6V) or 2S LiPo (7.4V) with DC jack
- Hardware: 830-point breadboard, 22 AWG solid jumper wires
L293D to Arduino Pin Mapping
The L293D requires three power connections: VCC1 (5V logic), VCC2 (Motor supply), and GND. All grounds must be tied together to establish a common reference.
| L293D Pin | Function | Connection Target |
|---|---|---|
| 1 (1,2EN) | Enable Motor A (PWM) | Arduino Pin 9 (PWM) |
| 2 (1A) | Input 1 Motor A | Arduino Pin 8 (Digital) |
| 3 (1Y) | Output 1 Motor A | Motor A Terminal 1 |
| 4, 5, 12, 13 | Ground / Heatsink | Common Ground (Arduino + Battery) |
| 6 (2Y) | Output 2 Motor A | Motor A Terminal 2 |
| 7 (2A) | Input 2 Motor A | Arduino Pin 7 (Digital) |
| 8 (VCC2) | Motor Power Supply | Battery Pack Positive (+) |
| 9 (3,4EN) | Enable Motor B (PWM) | Arduino Pin 10 (PWM) |
| 10 (3A) | Input 1 Motor B | Arduino Pin 6 (Digital) |
| 11 (3Y) | Output 1 Motor B | Motor B Terminal 1 |
| 14 (4Y) | Output 2 Motor B | Motor B Terminal 2 |
| 15 (4A) | Input 2 Motor B | Arduino Pin 5 (Digital) |
| 16 (VCC1) | Logic Power Supply | Arduino 5V Pin |
Compilable Arduino Code for Dual DC Motor Control
The following sketch targets the Arduino Uno R3. It implements a Serial command parser to control both motors, complete with input validation and error handling. This prevents the microcontroller from executing garbage data if the serial buffer gets corrupted or if a user types an invalid string.
Open the Serial Monitor at 115200 baud and send commands in the format [Motor]:[Direction]:[Speed]. For example, A:F:200 runs Motor A forward at a PWM value of 200.
// L293D Dual Motor Control with Serial Error Handling
// Target Board: Arduino Uno R3 (ATmega328P)
// --- Pin Definitions ---
// Motor A (Left)
const int EN_A = 9; // PWM pin
const int IN_1 = 8; // Digital pin
const int IN_2 = 7; // Digital pin
// Motor B (Right)
const int EN_B = 10; // PWM pin
const int IN_3 = 6; // Digital pin
const int IN_4 = 5; // Digital pin
void setup() {
// Initialize serial communication for debugging and control
Serial.begin(115200);
// Set all motor control pins as outputs
pinMode(EN_A, OUTPUT);
pinMode(IN_1, OUTPUT);
pinMode(IN_2, OUTPUT);
pinMode(EN_B, OUTPUT);
pinMode(IN_3, OUTPUT);
pinMode(IN_4, OUTPUT);
// Ensure motors are stopped on boot
stopMotor(IN_1, IN_2, EN_A);
stopMotor(IN_3, IN_4, EN_B);
Serial.println("L293D Controller Ready. Format: [A/B]:[F/B/S]:[0-255]");
}
void loop() {
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n');
command.trim(); // Remove trailing whitespace/CR
// Parse the command string
int firstColon = command.indexOf(':');
int secondColon = command.indexOf(':', firstColon + 1);
// Error Handling: Validate command structure
if (firstColon == -1 || secondColon == -1 || firstColon == 0 || secondColon == firstColon + 1) {
Serial.println("Error: Unrecognized command format. Expected [Motor]:[Dir]:[Speed]");
return;
}
String motorID = command.substring(0, firstColon);
String direction = command.substring(firstColon + 1, secondColon);
String speedStr = command.substring(secondColon + 1);
// Error Handling: Validate speed is an integer
int speed = speedStr.toInt();
if (speed < 0 || speed > 255 || speedStr.length() == 0) {
Serial.println("Error: Speed must be an integer between 0 and 255.");
return;
}
// Execute command based on Motor ID
if (motorID == "A") {
executeMotorCommand(IN_1, IN_2, EN_A, direction, speed, "Motor A");
} else if (motorID == "B") {
executeMotorCommand(IN_3, IN_4, EN_B, direction, speed, "Motor B");
} else {
Serial.println("Error: Invalid Motor ID. Use 'A' or 'B'.");
}
}
}
void executeMotorCommand(int in1, int in2, int en, String dir, int speed, String motorName) {
if (dir == "F") {
forwardMotor(in1, in2, en, speed);
Serial.print(motorName + " Forward at speed: ");
Serial.println(speed);
} else if (dir == "B") {
backwardMotor(in1, in2, en, speed);
Serial.print(motorName + " Backward at speed: ");
Serial.println(speed);
} else if (dir == "S") {
stopMotor(in1, in2, en);
Serial.println(motorName + " Stopped.");
} else {
Serial.println("Error: Invalid Direction. Use 'F' (Forward), 'B' (Backward), or 'S' (Stop).");
}
}
// --- Motor Control Functions ---
void forwardMotor(int in1, int in2, int en, int speed) {
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
analogWrite(en, speed);
}
void backwardMotor(int in1, int in2, int en, int speed) {
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
analogWrite(en, speed);
}
void stopMotor(int in1, int in2, int en) {
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
analogWrite(en, 0);
}
Debugging: First Three Things to Check When It Fails
Motor control circuits are notorious for failing silently or behaving erratically. If your motors are not spinning as expected, follow this ranked diagnostic path before rewriting your code.
1. Symptom: Motor Hums or Clicks but Won't Spin
Most Likely Cause: Insufficient voltage reaching the motor due to the L293D's internal voltage drop, or the PWM value is below the motor's stall threshold.
The Fix: Put your multimeter in DC voltage mode. Measure the voltage directly across the motor terminals while the Arduino is commanding a speed of 255. If you are feeding 5V into VCC2, you will likely read ~3.6V. TT gearmotors often require at least 4V to overcome static friction. Upgrade your VCC2 supply to a 6V (4x AA) or 7.4V (2S LiPo) source. For more on H-bridge voltage drops, refer to the Texas Instruments L293D Datasheet.
2. Symptom: Arduino Resets or Brownouts When Motor Starts
Most Likely Cause: Back-EMF spikes or massive current inrush from the motor is pulling the Arduino's 5V rail down, triggering the ATmega328P's brownout detection (BOD).
The Fix: Ensure VCC1 (Pin 16) and VCC2 (Pin 8) are completely isolated. VCC1 should come from the Arduino's 5V pin, while VCC2 must come directly from the battery pack. Crucially, verify that the battery pack ground and Arduino ground are tied together at a single star-point on the breadboard to prevent ground loops. Never power VCC2 from the Arduino's onboard 5V regulator.
3. Symptom: Serial Monitor Prints 'Error: Unrecognized command format.'
Most Likely Cause: The Serial Monitor is appending carriage returns (CR) or the baud rate is mismatched, causing the readStringUntil('\n') function to fail or parse empty strings.
The Fix: Verify your Serial Monitor is set to exactly 115200 baud. In the Arduino IDE Serial Monitor dropdown at the bottom, change the line ending setting from 'No line ending' to 'Both NL & CR'. The code specifically looks for the newline character (\n) to terminate the string. If it receives raw data without a newline, the buffer will timeout or parse incorrectly.
Extending and Simplifying the Build
Once you have the basic L293D and Arduino circuit working, you will inevitably want to scale the project up for a robot chassis or simplify it for a permanent installation.
How to Simplify: Motor Shields
Breadboarding a DIP-16 IC with 16 jumper wires is prone to loose connections. For a permanent or cleaner build, switch to an L293D Motor Drive Shield (often sold as the 'Adafruit Motor Shield V1' or generic clones). These shields plug directly into the Arduino Uno headers, route the PWM pins internally, and provide screw terminals for motor wires and external power. This eliminates 90% of wiring-related debugging.
How to Extend: Closed-Loop Control and Efficiency
If you need precise positioning or speed maintenance under varying loads, the L293D's open-loop nature is a limitation.
- Add Encoders: Attach magnetic or optical encoders to the TT motor shafts. Read the encoder pulses using Arduino hardware interrupts (Pins 2 and 3 on the Uno) to implement a PID control loop that adjusts the PWM dynamically to maintain a target RPM.
- Upgrade the Driver: If battery life is a concern, replace the L293D with a DRV8833 or TB6612FNG module. These use MOSFETs instead of bipolar transistors, dropping the internal voltage loss from 1.4V down to ~0.4V. This means your motors get more power, and your batteries last significantly longer. For advanced shield options, review the Arduino PWM and Analog Output documentation to understand how higher-frequency PWM can reduce motor whine on MOSFET drivers.






