Illustre les modules 4 à 6 (9 figures)

M4 : trame UART 8N1, câblage série croisé. M5 : bus I2C, trame I2C, bus SPI. M6 : tâches millis(), déroulé d'une ISR, modes de déclenchement, encodeur rotatif.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Artemia
2026-10-18 15:15:43 +02:00
co-authored by Claude Opus 5.5
parent 499d11402b
commit 372c5a3e1e
24 changed files with 16951 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
"""Module 6 — Interruptions matérielles & timers."""
import matplotlib.pyplot as plt
import numpy as np
from outils import chronogramme
from style import BLEU, CM, ENCRE, GRIS, ORANGE, ROUGE, VERT, Figure
def taches_millis():
fig, ax = plt.subplots(figsize=(16 * CM, 6.6 * CM))
duree = 5200
# loop() : itérations très rapides
ax.vlines(np.arange(0, duree, 40), 3.1, 3.7, color=GRIS, lw=0.6)
# LED toutes les 300 ms
t = np.arange(0, duree + 300, 300)
niveaux = np.arange(len(t)) % 2
ax.step(t, 2.0 + niveaux * 0.6, where="post", color=BLEU, lw=1.6)
# NeoPixel toutes les 1000 ms
teintes = [ROUGE, VERT, BLEU, "#f5f5f5", ROUGE, VERT]
for k in range(6):
ax.add_patch(plt.Rectangle((k * 1000, 0.95), min(1000, duree - k * 1000), 0.6,
facecolor=teintes[k], edgecolor=GRIS, lw=0.6, alpha=0.85))
# Debug toutes les 5000 ms
for x in (0, 5000):
ax.plot(x, 0.3, marker="v", color=ORANGE, ms=8)
ax.text(x + 60, 0.3, "Serial.print", fontsize=7, color=ORANGE, va="center")
noms = [(3.4, "loop()", GRIS), (2.3, "LED (300 ms)", BLEU), (1.25, "NeoPixel (1 s)", ENCRE),
(0.3, "debug (5 s)", ORANGE)]
for yy, n, c in noms:
ax.text(-80, yy, n, ha="right", va="center", fontsize=8.5, color=c, fontweight="bold")
ax.text(duree, 3.85, "loop() tourne en permanence : à chaque tour, on teste « l'heure est-elle venue ? »",
ha="right", fontsize=7.5, color=GRIS, style="italic")
ax.set_xlim(-50, duree)
ax.set_ylim(-0.1, 4.2)
ax.set_yticks([])
ax.spines["left"].set_visible(False)
ax.set_xticks(range(0, 5001, 1000), [f"{s} s" for s in range(6)])
ax.set_xlabel("millis()")
ax.grid(axis="y", visible=False)
fig.tight_layout()
return fig
def deroule_isr():
fig, ax = plt.subplots(figsize=(16 * CM, 5.0 * CM))
# Signal du bouton
ax.step([0, 3.0, 6.0, 10], [2.6, 1.9, 2.6, 2.6], where="post", color=BLEU, lw=1.6)
ax.text(-0.15, 2.25, "bouton\n(GPIO5)", ha="right", va="center", fontsize=8.5, fontweight="bold", color=BLEU)
ax.annotate("front descendant\n(FALLING)", xy=(3.0, 2.25), xytext=(1.2, 3.25), fontsize=7.5, color=BLEU,
arrowprops=dict(arrowstyle="-|>", color=BLEU, lw=0.8), ha="center")
# Exécution du processeur
y = 0.6
ax.broken_barh([(0, 3.0), (3.35, 6.65)], (y, 0.7), facecolors=BLEU, alpha=0.25, edgecolor=BLEU)
ax.broken_barh([(3.0, 0.35)], (y, 0.7), facecolors=ROUGE, edgecolor=ROUGE)
ax.broken_barh([(5.0, 1.2)], (y, 0.7), facecolors=VERT, alpha=0.55, edgecolor=VERT)
ax.text(-0.15, y + 0.35, "processeur", ha="right", va="center", fontsize=8.5, fontweight="bold", color=ENCRE)
ax.text(1.5, y + 0.35, "loop()", ha="center", va="center", fontsize=8)
ax.text(8.1, y + 0.35, "loop()", ha="center", va="center", fontsize=8)
ax.annotate("ISR très courte :\ninterruptionDetectee = true", xy=(3.17, y), xytext=(3.4, -0.55),
fontsize=7.5, color=ROUGE, arrowprops=dict(arrowstyle="-|>", color=ROUGE, lw=0.8))
ax.text(5.6, y + 0.35, "traitement", ha="center", va="center", fontsize=7.5)
ax.text(5.6, y + 0.95, "if (interruptionDetectee) …", ha="center", fontsize=7.2, color=VERT,
family="monospace")
ax.set_xlim(-1.6, 10)
ax.set_ylim(-0.8, 3.9)
ax.axis("off")
fig.tight_layout()
return fig
def modes_declenchement():
pts = [(0, 0), (1.5, 1), (4, 0), (6, 1), (8.5, 0)]
fig, ax, y = chronogramme([("signal", pts)], 10, largeur_cm=16, hauteur_voie_cm=3.4)
ax.set_xticks([])
ax.spines["bottom"].set_visible(False)
lignes = [("RISING", [1.5, 6], BLEU), ("FALLING", [4, 8.5], ORANGE), ("CHANGE", [1.5, 4, 6, 8.5], VERT)]
for k, (nom, xs, c) in enumerate(lignes):
yy = -0.7 - k * 0.7
ax.text(-0.25, yy, nom, ha="right", va="center", fontsize=8.5, fontweight="bold", color=c)
ax.plot([0, 10], [yy, yy], color="#e5e7eb", lw=0.8)
for x in xs:
ax.plot(x, yy, marker="o", color=c, ms=7)
ax.plot([x, x], [yy, 0], color=c, lw=0.6, ls=":")
ax.set_ylim(-3.0, 1.5)
ax.text(10, -2.8, "● = instant où l'ISR est appelée", ha="right", fontsize=7.5, color=GRIS)
fig.tight_layout()
return fig
def encodeur():
fig, axes = plt.subplots(1, 2, figsize=(16 * CM, 5.2 * CM))
cas = [("Rotation dans un sens", 0.0, "DT = HIGH → compteur++", BLEU),
("Rotation dans l'autre sens", 0.5, "DT = LOW → compteur--", ORANGE)]
t = np.linspace(0, 4, 2000)
for ax, (titre, dephasage, regle, c) in zip(axes, cas):
clk = ((t % 2) < 1).astype(float)
dt = (((t - 0.5 + dephasage * 2) % 2) < 1).astype(float)
ax.plot(t, clk + 1.6, color=BLEU, lw=1.6)
ax.plot(t, dt, color=GRIS, lw=1.6)
ax.text(-0.1, 2.1, "CLK", ha="right", va="center", fontsize=8.5, fontweight="bold", color=BLEU)
ax.text(-0.1, 0.5, "DT", ha="right", va="center", fontsize=8.5, fontweight="bold", color=GRIS)
for x in (1, 3):
ax.plot([x, x], [-0.25, 2.8], color=c, lw=1, ls="--")
etat = dt[np.searchsorted(t, x + 0.01)]
ax.plot(x, etat, "o", color=c, ms=6)
ax.set_title(titre, fontsize=9, loc="left")
ax.text(2, -0.75, regle, ha="center", fontsize=8.5, color=c, fontweight="bold")
ax.set_xlim(-0.6, 4)
ax.set_ylim(-1.0, 2.9)
ax.axis("off")
fig.text(0.5, 0.02, "À chaque front descendant de CLK (pointillés), l'ISR lit l'état de DT. "
"Le sens réel dépend du câblage.", ha="center", fontsize=7.5, color=GRIS, style="italic")
fig.tight_layout(rect=(0, 0.06, 1, 1))
return fig
FIGURES = [
Figure("m06-taches-millis", taches_millis),
Figure("m06-deroule-isr", deroule_isr),
Figure("m06-modes-declenchement", modes_declenchement),
Figure("m06-encodeur", encodeur),
]