respiration.py
The 32U4's PWM follows a sine computed on the PC: the ramp is perfectly smooth because the x86 has all the time to compute 50 points per second. The visual demo of the host-MCU couple.
Hardware required
A LattePanda 3 Delta (x86 Intel N5105, Windows 10/11 or Ubuntu) with its Arduino-compatible co-processor (ATmega32U4) wired to the two 50-pin headers. 1 LED + 330 Ω resistor on D3.
Wiring
Anode on D3 through 330 Ω, GND. D3 is a PWM pin of the ATmega (marked ~ on schematics).
How it works
write_analog writes the timer's OCR register; the sinusoidal phase is recomputed each pass. The ~1 ms serial latency is masked by the 20 ms step. Host side: pip install pinpong then python3. MCU side: the ATmega32U4 shows up as a COM port — program it with the Arduino IDE (« Arduino Leonardo » board).
Going further
A time-of-day color gradient, or breathing synced to an audio file.
respiration.py
#!/usr/bin/env python3
# Rampe de luminosite sur D3 (PWM du 32U4) — cycle complet 4 s.
from pinpong.board import Board, Pin
import time, math
Board().begin()
led = Pin(Pin.D3, Pin.PWM_OCR)
print("Respiration (Ctrl-C pour sortir)")
try:
t0 = time.time()
while True:
phase = (time.time() - t0) % 4.0 / 4.0 # 0..1
duty = int(512 + 511 * math.sin(2 * math.pi * phase))
led.write_analog(duty) # 0..1023
time.sleep(0.02)
except KeyboardInterrupt:
led.write_analog(0)
print("\nLED eteinte")