Working with STM32 and Timers part 4: Servo Motor Control

Servo motor

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

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 colorFunction
RedVcc (4~6V)
BrownGND
OrangeSignal

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)
05% (1mS)
907.5% (1.5mS)
18010%(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
Connection
Actual connection

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. Demo:

Add Comment

Your email address will not be published. Required fields are marked *