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
+117
View File
@@ -0,0 +1,117 @@
"""Module 5 — Bus I2C et SPI."""
import matplotlib.pyplot as plt
from outils import boite, toile
from style import BLEU, CM, ENCRE, GRIS, ORANGE, VERT, Figure
def bus_i2c():
fig, ax = toile(16, 6.4)
maitre = boite(ax, 1.9, 3.2, 3.0, 2.6, couleur=BLEU)
ax.text(1.9, 3.75, "ESP32-S3", ha="center", fontsize=10, color=BLEU, fontweight="bold")
ax.text(1.9, 2.95, "maître\n(génère SCL)", ha="center", va="center", fontsize=8, color=ENCRE)
y_sda, y_scl = 4.0, 2.4
ax.plot([3.4, 15.6], [y_sda, y_sda], color=BLEU, lw=2)
ax.plot([3.4, 15.6], [y_scl, y_scl], color=ORANGE, lw=2)
ax.text(3.5, y_sda + 0.15, "SDA (GPIO8) — données", fontsize=8.5, color=BLEU, va="bottom")
ax.text(3.5, y_scl + 0.15, "SCL (GPIO9) — horloge", fontsize=8.5, color=ORANGE, va="bottom")
# Résistances de tirage
ax.plot([7.5, 9.5], [5.9, 5.9], color=ENCRE, lw=1.3)
ax.text(8.5, 6.05, "3V3", ha="center", fontsize=8, color=ENCRE)
for x, yb in ((7.8, y_sda), (9.2, y_scl)):
ax.plot([x, x], [5.9, 5.6], color=ENCRE, lw=1.3)
ax.add_patch(plt.Rectangle((x - 0.15, 4.7 if yb == y_sda else 4.2), 0.3, 0.9 if yb == y_sda else 1.4,
fill=False, ec=ENCRE, lw=1.3))
ax.plot([x, x], [4.7 if yb == y_sda else 4.2, yb], color=ENCRE, lw=1.3)
ax.plot(x, yb, "o", color=ENCRE, ms=4)
ax.text(9.5, 5.2, "résistances de tirage\n(souvent déjà sur les modules)", fontsize=7.5, color=GRIS, va="center")
# Esclaves
for x, nom, adr in ((6.0, "Écran OLED\nSSD1306", "0x3C"), (11.5, "Capteur\nBME280", "0x76"),
(14.6, "autre\nmodule", "0x??")):
boite(ax, x, 0.85, 2.7, 1.45, f"{nom}\nadresse {adr}", couleur=VERT, taille=7.2)
for dx, yb, c in ((-0.5, y_sda, BLEU), (0.5, y_scl, ORANGE)):
ax.plot([x + dx, x + dx], [1.5, yb], color=c, lw=1.5)
ax.plot(x + dx, yb, "o", color=c, ms=4)
ax.text(1.9, 1.05, "tous sur les 2 mêmes fils :\nchacun répond\nà son adresse", ha="center", va="center",
fontsize=7.2, color=GRIS, style="italic")
return fig
def trame_i2c():
# Écriture vers l'adresse 0x3C (0111100), R/W = 0, ACK, octet 0xAF, ACK
adresse = [0, 1, 1, 1, 1, 0, 0]
donnee = [1, 0, 1, 0, 1, 1, 1, 1]
bits = adresse + [0] + [0] + donnee + [0]
roles = ["adr"] * 7 + ["rw"] + ["ack"] + ["data"] * 8 + ["ack"]
fig, ax = plt.subplots(figsize=(16 * CM, 5.6 * CM))
t0 = 1.0
scl_x, scl_y, sda_x, sda_y = [0, t0], [1, 1], [0, 0.5], [1, 1]
sda_x += [0.5]
sda_y += [0] # START : SDA descend pendant que SCL est haut
scl_x += [t0]
scl_y += [0]
for k, b in enumerate(bits):
x = t0 + k
scl_x += [x + 0.5, x + 0.5, x + 1, x + 1]
scl_y += [0, 1, 1, 0]
sda_x += [x + 0.15, x + 0.15]
sda_y += [sda_y[-1], b]
fin = t0 + len(bits)
scl_x += [fin + 0.4, fin + 0.4, fin + 1.4]
scl_y += [0, 1, 1]
sda_x += [fin + 0.15, fin + 0.15, fin + 0.8, fin + 0.8, fin + 1.4]
sda_y += [sda_y[-1], 0, 0, 1, 1] # STOP : SDA monte pendant que SCL est haut
ax.plot(scl_x, [v + 2 for v in scl_y], color=ORANGE, lw=1.6)
ax.plot(sda_x, sda_y, color=BLEU, lw=1.6)
couleurs = {"adr": BLEU, "rw": BLEU, "ack": VERT, "data": BLEU}
for k, (b, r) in enumerate(zip(bits, roles)):
x = t0 + k
ax.axvspan(x, x + 1, ymin=0.08, ymax=0.42, color=couleurs[r], alpha=0.07 if r != "ack" else 0.2, lw=0)
ax.text(x + 0.5, -0.35, str(b), ha="center", fontsize=7.5, color=ENCRE)
groupes = [(0, 1, "START", ORANGE), (t0, t0 + 7, "adresse 0x3C (7 bits)", BLEU), (t0 + 7, t0 + 8, "R/W", BLEU),
(t0 + 8, t0 + 9, "ACK", VERT), (t0 + 9, t0 + 17, "donnée (8 bits)", BLEU),
(t0 + 17, t0 + 18, "ACK", VERT), (fin, fin + 1.4, "STOP", ORANGE)]
for a, b, txt, c in groupes:
ax.annotate("", xy=(a + 0.05, 3.45), xytext=(b - 0.05, 3.45),
arrowprops=dict(arrowstyle="|-|", color=c, lw=0.9, mutation_scale=3))
ax.text((a + b) / 2, 3.6, txt, ha="center", va="bottom", fontsize=7.3, color=c, fontweight="bold")
ax.text(-0.3, 2.5, "SCL", ha="right", va="center", fontsize=9, fontweight="bold", color=ORANGE)
ax.text(-0.3, 0.5, "SDA", ha="right", va="center", fontsize=9, fontweight="bold", color=BLEU)
ax.text(fin + 1.4, -0.75, "ACK (en vert) : c'est l'esclave qui tire SDA à 0 pour accuser réception",
ha="right", fontsize=7.5, color=VERT)
ax.set_xlim(-0.4, fin + 1.6)
ax.set_ylim(-0.95, 4.2)
ax.axis("off")
fig.tight_layout()
return fig
def bus_spi():
fig, ax = toile(16, 6.4)
boite(ax, 2.0, 3.2, 3.2, 4.4, couleur=BLEU)
ax.text(2.0, 4.55, "ESP32-S3\nmaître", ha="center", va="center", fontsize=9.5, color=BLEU, fontweight="bold")
lignes = [("SCK", 4.2, ORANGE, "horloge"), ("MOSI", 3.5, BLEU, "maître → esclave"),
("MISO", 2.8, VERT, "esclave → maître")]
for nom, yy, c, role in lignes:
ax.plot([3.6, 15.4], [yy, yy], color=c, lw=2)
ax.text(3.75, yy + 0.08, f"{nom} — {role}", fontsize=8, color=c, va="bottom")
esclaves = [(9.0, "Écran TFT", "CS1"), (13.5, "Carte SD", "CS2")]
for i, (x, nom, cs) in enumerate(esclaves):
boite(ax, x, 0.8, 2.8, 1.1, nom, couleur=GRIS, taille=8.5)
for dx, (_, yy, c, _r) in zip((-0.9, -0.3, 0.3), lignes):
ax.plot([x + dx, x + dx], [1.35, yy], color=c, lw=1.4)
ax.plot(x + dx, yy, "o", color=c, ms=3.5)
ycs = 1.9 - i * 0.45
ax.plot([3.6, x + 0.9, x + 0.9], [ycs, ycs, 1.35], color=ENCRE, lw=1.4, ls="--" if i else "-")
ax.text(3.75, ycs + 0.06, cs, fontsize=7.8,
color=ENCRE, va="bottom")
ax.text(15.4, 5.6, "SCK, MOSI, MISO : partagés\nCS (Chip Select) : une ligne par périphérique,\nle maître met à 0 celle de son interlocuteur",
ha="right", va="center", fontsize=7.8, color=GRIS, style="italic")
return fig
FIGURES = [
Figure("m05-bus-i2c", bus_i2c),
Figure("m05-trame-i2c", trame_i2c),
Figure("m05-bus-spi", bus_spi),
]