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 Alpha (x86 Intel m3-7Y30, Windows 10 or Linux) with its ATmega32U4 co-processor, Arduino Leonardo compatible, on the 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. The ATmega32U4 is a genuine Leonardo: flash it as « Arduino Leonardo » in the IDE through its internal COM port. Host-side, DFRobot's lattepanda Python library talks to it over serial.
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")