Add GPIO26 speaker beep and melody test.
Play audio on boot and every 12s via the onboard amp; show status on the LVGL UI and document pins. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
12
CHANGELOG.md
Normal file
12
CHANGELOG.md
Normal file
@@ -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.
|
||||
38
README.md
38
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)。
|
||||
|
||||
10
include/audio_test.h
Normal file
10
include/audio_test.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void audio_init();
|
||||
// 短测:三声蜂鸣(开机 / 周期测试)
|
||||
void audio_play_beep_sequence();
|
||||
// 简短旋律(约 1.5s)
|
||||
void audio_play_melody();
|
||||
const char *audio_last_status();
|
||||
@@ -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
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
|
||||
void ui_create();
|
||||
void ui_update(const SdCardInfo &info);
|
||||
void ui_set_audio_status(const char *text);
|
||||
|
||||
49
src/audio_test.cpp
Normal file
49
src/audio_test.cpp
Normal file
@@ -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;
|
||||
}
|
||||
23
src/main.cpp
23
src/main.cpp
@@ -2,6 +2,7 @@
|
||||
#include <TFT_eSPI.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
14
src/ui.cpp
14
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user