/* * RECEIVER — XIAO ESP32-C3 + passive buzzer * Receives a frequency over ESP-NOW and plays it on the buzzer. If packets * stop arriving it silences the buzzer (watchdog) so it never gets stuck. * * Wiring (XIAO ESP32-C3): * Buzzer + -> D10 (GPIO10) * Buzzer - -> GND * * IMPORTANT: pitch control needs a PASSIVE (piezo) buzzer or small speaker. * An ACTIVE buzzer has its own oscillator and only does on/off at a fixed * pitch — tone() cannot change its frequency. * * Built for ESP32 Arduino core 3.x (current). */ #include #include #include static const int PIN_BUZZER = 10; // D10 static const uint8_t WIFI_CHANNEL = 1; // must match the sender static const uint32_t TIMEOUT_MS = 500; // silence if no packet within this typedef struct __attribute__((packed)) { uint16_t freq; // Hz (0 = silent) } message_t; volatile uint16_t targetFreq = 0; volatile uint32_t lastRxMs = 0; /* ---- ESP-NOW receive callback (core 3.x signature) ---- * If you are on the OLDER core 2.x, replace the line below with: * void onRecv(const uint8_t *mac, const uint8_t *data, int len) { */ void onRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len) { if (len < (int)sizeof(message_t)) return; message_t m; memcpy(&m, data, sizeof(m)); targetFreq = m.freq; lastRxMs = millis(); } void setup() { Serial.begin(115200); delay(300); pinMode(PIN_BUZZER, OUTPUT); noTone(PIN_BUZZER); WiFi.mode(WIFI_STA); WiFi.disconnect(); esp_wifi_set_channel(WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE); if (esp_now_init() != ESP_OK) { Serial.println("ESP-NOW init failed; restarting"); ESP.restart(); } esp_now_register_recv_cb(onRecv); Serial.println("Receiver ready"); } uint16_t curFreq = 0; void loop() { uint16_t f = targetFreq; uint32_t last = lastRxMs; // watchdog: go quiet if the sender has gone silent if (millis() - last > TIMEOUT_MS) f = 0; if (f != curFreq) { curFreq = f; if (f == 0) noTone(PIN_BUZZER); else tone(PIN_BUZZER, f); } delay(5); }