Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
embassy-piezo
Driver asynchrone no_std pour capteur de vibration piézoélectrique (sortie numérique DO), pour cibles ESP32 via esp-hal.
Même philosophie que embassy-gy-bmi160 et embassy-bmp280 :
async natif, zéro allocation, zéro unsafe, détection sans polling.
⚡ Caractéristiques
#![forbid(unsafe_code)]: sécurité garantie à la compilation- Détection front montant sans polling : zéro CPU en attente
- Debounce configurable pour filtrer les rebonds électriques
- Comptage d'événements avec
saturating_add(pas de panic après overflow) - Timeout configurable sur attente vibration et silence
- Snapshot d'état typé
VibrationEvent { count, active } - Signal global
VIBRATION_SIGNALinter-tâches (interrupt-safe) - Zéro allocation, bare-metal pur
📦 Installation
[]
= { = "0.1.0", = ["esp32c3"] } # adapter la feature à ta puce
= { = "1.1", = ["unstable"] }
= { = "0.3", = ["embassy"] } # fournit l'executor + le time-driver embassy (esp-hal >= 1.x)
= "0.10"
= "0.5"
= "0.8"
Une seule feature de puce doit être active à la fois :
esp32,esp32c2,esp32c3,esp32c6,esp32h2,esp32s2ouesp32s3. Par défaut, le crate cible l'ESP32 d'origine.
⚠
esp-hal-embassyest obsolète depuisesp-hal 1.x: il a été remplacé paresp-rtos(featureembassy). Si tu pars d'un projet récent, n'installe pasesp-hal-embassy— utiliseesp-rtoscomme indiqué ci-dessous, sinon Cargo échouera à résoudre les versions (esp-hal-embassyreste figé suresp-hal ^1.0.0-rc.0).
🔴 Câblage (ESP32 DevKit)
| Broche module | Connexion | Note |
|---|---|---|
| VCC | 3.3V | |
| GND | Masse | |
| DO | GPIOx | Sortie numérique : haut = vibration |
| AO | — | Sortie analogique (non utilisée ici) |
Sensibilité : réglable via le potentiomètre bleu sur le module. Si le pin reste haut en permanence, tourner le potentiomètre dans le sens horaire.
⚠ Évite les broches de strapping au boot (ex. GPIO2, GPIO8, GPIO9 sur ESP32-C3 — vérifie le datasheet de ta puce). Choisis une broche libre standard (ex. GPIO4, GPIO5, GPIO7, GPIO18…).
🚀 Utilisation
Initialisation du runtime Embassy (esp-hal 1.x / esp-rtos)
use TimerGroup;
use SoftwareInterruptControl;
let peripherals = init;
let timg0 = new;
let software_interrupt = new;
// Remplace l'ancien esp_hal_embassy::init(...) — requis avant tout
// Timer::after / with_timeout / spawn de tâche async.
start;
Le point d'entrée main doit être marqué #[esp_rtos::main] (et non
#[embassy_executor::main]) :
async !
Initialisation du driver
use ;
use PiezoVibration;
// Sans debounce : tout front montant est compté immédiatement
let pin = new;
let mut piezo = new;
// Avec debounce : chocs humains (frappe, impact mécanique)
// 12ms : valeur validée empiriquement sur module piézo DO générique
// (1 tap physique = 1 comptage exact, sans rebond ni perte)
let pin = new;
let mut piezo = new_with_debounce;
Debounce — guide pratique
Après chaque front montant, le driver attend debounce_ms millisecondes puis
vérifie que le pin est toujours haut. Si le signal est retombé entre-temps
(rebond électrique), l'événement est ignoré et l'attente recommence sans
incrémenter le compteur.
debounce_ms |
Cas d'usage |
|---|---|
0 |
Désactivé — tout front montant est compté |
5–10 |
Filtrage électrique léger (risque de double-comptage) |
12 |
Valeur de référence validée sur module piézo DO générique — 1 tap = 1 comptage exact |
15–30 |
Plage acceptable selon le module, à recalibrer si besoin |
100 |
Chocs lents / mécaniques amortis |
⚠ Chaque module piézo a une durée d'impulsion différente — 12ms est la valeur validée pour le module de référence utilisé pendant le développement de ce crate, mais reste un point de départ à recalibrer pour ton propre module si besoin.
Méthode de calibration recommandée (par dichotomie) :
- Commence à
5ms. Si chaque tap compte +2 ou plus → le debounce est trop court.- Monte à
30ms. Si plus aucune vibration n'est détectée → trop long.- Resserre l'intervalle jusqu'à obtenir exactement +1 par tap physique.
- 12ms a donné un résultat exact (1 tap = +1) sur le matériel de test — commence par cette valeur avant de recalibrer si nécessaire.
Attente d'une vibration (bloquant async)
// Suspend la tâche jusqu'au prochain front montant validé : zéro CPU pendant l'attente
let event = piezo.wait_for_vibration.await;
// event.count : u32 : nombre total de vibrations depuis le démarrage
// event.active : bool : pin encore haut à cet instant
⚠️ Éviter le double-comptage en boucle continue
Si tu enchaînes directement wait_for_vibration() dans une boucle sans
réarmement, et que le pin reste électriquement haut un peu plus longtemps que
prévu (résonance mécanique du capteur, bruit), le driver peut redéclencher
plusieurs fois pour un seul choc physique. Attends que le signal redescende
avant de réécouter :
use VIBRATION_SIGNAL;
use Duration;
async
Avec timeout
use Duration;
use PiezoError;
match piezo.wait_for_vibration_timeout.await
Le timeout englobe l'intégralité de la détection, délai de debounce inclus. Exemple : avec
timeout = 200 msetdebounce_ms = 100, un choc survenu à 150 ms laisse 50 ms pour la confirmation : si ce délai expire,Timeoutest retourné.
Attente de fin de vibration
// Attend que le pin repasse bas (fin de l'impulsion)
piezo.wait_for_silence.await;
// Avec timeout (recommandé en pratique, voir section anti-double-comptage ci-dessus)
match piezo.wait_for_silence_timeout.await
Lecture instantanée
if piezo.is_vibrating
let state = piezo.state;
// state.count : u32
// state.active : bool
let n = piezo.count;
piezo.reset_count;
💡 Astuce debug matériel : si tu n'es pas sûr que le câblage/capteur fonctionne avant même de tester la détection de front, ajoute une tâche de polling temporaire qui logue
is_vibrating()toutes les 500ms — ça confirme que le signal physique change bien quand tu tapes, indépendamment de toute la logique de debounce/edge-detection.
Comptage sur fenêtre temporelle
use Duration;
// Combien de chocs détectés en 2 secondes ?
// À utiliser avec une tâche de comptage parallèle (voir exemple complet)
let hits = piezo.count_during.await;
📡 Signaux globaux
VIBRATION_SIGNAL publie le compteur u32 à chaque vibration.
Sûr depuis les interruptions (CriticalSectionRawMutex).
use VIBRATION_SIGNAL;
// Tâche productrice
let event = piezo.wait_for_vibration.await;
VIBRATION_SIGNAL.signal;
// Tâche consommatrice (logger, LED, radio, OLED…)
async
Le signal publie un
u32(compteur) et non unbool: la tâche consommatrice peut détecter des événements manqués entre deuxwait().
🏗️ Architecture du projet
embassy-piezo/
├── Cargo.toml
└── src/
├── lib.rs ← Driver principal, VibrationEvent, PiezoVibration
├── error.rs ← PiezoError (Timeout, PinUnavailable)
└── signals.rs ← VIBRATION_SIGNAL (CriticalSectionRawMutex)
📋 API publique : référence rapide
PiezoVibration
| Méthode | Async | Description |
|---|---|---|
PiezoVibration::new(pin) |
— | Crée le driver sans debounce |
PiezoVibration::new_with_debounce(pin, ms) |
— | Crée le driver avec debounce |
wait_for_vibration() |
✅ | Attend le prochain front montant validé, incrémente le compteur |
wait_for_vibration_timeout(d) |
✅ | Idem avec timeout → Result<VibrationEvent, PiezoError> |
wait_for_silence() |
✅ | Attend le front descendant |
wait_for_silence_timeout(d) |
✅ | Idem avec timeout → Result<(), PiezoError> |
count_during(window) |
✅ | Compte les vibrations sur une fenêtre temporelle |
is_vibrating() |
— | Lecture instantanée du pin |
count() |
— | Compteur cumulé depuis le démarrage |
reset_count() |
— | Remet le compteur à zéro |
state() |
— | Snapshot VibrationEvent { count, active } |
VibrationEvent
| Champ | Type | Description |
|---|---|---|
count |
u32 |
Vibrations cumulées (jamais de panic : saturating_add) |
active |
bool |
Pin haut à l'instant de la lecture |
PiezoError
| Variant | Cause |
|---|---|
Timeout |
Délai expiré sans événement |
PinUnavailable |
Pin mal configuré |
🐞 Dépannage rapide
| Symptôme | Cause probable | Solution |
|---|---|---|
| Tu pars de zéro et ne sais pas par où commencer | — | Essaie 12ms en premier (valeur de référence validée), puis ajuste si besoin |
| Rien ne se passe jamais, même en tapant fort | Câblage DO/GPIO incorrect, ou alim manquante | Vérifie VCC/GND/DO, teste avec is_vibrating() en polling |
is_vibrating() reste toujours false en tapant |
Sensibilité du potentiomètre trop basse | Tourne le potentiomètre bleu dans le sens horaire |
| Chaque tap compte +2 ou plus | Debounce trop court pour ce module | Augmente debounce_ms (essaie 15-30ms) |
| Plus aucune détection après avoir augmenté le debounce | Debounce trop long, impulsion filtrée | Redescends progressivement (dichotomie) |
| Compteur explose en continu sans qu'on touche au capteur | Boucle sans réarmement + pin resté haut | Ajoute wait_for_silence_timeout() après chaque détection |
📜 Licence
GPL-2.0-or-later — voir LICENSE.
Copyright (C) 2026 Jorge Andre Castro