respiration.ino
The STM32F1 core routes analogWrite to hardware timers: PA1 is TIM2 channel 2, and frequency is set per pin. The LED breathes on a 20 kHz PWM that even the capacitors cannot hear.
Hardware required
A GD32F103C8T6 development board (Cortex-M3 at 108 MHz, Blue Pill pin-to-pin compatible), powered at 3.3 V/5 V, with an ST-Link or serial adapter. 1 LED + 330 Ω resistor on PA1.
Wiring
LED anode on PA1 through 330 Ω to GND. PA1 must stay free at boot (no strap), making it a good output pin.
How it works
analogWrite sets TIM2's channel to PWM mode and writes the compare value; the loop only ramps the setpoint. A 108 MHz time base = comfortable phase resolution. With Arduino: install the « STM32F1 » core (Roger Clark, board manager) and pick the « GD32F103C » board; the user LED is PC13 (active LOW). In C: GD32F10x firmware library + ST-Link.
Going further
Three TIM2 channels (PA0/1/2) for an RGB LED, or a MOSFET stage for a dimmable lamp.
respiration.ino
// Respiration sur PA1 (TIM2CH2) — analogWrite du core STM32F1.
const int LED = PA1;
const int FREQ = 20000; // 20 kHz : inaudible pour les composants
int niveau = 0;
int sens = 2;
void setup() {
pinMode(LED, OUTPUT);
analogWriteFrequency(LED, FREQ); // core STM32F1 : frequence par broche
Serial.begin(115200);
}
void loop() {
niveau += sens;
if (niveau >= 255 || niveau <= 0) sens = -sens;
analogWrite(LED, niveau);
delay(5); // rampe complete ~ 0,64 s
}