servo-pwm.c

STM32F103 "Blue Pill" (STM32F103C8T6) · File : servo-pwm.c · Language : C · Use case : Piloter un servo d'angle avec un timer PWM 50 Hz

The timer configured to count microseconds generates the servo control pulse (0.5 to 2.5 ms over a 20 ms period). servo_angle converts any angle into a compare value: the basis of any robot arm in C.

Hardware

A Blue Pill STM32F103C8T6 (Cortex-M3 @ 72 MHz, 64 KB flash) powered by micro-USB or external 3.3 V; programmed over SWD or the serial bootloader. 1 hobby servo (SG90/MG90S) + external 5 V supply advised.

Wiring

Servo signal on the channel pin (e.g. PA6 for TIM3_CH1, set in the .ioc), + to external 5 V, grounds tied together.

How it works

The timer counts at 1 MHz (PSC set in CubeMX) with ARR=19999, i.e. 20 ms; the compare value sets the pulse width. The loop sweeps 0-180° in 5° steps.

Running it

STM32CubeIDE project (STM32F103C8) or Arduino (STM32 core): program over SWD (ST-LINK, DAPLink adapter) or the serial bootloader (BOOT0 to 1). Note: PC13 LED is active LOW.

Variants

Add smoothing (position interpolation), or drive 4 servos on 4 channels of one timer for a mini robot arm.

servo-pwm.c

// Servo 50 Hz : periode 20 ms, impulsion 0,5..2,5 ms.
// Timer configure dans CubeMX : PSC et ARR pour compter en us.
#include "main.h"

extern TIM_HandleTypeDef htim3; // ex. 1 MHz de comptage, ARR=19999

#define SERVO_CANAL TIM_CHANNEL_1

static void servo_angle(int angle) { // 0..180
  uint32_t us = 500 + (uint32_t)angle * 2000 / 180; // 500..2500 us
  __HAL_TIM_SET_COMPARE(&htim3, SERVO_CANAL, us);
}

uint32_t t0 = 0;
int angle = 0, sens = 1;

int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM3_Init();
  HAL_TIM_PWM_Start(&htim3, SERVO_CANAL);

  for (;;) {
    if (HAL_GetTick() - t0 >= 20) {   // pas de 20 ms
      t0 = HAL_GetTick();
      servo_angle(angle);
      angle += sens * 5;              // 5 degres par pas
      if (angle >= 180) sens = -1;
      if (angle <= 0)   sens = 1;
    }
  }
}

← Back to the board