diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..22ad6cb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +## 2026-10-17 — Speaker audio test + +- Add GPIO26 speaker path (onboard SC8002B amp / P4 connector). +- Boot: 3 beeps + short melody; then beep every 12s. +- LVGL row `Speaker` shows last audio status. +- Docs: README speaker section. + +## 2026-10-17 — Initial + +- CYD TF/microSD mount (VSPI) + LVGL storage info UI. diff --git a/README.md b/README.md index f3ad875..e713981 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# CYD TF 卡信息显示(LVGL) +# CYD TF 卡信息显示 + 喇叭测试(LVGL) -在 **ESP32-2432S028(CYD)** 上挂载 TF/microSD,用 LVGL 显示卡类型、文件系统、容量、已用/可用空间等。 +在 **ESP32-2432S028(CYD)** 上挂载 TF/microSD,用 LVGL 显示卡信息;并通过板载功放测试外接喇叭。 ## 硬件 @@ -9,27 +9,34 @@ | TFT MOSI / MISO / SCLK | 13 / 12 / 14 | | TFT CS / DC / BL | 15 / 2 / 21 | | **SD MOSI / MISO / SCK / CS** | **23 / 19 / 18 / 5** | +| **Speaker(SC8002B → P4)** | **26** | -TF 卡使用独立 VSPI;显示使用 TFT_eSPI(HSPI)。本工程未启用触摸,避免与 SD 争用总线。 +TF 卡使用独立 VSPI;显示使用 TFT_eSPI(HSPI)。喇叭接 CYD 的 **SPEAK / P4** 两针座(极性对调只会相位反,一般可出声)。 + +本工程未启用触摸,避免与 SD 争用总线。 ## 屏幕显示内容 - Status:是否挂载成功 - Type:MMC / SDSC / SDHC - Format:FAT16 / FAT32 等(按分区容量推断) -- Capacity:卡物理容量 -- Partition / Used / Free:分区总容量、已用、剩余 +- Capacity / Partition / Used / Free:容量与空间 - Root files:根目录条目数 +- **Speaker**:最近一次音频测试状态(GPIO26) - 进度条:已用百分比 -每 3 秒自动刷新;串口 115200 同步打印同样信息。 +每 3 秒刷新 SD;串口 115200 同步打印。 + +## 喇叭测试 + +- **开机**:三声蜂鸣 + 一小段旋律 +- **之后**:约每 12 秒再播一段三声蜂鸣 +- 实现:`tone()` / `noTone()` 打在 GPIO26(经板载放大器) + +听不到声时检查:P4 是否插紧、喇叭阻值(常见 8Ω)、音量是否过小。 ## 编译烧录 -1. VS Code / Cursor 安装 **PlatformIO** 扩展 -2. 打开本目录,连接 CYD(通常 USB 转串口 CH340) -3. 执行: - ```bash pio run -t upload pio device monitor @@ -37,7 +44,10 @@ pio device monitor ## 注意事项 -- TF 卡需为 **FAT/FAT32**(Arduino `SD` 库);exFAT 通常无法挂载。 -- 首次使用建议先在电脑上格式化为 FAT32。 -- 若花屏,可在 `platformio.ini` 把 `ILI9341_2_DRIVER` 换成 `ILI9341_DRIVER` 再试。 -- 若只要竖屏,在 `main.cpp` 去掉或改 `lv_display_set_rotation`。 +- TF 卡需为 **FAT/FAT32**;exFAT 通常无法挂载。 +- 若花屏,在 `platformio.ini` 把 `ILI9341_2_DRIVER` 换成 `ILI9341_DRIVER`。 +- 变更请同步更新 `CHANGELOG.md` 并提交本地 git。 + +## 文档与版本 + +见 [CHANGELOG.md](CHANGELOG.md)。 diff --git a/include/audio_test.h b/include/audio_test.h new file mode 100644 index 0000000..da8f52a --- /dev/null +++ b/include/audio_test.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +void audio_init(); +// 短测:三声蜂鸣(开机 / 周期测试) +void audio_play_beep_sequence(); +// 简短旋律(约 1.5s) +void audio_play_melody(); +const char *audio_last_status(); diff --git a/include/pins.h b/include/pins.h index 6f072b0..8e703b1 100644 --- a/include/pins.h +++ b/include/pins.h @@ -11,5 +11,8 @@ #define SD_SCK 18 #define SD_CS 5 +// 板载 SC8002B 功放 → P4 喇叭座(DAC2) +#define SPEAKER_PIN 26 + #define SCREEN_WIDTH 240 #define SCREEN_HEIGHT 320 diff --git a/include/ui.h b/include/ui.h index c214a53..47b07c0 100644 --- a/include/ui.h +++ b/include/ui.h @@ -4,3 +4,4 @@ void ui_create(); void ui_update(const SdCardInfo &info); +void ui_set_audio_status(const char *text); diff --git a/src/audio_test.cpp b/src/audio_test.cpp new file mode 100644 index 0000000..d2f9a7d --- /dev/null +++ b/src/audio_test.cpp @@ -0,0 +1,49 @@ +#include "audio_test.h" +#include "pins.h" + +static const char *g_status = "Idle"; + +void audio_init() { + pinMode(SPEAKER_PIN, OUTPUT); + digitalWrite(SPEAKER_PIN, LOW); + noTone(SPEAKER_PIN); + g_status = "Ready GPIO26"; + Serial.printf("Speaker init on GPIO%d (SC8002B amp)\n", SPEAKER_PIN); +} + +static void beep(uint16_t freq_hz, uint16_t ms) { + tone(SPEAKER_PIN, freq_hz); + delay(ms); + noTone(SPEAKER_PIN); + digitalWrite(SPEAKER_PIN, LOW); +} + +void audio_play_beep_sequence() { + g_status = "Beep x3"; + Serial.println("Audio: beep sequence"); + beep(880, 120); + delay(80); + beep(1175, 120); + delay(80); + beep(1397, 180); + delay(50); + g_status = "Beep done"; +} + +void audio_play_melody() { + // 简化版:C D E G A + static const uint16_t notes[] = {523, 587, 659, 784, 880, 784, 659}; + static const uint16_t durs[] = {160, 160, 160, 200, 240, 160, 280}; + + g_status = "Melody"; + Serial.println("Audio: melody test"); + for (size_t i = 0; i < sizeof(notes) / sizeof(notes[0]); ++i) { + beep(notes[i], durs[i]); + delay(40); + } + g_status = "Melody done"; +} + +const char *audio_last_status() { + return g_status; +} diff --git a/src/main.cpp b/src/main.cpp index dc2fd65..3b6e7aa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include #include +#include "audio_test.h" #include "pins.h" #include "sd_info.h" #include "ui.h" @@ -11,7 +12,9 @@ static constexpr uint32_t DRAW_BUF_SIZE = static uint32_t draw_buf[DRAW_BUF_SIZE / 4]; static uint32_t last_refresh_ms = 0; +static uint32_t last_audio_ms = 0; static constexpr uint32_t REFRESH_MS = 3000; +static constexpr uint32_t AUDIO_INTERVAL_MS = 12000; static void refresh_sd_ui() { SdCardInfo info = sd_read_info(); @@ -31,26 +34,29 @@ static void refresh_sd_ui() { } ui_update(info); + ui_set_audio_status(audio_last_status()); } void setup() { Serial.begin(115200); delay(200); Serial.println(); - Serial.printf("LVGL %d.%d.%d | CYD TF info\n", lv_version_major(), + Serial.printf("LVGL %d.%d.%d | CYD TF + Speaker\n", lv_version_major(), lv_version_minor(), lv_version_patch()); pinMode(TFT_BL_PIN, OUTPUT); digitalWrite(TFT_BL_PIN, HIGH); + audio_init(); + lv_init(); lv_display_t *disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf)); - // 横屏:320x240 lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270); ui_create(); + ui_set_audio_status(audio_last_status()); if (!sd_init()) { Serial.println("SD mount failed at boot"); @@ -58,6 +64,13 @@ void setup() { refresh_sd_ui(); last_refresh_ms = millis(); + + // 开机立刻测喇叭 + audio_play_beep_sequence(); + delay(200); + audio_play_melody(); + ui_set_audio_status(audio_last_status()); + last_audio_ms = millis(); } void loop() { @@ -70,5 +83,11 @@ void loop() { refresh_sd_ui(); } + if (now - last_audio_ms >= AUDIO_INTERVAL_MS) { + last_audio_ms = now; + audio_play_beep_sequence(); + ui_set_audio_status(audio_last_status()); + } + delay(5); } diff --git a/src/ui.cpp b/src/ui.cpp index 0241ca7..523b2bf 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -12,6 +12,7 @@ static lv_obj_t *lbl_free; static lv_obj_t *lbl_files; static lv_obj_t *bar_usage; static lv_obj_t *lbl_hint; +static lv_obj_t *lbl_audio; static lv_obj_t *make_row(lv_obj_t *parent, const char *title, lv_obj_t **value_out) { lv_obj_t *row = lv_obj_create(parent); @@ -82,6 +83,8 @@ void ui_create() { make_row(col, "Used", &lbl_used); make_row(col, "Free", &lbl_free); make_row(col, "Root files", &lbl_files); + make_row(col, "Speaker", &lbl_audio); + lv_label_set_text(lbl_audio, "GPIO26"); bar_usage = lv_bar_create(col); lv_obj_set_width(bar_usage, LV_PCT(100)); @@ -144,7 +147,14 @@ void ui_update(const SdCardInfo &info) { } lv_bar_set_value(bar_usage, pct, LV_ANIM_ON); - char hint[40]; - snprintf(hint, sizeof(hint), "Used %d%% | auto refresh", pct); + char hint[48]; + snprintf(hint, sizeof(hint), "Used %d%% | SD+Audio", pct); lv_label_set_text(lbl_hint, hint); } + +void ui_set_audio_status(const char *text) { + if (lbl_audio == nullptr || text == nullptr) { + return; + } + lv_label_set_text(lbl_audio, text); +}