How to Control Servo Motor Using PWM in Embedded C
To control a servo motor using
PWM in Embedded C, generate a PWM signal with a period of about 20ms and vary the pulse width between 1ms and 2ms to set the servo angle. Use a timer peripheral to create this PWM signal and adjust the duty cycle to move the servo to the desired position.Syntax
To control a servo motor, you need to configure a timer to generate a PWM signal. The key parts are:
- Timer initialization: Set timer period to 20ms (50Hz frequency).
- Duty cycle: Pulse width varies from 1ms (0°) to 2ms (180°).
- Output pin: Connect the PWM output pin to the servo signal wire.
c
void PWM_Init(void) { // Configure timer for 50Hz PWM frequency (20ms period) // Set PWM output pin as output } void PWM_SetDutyCycle(uint16_t pulse_width_us) { // Set timer compare register to pulse_width_us // pulse_width_us ranges from 1000 to 2000 microseconds }
Example
This example shows how to initialize PWM and set servo angle by changing pulse width in microseconds.
c
#include <stdint.h> #include <stdio.h> // Mock functions for timer and PWM hardware void Timer_Init_50Hz(void) { // Initialize timer for 20ms period } void PWM_SetPulseWidth(uint16_t pulse_width_us) { // Set PWM pulse width in microseconds printf("PWM pulse width set to %d us\n", pulse_width_us); } void Servo_SetAngle(uint8_t angle) { // Map angle (0-180) to pulse width (1000-2000 us) if (angle > 180) angle = 180; uint16_t pulse_width = 1000 + ((uint32_t)angle * 1000) / 180; PWM_SetPulseWidth(pulse_width); } int main(void) { Timer_Init_50Hz(); // Move servo to 0 degrees Servo_SetAngle(0); // Move servo to 90 degrees Servo_SetAngle(90); // Move servo to 180 degrees Servo_SetAngle(180); return 0; }
Output
PWM pulse width set to 1000 us
PWM pulse width set to 1500 us
PWM pulse width set to 2000 us
Common Pitfalls
- Incorrect timer frequency: Using a PWM frequency other than ~50Hz can cause servo jitter or no movement.
- Pulse width out of range: Pulse widths less than 1ms or greater than 2ms may damage the servo or cause erratic behavior.
- Not initializing PWM output pin: Forgetting to set the pin as output or connect it properly will prevent servo control.
- Blocking delays: Using blocking delays instead of timer interrupts can cause unstable PWM signals.
c
/* Wrong: Using 1kHz PWM frequency (period 1ms) instead of 50Hz */ void PWM_Init_Wrong(void) { // Timer period set to 1ms (too fast for servo) } /* Right: Use 20ms period for servo PWM */ void PWM_Init_Correct(void) { // Timer period set to 20ms (50Hz) }
Quick Reference
Servo PWM control summary:
| Parameter | Value | Description |
|---|---|---|
| Frequency | 50 Hz | Servo expects 20ms period PWM signal |
| Pulse Width | 1ms to 2ms | Controls servo angle from 0° to 180° |
| Timer Setup | Configure timer for 20ms period | Use timer compare register for pulse width |
| Output Pin | GPIO PWM pin | Connect to servo signal wire |
| Parameter | Value | Description |
|---|---|---|
| Frequency | 50 Hz | Servo expects 20ms period PWM signal |
| Pulse Width | 1ms to 2ms | Controls servo angle from 0° to 180° |
| Timer Setup | Configure timer for 20ms period | Use timer compare register for pulse width |
| Output Pin | GPIO PWM pin | Connect to servo signal wire |
Key Takeaways
Use a 50Hz PWM signal with a 20ms period to control servo motors.
Vary the PWM pulse width between 1ms and 2ms to set servo angle from 0° to 180°.
Initialize the timer and PWM output pin correctly before controlling the servo.
Avoid PWM frequencies other than 50Hz to prevent servo jitter or damage.
Map servo angles to pulse widths carefully to ensure smooth movement.