SD 卡
库: Arduino SD(随 ESP32 Arduino 核心内置)
访问: SD 全局对象,通过 SPI 总线
M5Cardputer 内置 microSD 卡槽,通过 SPI 访问。可用于存储 WAV 录音、日志文件、配置文件、图片或任何需要持久化存储的数据。
引脚分配
| 信号 | GPIO |
|---|---|
| SCK | 40 |
| MISO | 39 |
| MOSI | 14 |
| CS | 12 |
这些由 M5Unified 预配置,你只需将 CS 引脚传给 SD.begin()。
挂载 / 初始化
#include <SD.h>
void setup() {
M5Cardputer.begin();
SPI.begin(40, 39, 14, 12); // SCK, MISO, MOSI, CS
if (!SD.begin(12, SPI, 25000000)) { // CS, SPI总线, 频率 (25 MHz)
M5Cardputer.Display.println("SD 初始化失败!");
return;
}
uint8_t cardType = SD.cardType();
uint64_t cardSize = SD.cardSize() / (1024 * 1024); // MB
if (cardType == CARD_NONE) {
M5Cardputer.Display.println("未检测到 SD 卡");
} else {
M5Cardputer.Display.printf("SD 卡: %llu MB\n", cardSize);
}
}
卡类型常量
| 常量 | 含义 |
|---|---|
CARD_NONE |
无卡 / 未知 |
CARD_MMC |
MMC 卡 |
CARD_SD |
SD 卡 |
CARD_SDHC |
SDHC 卡(最常见) |
文件操作
所有文件操作使用 fs::FS 抽象层,通过 File 类进行。
打开文件
File file = SD.open("/data.txt"); // 读取模式(默认)
File file = SD.open("/data.txt", FILE_WRITE); // 写入模式(创建/截断)
File file = SD.open("/data.txt", FILE_APPEND); // 追加模式
读取
// 逐字节读取
while (file.available()) {
char c = file.read();
// ...
}
// 读取到缓冲区
uint8_t buf[256];
size_t bytesRead = file.read(buf, sizeof(buf));
// 跳到指定位置
file.seek(44); // 跳过 WAV 文件头(44 字节)
写入
// 写入文本
file.print("你好,SD 卡!");
file.println(" 第二行");
// 写入二进制
uint8_t data[] = {0x00, 0xFF, 0x55};
file.write(data, sizeof(data));
关闭
文件 / 目录管理
// 检查是否存在
if (SD.exists("/config.json")) { ... }
// 删除
SD.remove("/old_file.txt");
// 重命名
SD.rename("/old.txt", "/new.txt");
// 创建目录
SD.mkdir("/logs");
// 删除目录(必须为空)
SD.rmdir("/empty_dir");
列出目录内容
File dir = SD.open("/");
while (File entry = dir.openNextFile()) {
M5Cardputer.Display.printf("%s %u 字节 %s\n",
entry.name(),
entry.size(),
entry.isDirectory() ? "[目录]" : "");
entry.close();
}
dir.close();
空间信息
uint64_t total = SD.totalBytes();
uint64_t used = SD.usedBytes();
uint64_t free = total - used;
M5Cardputer.Display.printf("总容量: %llu MB\n", total / 1024 / 1024);
M5Cardputer.Display.printf("剩余: %llu MB\n", free / 1024 / 1024);
WAV 录音到 SD 卡
最小 WAV 写入示例
struct WAVHeader {
char riff[4] = {'R','I','F','F'};
uint32_t fileSize = 0;
char wave[4] = {'W','A','V','E'};
char fmt[4] = {'f','m','t',' '};
uint32_t fmtSize = 16;
uint16_t audioFormat = 1; // PCM
uint16_t numChannels = 1; // 单声道
uint32_t sampleRate = 16000;
uint32_t byteRate = 16000 * 2;
uint16_t blockAlign = 2;
uint16_t bitsPerSample = 16;
char data[4] = {'d','a','t','a'};
uint32_t dataSize = 0;
};
void saveWAV(const char* path, int16_t* samples, size_t count) {
File file = SD.open(path, FILE_WRITE);
WAVHeader header;
header.fileSize = 36 + count * sizeof(int16_t);
header.dataSize = count * sizeof(int16_t);
file.write((uint8_t*)&header, sizeof(WAVHeader));
file.write((uint8_t*)samples, count * sizeof(int16_t));
file.close();
}
快速示例:按键日志记录到 SD 卡
#include <SD.h>
#include <SPI.h>
void setup() {
M5Cardputer.begin();
SPI.begin(40, 39, 14, 12);
SD.begin(12, SPI, 25000000);
// 创建日志表头(仅一次)
if (!SD.exists("/log.csv")) {
File f = SD.open("/log.csv", FILE_WRITE);
f.println("时间戳,按键");
f.close();
}
}
void loop() {
M5Cardputer.update();
if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) {
M5Cardputer.Keyboard.updateKeysState();
for (char c : M5Cardputer.Keyboard.keysState().word) {
File f = SD.open("/log.csv", FILE_APPEND);
f.printf("%lu,%c\n", millis(), c);
f.close();
}
}
}