Passe à Quarto : projet, gabarit PDF (Typst) et module 3 en .qmd
Le Markdown remplace le .odt binaire comme source : modifications lisibles dans git, PDF produit par 'quarto render'. Le gabarit reprend la charte des supports (titres bleus, encadrés, code coloré, en-tête et pied de page). Conversion vérifiée : 865 mots, aucun écart avec le .odt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8012ce98b3
commit
ff1628efeb
@@ -22,3 +22,11 @@ secrets.h
|
|||||||
# Environnement Python
|
# Environnement Python
|
||||||
.venv/
|
.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
||||||
|
/.quarto/
|
||||||
|
**/*.quarto_ipynb
|
||||||
|
|
||||||
|
# Sorties Quarto (PDF générés)
|
||||||
|
_output/
|
||||||
|
.quarto/
|
||||||
|
modules/*.typ
|
||||||
|
|||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
project:
|
||||||
|
type: default
|
||||||
|
output-dir: _output
|
||||||
|
render:
|
||||||
|
- modules/*.qmd
|
||||||
|
|
||||||
|
lang: fr
|
||||||
|
subtitle: "Formation ESP32-S3 avec Arduino Framework"
|
||||||
|
|
||||||
|
crossref:
|
||||||
|
fig-title: Figure
|
||||||
|
fig-prefix: figure
|
||||||
|
|
||||||
|
format:
|
||||||
|
typst:
|
||||||
|
papersize: a4
|
||||||
|
margin:
|
||||||
|
x: 2cm
|
||||||
|
y: 2.2cm
|
||||||
|
mainfont: "Segoe UI"
|
||||||
|
fontsize: 10pt
|
||||||
|
codefont: "Consolas"
|
||||||
|
toc: false
|
||||||
|
highlight-style: modele/code.theme
|
||||||
|
include-in-header: modele/entete.typ
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
{
|
||||||
|
"custom-styles": {
|
||||||
|
"INI Files": {
|
||||||
|
"Section": {
|
||||||
|
"selected-text-color": "#6f42c1",
|
||||||
|
"text-color": "#6f42c1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Python": {
|
||||||
|
"Builtin Function": {
|
||||||
|
"selected-text-color": "#6f42c1",
|
||||||
|
"text-color": "#6f42c1"
|
||||||
|
},
|
||||||
|
"Import": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"Special Variable": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Rust": {
|
||||||
|
"Attribute": {
|
||||||
|
"selected-text-color": "#24292e",
|
||||||
|
"text-color": "#24292e"
|
||||||
|
},
|
||||||
|
"Macro": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"Self": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"Trait": {
|
||||||
|
"selected-text-color": "#24292e",
|
||||||
|
"text-color": "#24292e"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"XML": {
|
||||||
|
"Element": {
|
||||||
|
"selected-text-color": "#22863a",
|
||||||
|
"text-color": "#22863a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"editor-colors": {
|
||||||
|
"BackgroundColor": "#ffffff",
|
||||||
|
"BracketMatching": "#bef5cb",
|
||||||
|
"CodeFolding": "#f6f8fa",
|
||||||
|
"CurrentLine": "#f6f8fa",
|
||||||
|
"CurrentLineNumber": "#24292e",
|
||||||
|
"IconBorder": "#ffffff",
|
||||||
|
"IndentationLine": "#d7dbe0",
|
||||||
|
"LineNumbers": "#c7c2bc",
|
||||||
|
"MarkBookmark": "#8be9fd",
|
||||||
|
"MarkBreakpointActive": "#ff5555",
|
||||||
|
"MarkBreakpointDisabled": "#bd93f9",
|
||||||
|
"MarkBreakpointReached": "#f1fa8c",
|
||||||
|
"MarkError": "#b31d28",
|
||||||
|
"MarkExecution": "#44475a",
|
||||||
|
"MarkWarning": "#e36209",
|
||||||
|
"ModifiedLines": "#d73a49",
|
||||||
|
"ReplaceHighlight": "#50fa7b",
|
||||||
|
"SavedLines": "#28a745",
|
||||||
|
"SearchHighlight": "#ffea7f",
|
||||||
|
"Separator": "#e1e4e8",
|
||||||
|
"SpellChecking": "#ff5555",
|
||||||
|
"TabMarker": "#d1d5da",
|
||||||
|
"TemplateBackground": "#23241e",
|
||||||
|
"TemplateFocusedPlaceholder": "#22231d",
|
||||||
|
"TemplatePlaceholder": "#22231d",
|
||||||
|
"TemplateReadOnlyPlaceholder": "#262721",
|
||||||
|
"TextSelection": "#dee6fc",
|
||||||
|
"WordWrapMarker": "#e1e4e8"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"copyright": [
|
||||||
|
"SPDX-FileCopyrightText: 2020 GitHub Inc.",
|
||||||
|
"SPDX-FileCopyrightText: 2020 Waqar Ahmed <waqar.17a@gmail.com>"
|
||||||
|
],
|
||||||
|
"license": "SPDX-License-Identifier: MIT",
|
||||||
|
"name": "GitHub Light",
|
||||||
|
"revision": 2
|
||||||
|
},
|
||||||
|
"text-styles": {
|
||||||
|
"Alert": {
|
||||||
|
"bold": true,
|
||||||
|
"selected-text-color": "#ff5555",
|
||||||
|
"text-color": "#ff5555"
|
||||||
|
},
|
||||||
|
"Annotation": {
|
||||||
|
"selected-text-color": "#6a737d",
|
||||||
|
"text-color": "#6a737d"
|
||||||
|
},
|
||||||
|
"Attribute": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"BaseN": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"BuiltIn": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"Char": {
|
||||||
|
"selected-text-color": "#032f62",
|
||||||
|
"text-color": "#032f62"
|
||||||
|
},
|
||||||
|
"Comment": {
|
||||||
|
"selected-text-color": "#6a737d",
|
||||||
|
"text-color": "#6a737d"
|
||||||
|
},
|
||||||
|
"CommentVar": {
|
||||||
|
"selected-text-color": "#6a737d",
|
||||||
|
"text-color": "#6a737d"
|
||||||
|
},
|
||||||
|
"Constant": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"ControlFlow": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"DataType": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"DecVal": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"Documentation": {
|
||||||
|
"selected-text-color": "#6a737d",
|
||||||
|
"text-color": "#6a737d"
|
||||||
|
},
|
||||||
|
"Error": {
|
||||||
|
"selected-text-color": "#ff5555",
|
||||||
|
"text-color": "#ff5555",
|
||||||
|
"underline": true
|
||||||
|
},
|
||||||
|
"Extension": {
|
||||||
|
"bold": true,
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"Float": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"Function": {
|
||||||
|
"selected-text-color": "#6f42c1",
|
||||||
|
"text-color": "#6f42c1"
|
||||||
|
},
|
||||||
|
"Import": {
|
||||||
|
"selected-text-color": "#032f62",
|
||||||
|
"text-color": "#032f62"
|
||||||
|
},
|
||||||
|
"Information": {
|
||||||
|
"selected-text-color": "#6a737d",
|
||||||
|
"text-color": "#6a737d"
|
||||||
|
},
|
||||||
|
"Keyword": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"Normal": {
|
||||||
|
"selected-text-color": "#24292e",
|
||||||
|
"text-color": "#24292e"
|
||||||
|
},
|
||||||
|
"Operator": {
|
||||||
|
"selected-text-color": "#24292e",
|
||||||
|
"text-color": "#24292e"
|
||||||
|
},
|
||||||
|
"Others": {
|
||||||
|
"selected-text-color": "#6f42c1",
|
||||||
|
"text-color": "#6f42c1"
|
||||||
|
},
|
||||||
|
"Preprocessor": {
|
||||||
|
"selected-text-color": "#d73a49",
|
||||||
|
"text-color": "#d73a49"
|
||||||
|
},
|
||||||
|
"RegionMarker": {
|
||||||
|
"selected-text-color": "#6a737d",
|
||||||
|
"text-color": "#6a737d"
|
||||||
|
},
|
||||||
|
"SpecialChar": {
|
||||||
|
"selected-text-color": "#005cc5",
|
||||||
|
"text-color": "#005cc5"
|
||||||
|
},
|
||||||
|
"SpecialString": {
|
||||||
|
"selected-text-color": "#032f62",
|
||||||
|
"text-color": "#032f62"
|
||||||
|
},
|
||||||
|
"String": {
|
||||||
|
"selected-text-color": "#032f62",
|
||||||
|
"text-color": "#032f62"
|
||||||
|
},
|
||||||
|
"Variable": {
|
||||||
|
"selected-text-color": "#e36209",
|
||||||
|
"text-color": "#e36209"
|
||||||
|
},
|
||||||
|
"VerbatimString": {
|
||||||
|
"selected-text-color": "#032f62",
|
||||||
|
"text-color": "#032f62"
|
||||||
|
},
|
||||||
|
"Warning": {
|
||||||
|
"selected-text-color": "#ff5555",
|
||||||
|
"text-color": "#ff5555"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"background-color": "#f6f8fa"
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// Note : Quarto décale les titres d'un niveau (## -> niveau 1, ### -> niveau 2).
|
||||||
|
// Gabarit commun des supports : couleurs, titres, en-tête et pied de page.
|
||||||
|
#let bleu-formation = rgb("#1a5fb4")
|
||||||
|
#let gris-doux = rgb("#6b7280")
|
||||||
|
|
||||||
|
#set page(
|
||||||
|
header: context {
|
||||||
|
if counter(page).get().first() > 1 [
|
||||||
|
#set text(size: 8pt, fill: gris-doux)
|
||||||
|
Formation ESP32-S3 avec Arduino Framework
|
||||||
|
#h(1fr)
|
||||||
|
#document.title
|
||||||
|
#v(-4pt)
|
||||||
|
#line(length: 100%, stroke: 0.4pt + gris-doux)
|
||||||
|
]
|
||||||
|
},
|
||||||
|
footer: context [
|
||||||
|
#set text(size: 8pt, fill: gris-doux)
|
||||||
|
#h(1fr)
|
||||||
|
#counter(page).display("1 / 1", both: true)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
#show heading.where(level: 1): it => block(above: 1.6em, below: 0.8em, width: 100%)[
|
||||||
|
#set text(size: 14pt, weight: "semibold", fill: bleu-formation)
|
||||||
|
#it.body
|
||||||
|
#v(-6pt)
|
||||||
|
#line(length: 100%, stroke: 0.6pt + bleu-formation.lighten(60%))
|
||||||
|
]
|
||||||
|
#show heading.where(level: 2): set text(size: 11.5pt, weight: "semibold", fill: bleu-formation)
|
||||||
|
#show heading.where(level: 2): set block(above: 1.3em, below: 0.6em)
|
||||||
|
|
||||||
|
// Code : le fond et les couleurs viennent du thème modele/code.theme
|
||||||
|
#show raw: set text(size: 8.5pt)
|
||||||
|
|
||||||
|
// Tableaux : en-tête bleu
|
||||||
|
#set table(
|
||||||
|
stroke: 0.5pt + rgb("#d0d7de"),
|
||||||
|
fill: (_, y) => if y == 0 { bleu-formation } else if calc.even(y) { rgb("#f6f8fa") },
|
||||||
|
)
|
||||||
|
#show table.cell.where(y: 0): set text(fill: white, weight: "bold")
|
||||||
|
|
||||||
|
#show figure.caption: set text(size: 8.5pt, style: "italic", fill: gris-doux)
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
---
|
||||||
|
title: "Module 3 — Signaux analogiques : PWM & ADC"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objectifs du module
|
||||||
|
|
||||||
|
- Comprendre le principe du PWM (modulation de largeur d'impulsion) et son usage sur ESP32-S3 via l'API LEDC.
|
||||||
|
- Réaliser un variateur de luminosité et un contrôle de servomoteur.
|
||||||
|
- Comprendre le fonctionnement du convertisseur analogique-numérique (ADC) et ses limites.
|
||||||
|
- Lire un potentiomètre et convertir la valeur brute en unité physique.
|
||||||
|
|
||||||
|
## 1. Qu'est-ce que le PWM ?
|
||||||
|
|
||||||
|
Le PWM (Pulse Width Modulation) simule une sortie analogique en faisant varier rapidement le rapport cyclique (duty cycle) d'un signal carré : plus la portion « HIGH » est longue par rapport à la période, plus la valeur moyenne perçue (tension, luminosité, vitesse) est élevée. C'est la technique utilisée pour faire varier la luminosité d'une LED ou piloter un servomoteur.
|
||||||
|
|
||||||
|
{#fig-m03-pwm-rapport-cyclique}
|
||||||
|
|
||||||
|
## 2. Le PWM sur ESP32-S3 : l'API LEDC
|
||||||
|
|
||||||
|
Contrairement à un Arduino Uno où `analogWrite()` suffit, l'ESP32 utilise un contrôleur matériel dédié appelé LEDC (LED Control), plus flexible (fréquence et résolution configurables) mais nécessitant une configuration explicite. Depuis les versions récentes du core Arduino-ESP32, une API simplifiée `analogWrite()` est également disponible et gère LEDC en interne — nous verrons les deux approches.
|
||||||
|
|
||||||
|
### 2.1 Approche simplifiée : `analogWrite()`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define LED_PIN 4
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Rien de particulier a configurer avec l'API simplifiee
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
for (int duty = 0; duty <= 255; duty++) {
|
||||||
|
analogWrite(LED_PIN, duty); // 0 = eteint, 255 = pleine puissance
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
for (int duty = 255; duty >= 0; duty--) {
|
||||||
|
analogWrite(LED_PIN, duty);
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 Approche explicite : API LEDC (contrôle fin)
|
||||||
|
|
||||||
|
Utile lorsqu'on a besoin d'une fréquence ou d'une résolution précise (par exemple pour piloter un servomoteur, qui attend une fréquence de 50 Hz).
|
||||||
|
|
||||||
|
{#fig-m03-servo-50hz}
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define LED_PIN 4
|
||||||
|
#define PWM_FREQ 5000 // 5 kHz
|
||||||
|
#define PWM_RES 8 // resolution 8 bits (0-255)
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
ledcAttach(LED_PIN, PWM_FREQ, PWM_RES);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
for (int duty = 0; duty <= 255; duty++) {
|
||||||
|
ledcWrite(LED_PIN, duty);
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
::: {.callout-note title="Version du core Arduino-ESP32"}
|
||||||
|
L'API LEDC a changé entre les versions 2.x et 3.x du core Arduino-ESP32 (l'ancienne API utilisait des numéros de canal explicites via ledcSetup/ledcAttachPin). Vérifiez la version installée dans le gestionnaire de cartes si le code ci-dessus ne compile pas, et adaptez-vous à la documentation correspondante.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 3. Exercice : variateur de luminosité avec potentiomètre
|
||||||
|
|
||||||
|
Nous allons combiner PWM et lecture analogique : la position d'un potentiomètre définit la luminosité d'une LED.
|
||||||
|
|
||||||
|
{#fig-m03-montage-variateur}
|
||||||
|
|
||||||
|
## 4. Le convertisseur analogique-numérique (ADC)
|
||||||
|
|
||||||
|
L'ADC convertit une tension continue (0 à 3,3 V) en une valeur numérique. L'ESP32-S3 dispose d'un ADC 12 bits, soit une résolution de 4096 valeurs possibles (0 à 4095).
|
||||||
|
|
||||||
|
{#fig-m03-adc-quantification}
|
||||||
|
|
||||||
|
| Caractéristique | Valeur |
|
||||||
|
|---|---|
|
||||||
|
| Résolution native | 12 bits (0 à 4095) |
|
||||||
|
| Plage de tension | 0 à 3,3 V (selon atténuation configurée) |
|
||||||
|
| Unité ADC utilisable en Wi-Fi actif | ADC1 uniquement (ADC2 partagé avec le Wi-Fi) |
|
||||||
|
| Fonction de lecture | `analogRead(pin)` |
|
||||||
|
|
||||||
|
::: {.callout-warning title="Limitation importante : ADC2 et Wi-Fi"}
|
||||||
|
L'ADC2 de l'ESP32 partage des ressources internes avec le module Wi-Fi. Si le Wi-Fi est actif (voir Module 7), les lectures sur les broches ADC2 deviennent peu fiables voire impossibles. Pour tout projet connecté utilisant l'analogique, privilégiez les broches de l'ADC1 (généralement GPIO1 à GPIO10 sur l'ESP32-S3).
|
||||||
|
:::
|
||||||
|
|
||||||
|
### 4.1 Lire un potentiomètre
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define POT_PIN 1 // Broche ADC1
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int valeurBrute = analogRead(POT_PIN); // 0 a 4095
|
||||||
|
float tension = valeurBrute * (3.3 / 4095.0); // conversion en volts
|
||||||
|
Serial.printf("Brut: %d Tension: %.2f V\n", valeurBrute, tension);
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Exercice combiné : variateur de LED par potentiomètre
|
||||||
|
|
||||||
|
Utilisez la valeur lue sur le potentiomètre (0-4095) pour piloter la luminosité d'une LED en PWM (0-255) en convertissant l'échelle avec la fonction `map()`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define POT_PIN 1
|
||||||
|
#define LED_PIN 4
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
ledcAttach(LED_PIN, 5000, 8);
|
||||||
|
Serial.begin(115200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int brut = analogRead(POT_PIN);
|
||||||
|
int duty = map(brut, 0, 4095, 0, 255);
|
||||||
|
ledcWrite(LED_PIN, duty);
|
||||||
|
Serial.printf("Potentiometre: %d -> PWM: %d\n", brut, duty);
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Aller plus loin : appliquer le PWM à la LED NeoPixel
|
||||||
|
|
||||||
|
Pour rappel (Module 2), la LED NeoPixel ne se pilote pas avec analogWrite ou ledcWrite : elle utilise un protocole numérique dédié (WS2812) géré par la bibliothèque Adafruit_NeoPixel, dont la fonction `setBrightness()` joue un rôle équivalent à celui du PWM pour l'intensité globale. Reliez les deux notions : adaptez l'exercice du variateur pour que ce soit cette fois la luminosité de la LED NeoPixel qui varie selon le potentiomètre.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
#define POT_PIN 1
|
||||||
|
#define NEOPIXEL_PIN 48
|
||||||
|
|
||||||
|
Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
pixel.begin();
|
||||||
|
pixel.setPixelColor(0, pixel.Color(255, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int brut = analogRead(POT_PIN);
|
||||||
|
int luminosite = map(brut, 0, 4095, 0, 255);
|
||||||
|
pixel.setBrightness(luminosite);
|
||||||
|
pixel.show();
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checklist de fin de module
|
||||||
|
|
||||||
|
- [ ] Je sais expliquer le principe du duty cycle en PWM.
|
||||||
|
- [ ] Je sais configurer une sortie PWM avec analogWrite ou l'API LEDC.
|
||||||
|
- [ ] Je connais la résolution et les limites de l'ADC de l'ESP32-S3 (notamment ADC2 + Wi-Fi).
|
||||||
|
- [ ] J'ai réalisé le variateur de luminosité piloté par potentiomètre, sur LED classique et sur NeoPixel.
|
||||||
Reference in New Issue
Block a user