Files
ArtemiaandClaude Opus 5.5 30d0e356a6 Illustre les modules 0 à 2 (9 figures)
Bibliothèque commune schemas/outils.py (boîtes, flèches, chronogrammes, séquences). M0 : chaîne de développement, séquence BOOT/RESET. M1 : architecture, comparatif Uno/ESP32-S3, diviseur de tension. M2 : pull-up, rebonds, chenillard, protocole WS2812.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:11:18 +02:00

122 lines
5.9 KiB
Python

"""Module 2 — Entrées/sorties numériques & LED RGB NeoPixel."""
import matplotlib.pyplot as plt
import numpy as np
import schemdraw
import schemdraw.elements as elm
from outils import chronogramme
from style import BLEU, CM, ENCRE, GRIS, ORANGE, ROUGE, VERT, Figure
schemdraw.use("matplotlib")
def pull_up():
d = schemdraw.Drawing(show=False)
d.config(fontsize=10.5, unit=2.4, color=ENCRE)
d += (vdd := elm.Vdd().label("3V3"))
d += (r := elm.Resistor().down().label("pull-up interne\n≈ 45 kΩ", loc="bottom").color(BLEU))
d += (n := elm.Dot())
d += (lecture := elm.Line().left().length(2.6).label("vers digitalRead()", loc="top", fontsize=9).color(BLEU))
d += elm.Line().right().at(n.center).length(2.8)
d += (gpio := elm.Dot(open=True).label("GPIO5", loc="top"))
d += elm.Line().right().length(1.2)
d += elm.Button().down().label("bouton", loc="bottom").color(ORANGE)
d += elm.Ground()
d += elm.EncircleBox([vdd, r, n, lecture, gpio], padx=0.3, pady=0.5).linestyle("--").color(GRIS)
d += elm.Label().at((n.center[0] + 1.6, vdd.end[1] + 0.2)).label("à l'intérieur\nde l'ESP32-S3", color=GRIS, fontsize=9)
d += elm.Label().at((gpio.center[0] + 3.6, n.center[1] - 2.0)).label(
"relâché → HIGH (3,3 V)\nappuyé → LOW (0 V)", fontsize=10, color=VERT)
return d.draw(show=False)
def rebonds():
t = [0]
niv = [1]
# Appui avec rebonds autour de 40 ms, relâchement avec rebonds autour de 140 ms
for a, b in ((40, 0), (41.2, 1), (42, 0), (43.5, 1), (44.1, 0), (140, 1), (140.8, 0), (141.9, 1), (142.5, 0), (143.2, 1)):
t.append(a)
niv.append(b)
voies = [("broche (brut)", list(zip(t, niv))),
("état retenu", [(0, 1), (54, 0), (153, 1)])]
fig, ax, y = chronogramme(voies, 200, largeur_cm=16, hauteur_voie_cm=1.7,
graduations=range(0, 201, 25), unite="temps (ms)",
couleurs={"état retenu": VERT})
for x0, x1, txt in ((40, 44.1, "rebonds\n(quelques ms)"), (140, 143.2, "rebonds")):
ax.axvspan(x0 - 1, x1 + 1, color=ORANGE, alpha=0.18)
ax.text((x0 + x1) / 2, y(0) + 1.25, txt, ha="center", fontsize=7.5, color=ORANGE)
ax.annotate("", xy=(54, y(1) + 0.5), xytext=(44.1, y(1) + 0.5),
arrowprops=dict(arrowstyle="<->", color=ENCRE, lw=0.9))
ax.text(49, y(1) + 0.62, "attente", ha="center", fontsize=7, color=ENCRE)
ax.text(97, y(1) + 0.3, "un seul appui détecté", ha="center", fontsize=8, color=VERT, fontweight="bold")
ax.set_ylim(-0.5, 3.9)
fig.tight_layout()
return fig
def chenillard():
d = schemdraw.Drawing(show=False)
d.config(fontsize=10.5, unit=2.2, color=ENCRE)
pins = [elm.IcPin(name=f"GPIO{g}", side="right", anchorname=f"P{g}") for g in (7, 6, 5, 4)]
ic = elm.Ic(pins=pins, size=(3.2, 5.4), pinfontsize=10).label("ESP32-S3", loc="center", fontsize=12).color(BLEU)
d += ic
couleurs = {4: ROUGE, 5: VERT, 6: BLEU, 7: ORANGE}
fins = []
for g in (4, 5, 6, 7):
d += elm.Line().right().at(getattr(ic, f"P{g}")).length(0.6)
d += elm.Resistor().right().label("220 Ω", fontsize=9)
d += elm.LED().right().color(couleurs[g])
d += elm.Line().right().length(0.6)
fins.append(d.here)
d += elm.Line().at(fins[0]).to(fins[-1])
d += elm.Line().down().at(fins[-1]).length(0.6)
d += elm.Ground()
d += elm.Label().at((fins[0][0] + 0.4, (fins[0][1] + fins[-1][1]) / 2)).label("GND\ncommun", loc="right", fontsize=9, color=GRIS)
return d.draw(show=False)
def ws2812():
fig = plt.figure(figsize=(16 * CM, 8.6 * CM))
# (a) trame 24 bits
ax1 = fig.add_axes([0.04, 0.62, 0.92, 0.3])
ax1.axis("off")
ax1.set_xlim(0, 24)
ax1.set_ylim(0, 1.6)
for k, (nom, c) in enumerate((("G", VERT), ("R", ROUGE), ("B", BLEU))):
for b in range(8):
x = k * 8 + b
ax1.add_patch(plt.Rectangle((x, 0.3), 1, 0.8, facecolor=c, alpha=0.18 + 0.06 * (7 - b) / 7,
edgecolor=c, lw=1))
ax1.text(x + 0.5, 0.7, f"{nom}{7 - b}", ha="center", va="center", fontsize=6.5, color=ENCRE)
ax1.text(k * 8 + 4, 1.25, {"G": "Vert (8 bits)", "R": "Rouge (8 bits)", "B": "Bleu (8 bits)"}[nom],
ha="center", fontsize=8.5, color=c, fontweight="bold")
ax1.text(0, 0.02, "(a) Une couleur = 24 bits, envoyés dans l'ordre G-R-B (d'où NEO_GRB), bit de poids fort en premier",
fontsize=8, color=GRIS)
# (b) codage d'un bit
ax2 = fig.add_axes([0.08, 0.12, 0.88, 0.36])
for x0, th, tl, nom in ((0, 0.4, 0.85, "bit 0"), (1.8, 0.8, 0.45, "bit 1")):
xs = [x0, x0, x0 + th, x0 + th, x0 + th + tl]
ys = [0, 1, 1, 0, 0]
ax2.plot(xs, ys, color=BLEU, lw=1.8)
ax2.fill_between([x0, x0 + th], 0, 1, color=BLEU, alpha=0.12)
ax2.text(x0 + (th + tl) / 2, 1.32, nom, ha="center", fontsize=9, fontweight="bold", color=ENCRE)
ax2.annotate("", xy=(x0, 1.1), xytext=(x0 + th, 1.1), arrowprops=dict(arrowstyle="<->", lw=0.8))
ax2.text(x0 + th / 2, 1.14, f"{th} µs".replace(".", ","), ha="center", va="bottom", fontsize=7.5)
ax2.annotate("", xy=(x0 + th, -0.12), xytext=(x0 + th + tl, -0.12), arrowprops=dict(arrowstyle="<->", lw=0.8))
ax2.text(x0 + th + tl / 2, -0.2, f"{tl} µs".replace(".", ","), ha="center", va="top", fontsize=7.5)
ax2.text(3.4, 0.55, "période d'un bit : 1,25 µs (800 kHz)\nla différence se joue à ~400 ns près :\n"
"impossible avec digitalWrite(),\nla bibliothèque utilise le matériel (RMT)",
fontsize=8, color=ENCRE, va="center")
ax2.set_xlim(-0.1, 6.2)
ax2.set_ylim(-0.5, 1.6)
ax2.axis("off")
fig.text(0.04, 0.03, "(b) Codage d'un bit : seule la durée de l'état haut change", fontsize=8, color=GRIS)
return fig
FIGURES = [
Figure("m02-pull-up", pull_up),
Figure("m02-rebonds", rebonds),
Figure("m02-chenillard", chenillard),
Figure("m02-ws2812", ws2812),
]