docs 08 SD 卡读取例程
SD 卡读写
General Driver for Robots 板载有 SD 卡模块,可对 SD 卡进行读写操作,以下提供 SD 卡读写程序。
上传程序
-
将 Micro SD 卡格式化为 FAT32。
-
点击 [例程下载]General Driver for Robots SD 卡读写例程,解压并打开
SDCard.ino。 -
进入
C:\Users\用户名、AppData\Local\Arduino15\libraries,删除其中的SD文件夹。
-
删除后切回到 Arduino IDE,用 USB 线将多功能驱动板和计算机连接起来(此处插入的是多功能驱动板 USB 的 Type-C 接口),点击“工具”→“端口”,再点击新出现的 COM(这里新出现的 COM 为 COM26)。

-
在 Arduino IDE 中,点击“工具”→“开发板”→“ESP32”→“ESP32 Dev Module”。开发板以及端口都选择好后上传程序。上传程序后将 SD 卡插入到驱动板上的 SD 卡槽,需要先上传程序再插入 SD 卡,不然会出现上传程序失败的结果。打开串口监视器,若出现 SD 卡读取失败的情况则断开 USB 线重新连接。

程序解析
#include "FS.h"
#include "SD.h"
#include "SPI.h"
// <<<<<<<<<<<<<<<<<<<<< SD 卡读取例程解析 >>>>>>>>>>>>>>>>>>>>
// 该程序使用 ESP32 的 HSPI 总线连接 MicroSD 卡模块,并完成文件删除、写入、追加、
// 读取以及读写速度测试,最后输出 SD 卡总容量和已用容量。
// 定义 SD 卡 SPI 通信引脚
#define SCK 14
#define MISO 12
#define MOSI 13
#define CS 15
// 读取指定路径文件的内容,并通过串口打印出来
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
// 以默认只读方式打开文件
File file = fs.open(path);
if(!file){
// 文件打开失败时提示并退出函数
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
// 当文件还有可读取数据时,逐字节读取并输出到串口
while(file.available()){
Serial.print((char)file.read());
}
// 关闭文件,释放资源
file.close();
}
// 向指定路径写入内容;如果文件不存在会创建文件,如果存在会覆盖原文件内容
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
// 使用 FILE_WRITE 模式打开文件
File file = fs.open(path, FILE_WRITE);
if(!file){
// 文件打开失败时提示并退出函数
Serial.println("Failed to open file for writing");
return;
}
// 将 message 字符串写入文件,并根据返回结果提示写入状态
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
// 关闭文件,确保数据写入完成
file.close();
}
// 在指定文件末尾追加内容,不会清空文件原有数据
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
// 使用 FILE_APPEND 模式打开文件
File file = fs.open(path, FILE_APPEND);
if(!file){
// 文件打开失败时提示并退出函数
Serial.println("Failed to open file for appending");
return;
}
// 将 message 字符串追加到文件末尾
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
// 关闭文件,保存追加结果
file.close();
}
// 删除指定路径的文件
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
// remove() 删除成功返回 true,失败返回 false
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
// 测试指定文件的读写速度
void testFileIO(fs::FS &fs, const char * path){
// 打开测试文件
File file = fs.open(path);
// 定义 512 字节缓冲区,用于分块读写数据
static uint8_t buf[512];
size_t len = 0;
// 记录读写开始和结束时间
uint32_t start = millis();
uint32_t end = start;
if(file){
// 获取文件大小
len = file.size();
size_t flen = len;
start = millis();
// 每次最多读取 512 字节,直到整个文件读取完成
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
// 计算读取耗时,并通过串口输出读取速度测试结果
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
// 以写入模式重新打开测试文件
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
// 连续写入 2048 个 512 字节数据块,即写入 1MB 数据
for(i=0; i<2048; i++){
file.write(buf, 512);
}
// 计算写入耗时,并通过串口输出写入速度测试结果
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
void setup(){
// 初始化串口,波特率为 115200
Serial.begin(115200);
// 创建 HSPI 对象,用于 SD 卡 SPI 通信
SPIClass spi = SPIClass(HSPI);
// 按照自定义引脚初始化 SPI 总线:SCK、MISO、MOSI、CS
spi.begin(SCK, MISO, MOSI, CS);
// 初始化 SD 卡,片选引脚为 CS,SPI 时钟频率设置为 80MHz
if (!SD.begin(CS,spi,80000000)) {
Serial.println("Card Mount Failed");
return;
}
// 获取 SD 卡类型
uint8_t cardType = SD.cardType();
// 如果没有检测到 SD 卡,则提示并退出
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
// 判断并输出 SD 卡类型
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
// 获取 SD 卡容量,单位由字节转换为 MB
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
delay(2000);
// 删除旧的 hello.txt 文件,避免之前的数据影响测试结果
deleteFile(SD, "/hello.txt");
// 创建 hello.txt 并写入"Hello "
writeFile(SD, "/hello.txt", "Hello ");
// 在 hello.txt 末尾追加"World!\n"
appendFile(SD, "/hello.txt", "World!\n");
// 读取 hello.txt 内容并打印到串口
readFile(SD, "/hello.txt");
// 对 test.txt 进行读写速度测试
testFileIO(SD, "/test.txt");
// 输出 SD 卡总空间
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
// 输出 SD 卡已使用空间
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
void loop(){
// 主循环为空,SD 卡测试流程只在 setup() 中执行一次
}