In this lesson, you will learn how to map specific pulse width durations to precise angular positions to actuate a hobby servo using timer-based PWM.
Understanding the Servo Control Signal
Unlike a simple motor that spins continuously based on voltage, a hobby servo expects a specific control signal. It requires a PWM signal with a frequency of 50Hz (a 20ms period). The "angle" of the servo is not determined by the frequency, but strictly by the pulse width (the amount of time the signal stays high within that 20ms window).
Mapping Pulse Width to Angle
Standard hobby servos follow a predictable timing convention:
- 1.0ms pulse: Rotates the servo to the 0° position (minimum).
- 1.5ms pulse: Rotates the servo to the 90° position (center).
- 2.0ms pulse: Rotates the servo to the 180° position (maximum).
To control the servo, your microcontroller must adjust the Compare Register of your timer to change the duration of the high pulse while keeping the overall period constant at 20ms.
Implementation Logic
If your timer is configured with a prescaler that results in a 1MHz clock (1µs per tick), your period (20ms) would be 20,000 ticks. To set the servo to 90°, you would set your Compare Register to 1,500.
// Example: Timer period = 20,000 ticks (20ms)
// Mapping 0° to 180° (1ms to 2ms pulse width)
void set_servo_angle(uint16_t angle) {
// Convert 0-180 degree input to 1000-2000 timer ticks
uint16_t pulse_width = 1000 + (angle * 1000 / 180);
// Update the Compare Register to change pulse duration
TIMER_COMPARE_REG = pulse_width;
}
By manipulating the Compare Register, you create a variable-width pulse that the servo's internal circuitry interprets as a physical position. Because you are using hardware-based PWM, the microcontroller remains free to handle other tasks while the timer maintains the pulse signal indefinitely.
Key Takeaway: The servo position is determined exclusively by the high-time duration of the PWM signal, which you control by writing values to the timer's compare register.