
In pervious PWM guide (here), discussed how to use TIM2 of STM32F411 to generate 2 PWM signals to fade 2 LEDs. In this guide, we shall use PWM signal to control a servo motor (SG90).
In this guide, we shall cover the following
- What is servo motor and how to control it
- Connection
- Code
- Demo
1. What is servo motor and how to control it
A servomotor is a rotary actuator or linear actuator that allows for precise control of angular or linear position, velocity and acceleration.[1] It consists of a suitable motor coupled to a sensor for position feedback. It also requires a relatively sophisticated controller, often a dedicated module designed specifically for use with servomotors. (Wikipedia link).
The servo motor used in our guide has three wires: red, brown and orange.
| Wire color | Function |
| Red | Vcc (4~6V) |
| Brown | GND |
| Orange | Signal |

In order to control the angle of the servo motor, a PWM signal of frequency 50Hz (20mS period) needed to be applied to the signal pin on the servo motor. to determine the angle of the servo as following:
| Angle | Duty Cycle (Period) |
| 0 | 5% (1mS) |
| 90 | 7.5% (1.5mS) |
| 180 | 10%(2mS) |

Hence we need to configure the TIM2 to generate 50Hz PWM signal on PA0 pin
2. Connection:
In this guide, we need the following
- STM32F411 Nucleo
- SG90 microservo
- Hock-up wires


3. Code:
#include "stm32f4xx.h" // Device header
void GPIO_Init(void);
void Timer2_init(void);
void delay(int ms );
void servo_write(uint8_t angle);
int pos;
int main(void)
{
GPIO_Init();
Timer2_init();
while(1)
{
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
servo_write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
servo_write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}
}
void GPIO_Init(void)
{
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
GPIOA->AFR[0]|=(1<<0);
GPIOA->MODER|=(1<<1);
}
void Timer2_init(void){
RCC->APB1ENR|=RCC_APB1ENR_TIM2EN; //enable clock access tto tim2
TIM2->PSC=4; //set prescaller to 4 (16000000Hz/4=4000000Hz)
TIM2->ARR=63999; //set the maximum count value
TIM2->CNT=0; //seset the current count
TIM2->CCMR1=(1<<5)|(1<<6); //configure the pins as PWM
TIM2->CCER|=0x1; //enbale channel1 and channel2
TIM2->CR1=1; //enable timer
}
void delay(int ms)
{
int i;
for(; ms>0 ;ms--)
{
for(i =0; i<3195;i++);
}
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void servo_write(uint8_t angle)
{
if(angle<0){angle=0;}
if(angle>180){angle=180;}
TIM2->CCR1=map (angle,0,180,2500,7000);
}
4 Comments
Thanks for your nice and kind helping me and spends alot of time to prepare EmbeddedExpertIO site Mr Husamuldeen.
May ı ask a question for you.
How can we run the program to my card f429 or f407, f103. Can you explain me
Thanks
God bless you
Huseyin AKGUL
Elektronik-Software
Ankara TURKIYE
For STM32F4xx, it will be the same.
For F103, it will be similar with minor modification.
Check this for how to generate PWM signal using F103:
https://blog.embeddedexpert.io/?p=1400
Hi friend
I am using a STM32L053R8
I had to change the line:
RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
but I have an error when running the program, when the motor starts to work it does so slowly and does not oscillate between 0 and 180
Do you have any idea why this happens?
Hi,
this is how to generate PWM on STM32L0:
https://blog.embeddedexpert.io/?p=1012
Add Comment