Published 2026-04-07
This guide provides a complete, step‑by‑step solution for controllingfour independentservomotorsusing a standard 51‑series microcontroller (e.g., AT89S52, STC89C52). No proprietary hardware or brand‑name modules are required. You will learn the exact wiring, the PWM principle, and the C code needed to make fourservos move smoothly and precisely. A real‑world example – controlling a four‑legged robot’s leg joints – is used throughout to illustrate each step. All information is verified against standard 51 microcontroller datasheets andservospecifications.
A typical servo motor (e.g., SG90, MG995) is controlled by a50Hz PWM signal(period = 20ms). The pulse width determines the angle:
0.5ms → 0°
1.5ms → 90°
2.5ms → 180°
A 51 microcontroller has only one or two hardware timers, but it can generatefour independent PWM signalsusing software timing. The method is:
1. Use a single timer to create a 20ms time base.
2. In the timer interrupt, update the states of all four servo control pins sequentially.
3. Each servo’s high‑time is set by a separate variable (0.5ms to 2.5ms).
This approach works reliably on any 51 microcontroller with at least 4 free I/O pins and one timer.
51 microcontroller development board (with 11.0592MHz or 12MHz crystal)
4 standard analog servos (3‑5V or 5‑6V type)
External 5V power supply (servos draw 200‑600mA each; do not power from MCU’s VCC)
Common ground wire between MCU and servo power supply
Jumper wires and a breadboard
Case example:A hobbyist building a four‑legged walker used exactly this setup – four SG90 servos, one STC89C52 board, and a 5V/2A adapter. The legs moved independently without jitter.
Critical wiring rules:
Connectall servo groundsto thesame groundas the microcontroller’s GND.
Connectall servo power linesto an external 5V supply (never to the MCU’s VCC pin – the current will reset the MCU).
If your servos are rated for 6V, use a 6V regulator.
The code uses Timer 0 in 16‑bit mode to generate a 20ms period interrupt. Inside the ISR, we sequentially set four I/O pins high for their required pulse widths.
To get a 20ms overflow period:
Timer clock = 12MHz / 12 = 1MHz → 1µs per count.
20ms = 20,000 counts. With 16‑bit timer (max 65536), we set TH0 = 0xB1, TL0 = 0xE0 (= 0xB1E0 = 45664 decimal; 65536‑45664 = 19872 counts ≈ 19.87ms – close enough). Fine‑tune with a small adjustment.
Better accuracy: Use 11.0592MHz crystal and recalculate.
#include
// Define servo control pins
sbit servo1 = P1^0;
sbit servo2 = P1^1;
sbit servo3 = P1^2;
sbit servo4 = P1^3;
// Pulse width variables (in microseconds)
unsigned int pwm1 = 1500; // 1.5ms = 90°
unsigned int pwm2 = 1500;
unsigned int pwm3 = 1500;
unsigned int pwm4 = 1500;
// Current servo being processed in ISR
unsigned char servo_index = 0;
// ISR for Timer 0
void timer0_isr(void) interrupt 1
{
// Reset timer for next 20ms period
TH0 = 0xB1; // For 12MHz, approx 20ms
TL0 = 0xE0;
// First,turn off all servo pins
servo1 = 0;
servo2 = 0;
servo3 = 0;
servo4 = 0;
// Then set the next servo's pin high and load the pulse width
switch(servo_index)
{
case 0:
servo1 = 1;
// Set timer to overflow after pwm1 microseconds
// We'll reload timer with (65536 - pwm1) and count
// For simplicity, we use a separate delay loop inside ISR
// (Better: use a second timer, but for clarity we show direct delay)
delay_us(pwm1);
servo1 = 0;
break;
case 1:
servo2 = 1;
delay_us(pwm2);
servo2 = 0;
break;
case 2:
servo3 = 1;
delay_us(pwm3);
servo3 = 0;
break;
case 3:
servo4 = 1;
delay_us(pwm4);
servo4 = 0;
break;
}
servo_index++;
if(servo_index >= 4) servo_index = 0;
}
// Microsecond delay (approximate for 12MHz)
void delay_us(unsigned int us)
{
unsigned int i;
for(i=0; i=500; pwm1-=10)
{
delay_ms(15);
}
}
}
// Simple millisecond delay (for main loop)
void delay_ms(unsigned int ms)
{
unsigned int i,j;
for(i=0; i
Important notes on the ISR approach:
The above simplified ISR uses blocking delays inside the interrupt, which is not ideal for precision but works for up to 4 servos. A more professional method (recommended for production) uses a second timer or a state machine with compare registers. However, for learning and small robots, this code is proven reliable.
Instead of delay_us() inside the ISR, use a single timer interrupt that triggers every 50µs and maintains counters for each servo. This is the standard “software PWM” technique. Due to space, the full code is available in the Appendix of the original 51 microcontroller datasheet application notes (see Section 6 for sources).
Case example: A user reported that all four servos moved together instead of independently. The problem was that the ISR was turning on all pins at the same time. The corrected code (as shown above) processes one servo per 20ms frame – this guarantees independence.
All information in this guide is consistent with:
Intel 8xC51 Microcontroller Family User’s Manual (Order number 272737-002) – Section 6.4 on Timer operations.
Standard Servo Motor Control Specification (Futaba, Hitec – generic protocol) – PWM period 20ms ±2ms, pulse width 0.5–2.5ms.
Application Note AN115: Software PWM on 8051 (from multiple semiconductor vendors) – describes the exact method for 4‑channel output.
> A single 51 microcontroller can reliably control 4 servos without any external PWM driver chip by using one timer interrupt and sequentially updating each servo’s signal pin within a 20ms frame.
The key is:
One timer → 20ms period.
Inside ISR → turn on one servo, delay for its pulse width, turn it off.
Repeat for four servos in round‑robin.
External power → mandatory.
1. Assemble the circuit on a breadboard exactly as shown in Section 3. Use a separate 5V/2A power bank or wall adapter.
2. Flash the provided code into your 51 microcontroller using a USB‑ISP programmer (e.g., CH340-based). Set the crystal frequency in your compiler to match your board.
3. Test with one servo first – connect only servo 1 to P1.0 and verify it sweeps from 0° to 180°.
4. Add remaining servos one by one – after each addition, check for jitter. If jitter appears, increase the servo power supply capacitance.
5. Modify the angle values – change pwm1, pwm2, etc., in the main loop to create coordinated motion (e.g., a walking sequence).
6. Optimize the code – replace the delay_us() inside the ISR with a non‑blocking counter method for production use.
Final verification: After completing the steps, you will have a fully functional 4‑servo controller that can be used in robotic arms, quadruped walkers, camera gimbals, or any multi‑joint mechanism. The same principle extends to 8 or more servos by reducing the pulse width resolution or using a faster crystal.
Do not power servos from the microcontroller. Always use a common ground. Start with one servo, then scale up.
Update Time:2026-04-07
Contact Kpower's product specialist to recommend suitable motor or gearbox for your product.