pwm-timer-led.c
A hardware PWM from an STM32 timer makes an LED breathe with no CPU cost: the channel compares against the counter and generates the waveform on its own. Duty cycle is expressed as a percentage of the CubeMX-configured period.
Hardware
A Nucleo F4 board (STM32F401RE/F411RE, Cortex-M4) programmed via ST-LINK (USB), 3.3 V pins. 1 LED + 330 Ω resistor (3.3 V) on the PWM channel output pin.
Wiring
LED + 330 Ω between the channel pin (chosen in the .ioc, e.g. PA0 for TIM2_CH1) and GND. Check the pin supports that timer.
How it works
HAL_TIM_PWM_Start runs the channel; __HAL_TIM_SET_COMPARE sets the next compare value. The timer counts in hardware; the loop only updates the setpoint every 10 ms.
Running it
Create a STM32CubeIDE project (pick Nucleo-F401RE or F411RE), paste the code into main.c, configure peripherals in the .ioc, then Run. The ST-LINK serial terminal shows printf at 115200.
Variants
Change the frequency via the CubeMX configuration (ARR/PSC), or drive 4 channels for 4 LEDs with one timer.
pwm-timer-led.c
// PWM sur TIMx/CHx genere par CubeMX : respiration de LED.
#include "main.h"
extern TIM_HandleTypeDef htim2; // PWM 20 kHz, periode = ARR
#define PWM_CANAL TIM_CHANNEL_1
uint32_t t0 = 0;
int16_t niveau = 0;
int8_t pas = 1;
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init(); // broche en mode PWM dans CubeMX + LED externe
HAL_TIM_PWM_Start(&htim2, PWM_CANAL);
uint32_t periode = __HAL_TIM_GET_AUTORELOAD(&htim2);
for (;;) {
if (HAL_GetTick() - t0 >= 10) {
t0 = HAL_GetTick();
niveau += pas;
if (niveau >= 100) pas = -1;
if (niveau <= 0) pas = 1;
// Rapport cyclique 0..100 % de la periode du timer.
__HAL_TIM_SET_COMPARE(&htim2, PWM_CANAL,
periode * niveau / 100);
}
}
}