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>
@@ -0,0 +1,63 @@
|
||||
"""Module 4 — Communication série & débogage."""
|
||||
from outils import boite, chronogramme, fleche, toile
|
||||
from style import BLEU, ENCRE, GRIS, ORANGE, VERT, Figure
|
||||
|
||||
|
||||
def trame_uart():
|
||||
# 'A' = 0x41 = 0b01000001, envoyé bit de poids faible en premier
|
||||
donnees = [(0x41 >> k) & 1 for k in range(8)]
|
||||
bits = [1] + [0] + donnees + [1] + [1] # repos, start, D0..D7, stop, repos
|
||||
points = [(i, b) for i, b in enumerate(bits)]
|
||||
fig, ax, y = chronogramme([("TX", points)], 12, largeur_cm=16, hauteur_voie_cm=2.2)
|
||||
ax.set_xticks([])
|
||||
ax.spines["bottom"].set_visible(False)
|
||||
noms = ["repos", "start"] + [f"D{k}" for k in range(8)] + ["stop", "repos"]
|
||||
couleurs = [GRIS, ORANGE] + [BLEU] * 8 + [VERT, GRIS]
|
||||
for i, (n, c) in enumerate(zip(noms, couleurs)):
|
||||
ax.text(i + 0.5, 1.35, n, ha="center", fontsize=8, color=c, fontweight="bold")
|
||||
if 2 <= i <= 9:
|
||||
ax.text(i + 0.5, -0.35, str(bits[i]), ha="center", fontsize=9, color=ENCRE)
|
||||
ax.axvline(i, ymin=0.12, ymax=0.83, color="#e5e7eb", lw=0.7, zorder=0)
|
||||
ax.annotate("", xy=(2, 1.85), xytext=(10, 1.85), arrowprops=dict(arrowstyle="<->", lw=0.9, color=BLEU))
|
||||
ax.text(6, 1.95, "8 bits de données : 'A' = 0x41, bit de poids faible (D0) en premier",
|
||||
ha="center", va="bottom", fontsize=8, color=BLEU)
|
||||
ax.annotate("", xy=(1, -0.75), xytext=(2, -0.75), arrowprops=dict(arrowstyle="<->", lw=0.9))
|
||||
ax.text(2.15, -0.75, "1 bit = 1 / 115200 s ≈ 8,7 µs", va="center", fontsize=8, color=ENCRE)
|
||||
ax.text(12, -0.75, "8N1 : 8 bits, pas de parité, 1 bit de stop", ha="right", va="center",
|
||||
fontsize=8, color=GRIS)
|
||||
ax.set_ylim(-1.1, 2.5)
|
||||
fig.tight_layout()
|
||||
return fig
|
||||
|
||||
|
||||
def cablage_serie():
|
||||
fig, ax = toile(16, 6.8)
|
||||
pc = boite(ax, 1.8, 3.1, 3.0, 2.2, "Ordinateur\n\nMoniteur série", couleur=GRIS, taille=8.5)
|
||||
esp = boite(ax, 8.0, 3.2, 4.0, 4.6, couleur=BLEU, fond="#f5f8fe")
|
||||
ax.text(8.0, 5.1, "ESP32-S3", ha="center", fontsize=10, color=BLEU, fontweight="bold")
|
||||
mod = boite(ax, 14.0, 3.0, 3.0, 3.8, couleur=ORANGE)
|
||||
ax.text(14.0, 4.2, "Module externe\n(GPS, RFID…)", ha="center", va="center", fontsize=8.5, color=ENCRE)
|
||||
# USB natif
|
||||
boite(ax, 7.0, 4.2, 1.6, 0.6, "USB", couleur=GRIS, taille=8)
|
||||
fleche(ax, (3.3, 4.2), (6.2, 4.2), "Serial\n(USB CDC)", double=True, couleur=VERT, taille=8)
|
||||
# Broches Serial2
|
||||
for yy, nom in ((3.0, "GPIO18 (TX)"), (2.0, "GPIO17 (RX)")):
|
||||
ax.text(9.9, yy, nom, ha="right", va="center", fontsize=8.5, color=ENCRE)
|
||||
for yy, nom in ((3.0, "RX"), (2.0, "TX")):
|
||||
ax.text(12.7, yy, nom, ha="left", va="center", fontsize=8.5, color=ENCRE)
|
||||
ax.text(9.9, 1.0, "GND", ha="right", va="center", fontsize=8.5, color=ENCRE)
|
||||
ax.text(12.7, 1.0, "GND", ha="left", va="center", fontsize=8.5, color=ENCRE)
|
||||
fleche(ax, (10.0, 3.0), (12.5, 2.0), couleur=BLEU)
|
||||
fleche(ax, (12.5, 3.0), (10.0, 2.0), couleur=ORANGE)
|
||||
ax.plot([10.0, 12.5], [1.0, 1.0], color=ENCRE, lw=1.3)
|
||||
ax.text(11.25, 3.35, "croisé !", ha="center", fontsize=8.5, color=ORANGE, fontweight="bold")
|
||||
ax.text(11.25, 0.55, "masse commune", ha="center", fontsize=7.5, color=GRIS)
|
||||
ax.text(8.0, 0.15, "Serial2.begin(9600, SERIAL_8N1, 17, 18);", ha="center", fontsize=7.5,
|
||||
color=GRIS, family="monospace")
|
||||
return fig
|
||||
|
||||
|
||||
FIGURES = [
|
||||
Figure("m04-trame-uart", trame_uart),
|
||||
Figure("m04-cablage-serie", cablage_serie),
|
||||
]
|
||||
@@ -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),
|
||||
]
|
||||
@@ -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),
|
||||
]
|
||||
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 70 KiB |