ESP32与SD卡交互实现:文件读写实战与初始化详解及引脚定义

news2024/11/15 13:31:11

本代码实现ESP32与SD卡的交互,包括定义SPI引脚、创建自定义SPI类实例、编写WriteFile与ReadFile函数进行文件读写。setup函数初始化串口、SPI、SD卡,向“/test.txt”写入“myfirstmessage”,读取并打印其内容。loop函数留空待扩展。

1. 需要准备的软硬件:

1.1 硬件:

  1. ESP32开发板在这里插入图片描述

  2. SD卡模块(如下图),可以是单独的TF卡模块也可以是集成到TFT屏幕的SD模块,TF卡与SD卡的硬件逻辑是一样,这主里不做区分在这里插入图片描述

  3. SD卡,Arduino 库仅支持 FAT16 和 FAT32 文件系统。 确保您的 SD 卡仅使用这两种格式进行格式化,否则将初始化错误。
    写本文时,在电脑上将SD卡以FAT32格式来格式化
    对于不同卡格式如下:

  • 对于SDSC卡:
    容量介于 16 MB 和 32 MB 之间 - FAT 16
    容量大于32 MB-FAT 16B
  • 对于SDHC卡
    容量小于 7.8 GB- FAT 32
    容量大于 7.8 GB- FAT 32
  • 对于SDXC卡
    exFAT

1.2 软件

  1. Arduino IDE或者在VS Code里的PlatformIO

1.3 连线方式一及代码

1.3.1 连接方式一如下表,本连线方式是用的ESP32的默认SPI接线方式,注意1.1的引脚图里23脚是VSPI MISO, 19脚是VSPI MOSI, 18脚是VSPI CLK 因此在接下来的代码中没有单独定义MISO、MOSI和CLK引脚。

引脚名称描述引脚编号
CSChip Select5
SCKClock18
MISOMaster In Slave Out19
MOSIMaster Out Slave In23

1.3.2 代码一:

/*
  SD Card Interface code for ESP32
  SPI Pins of ESP32 SD card as follows:
  CS    = 5;
  MOSI  = 23;
  MISO  = 19;
  SCK   = 18; 
*/

#include <SPI.h>
#include <SD.h>

File myFile;
const int CS = 5;

/**
 * @brief 将指定消息写入到文件中。
 * 
 * @param path 指向要写入的文件路径的字符指针。
 * @param message 指向要写入文件的消息的字符指针。
 * 该函数尝试打开指定路径的文件以进行写操作。如果文件成功打开,它将写入给定的消息,
 * 然后关闭文件,并通过串口打印一条完成消息。如果无法打开文件,它将打印错误消息和文件路径。
 */
void WriteFile(const char *path, const char *message){
  // 尝试打开文件以写入
  myFile = SD.open(path, FILE_WRITE);
  if (myFile) { // 文件打开成功
    Serial.printf("Writing to %s ", path); // 打印正在写入的文件路径
    myFile.println(message); // 写入消息到文件
    myFile.close(); // 关闭文件
    Serial.println("completed."); // 打印写入完成信息
  } 
  else { // 文件打开失败
    Serial.println("error opening file "); // 打印错误信息
    Serial.println(path); // 打印文件路径
  }
}

/**
 * 读取指定路径的文件
 * 
 * @param path 指向要打开的文件路径的字符指针
 * 
 * 该函数尝试打开指定路径的文件,如果成功打开,则逐字节读取文件内容并通过串口打印。
 * 如果无法打开文件,将打印错误信息。
 */
void ReadFile(const char *path){
  myFile = SD.open(path); // 尝试打开文件
  
  if (myFile) { // 如果文件成功打开
     Serial.printf("Reading file from %s\n", path); // 打印读取文件的路径信息
     while (myFile.available()) { // 循环,直到文件没有更多可用数据
      Serial.write(myFile.read()); // 读取并打印文件的一个字节
    }
    myFile.close(); // 关闭文件
  } 
  else {
    Serial.println("error opening test.txt"); // 如果无法打开文件,打印错误信息
  }
}

void setup() {
  Serial.begin(9600);
  delay(500);
  while (!Serial) { ; }
  Serial.println("Initializing SD card...");
  if (!SD.begin(CS)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  WriteFile("/test.txt", "ElectronicWings.com");
  ReadFile("/test.txt");
}

void loop() {
  // nothing happens after setup
}

1.4 连线方式二及代码

1.4.1 连接方式二如下表,本连线方式并没有使用ESP32默认的引脚,而是对SPI各个引脚进行了重定义

引脚名称描述引脚编号
CSChip Select23
SCKClock16
MISOMaster In Slave Out2
MOSIMaster Out Slave In17

1.4.2 代码二:

与代码一的主要不同只有下面几行:

const int MOSI_PIN = 17; // 定义SPI通信中MOSI(Master Out Slave In)信号的常量
const int MISO_PIN = 2; // 定义SPI通信中MISO(Master In Slave Out)信号的常量
const int SCK_PIN = 16; // 定义SPI通信中SCK(Serial Clock)信号的常量

// 定义一个自定义的SPI类实例
SPIClass CustomSPI;

void setup(){
  // 初始化自定义SPI通信,传入SCK、MISO、MOSI引脚及CS控制信号
  CustomSPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS);

    // 初始化SD卡,如果初始化失败则打印错误信息并返回
  if (!SD.begin(CS, CustomSPI, 1000000))
  {
    Serial.println("initialization failed!");
    return;
  }
}


完整代码如下:

#include <Arduino.h>
/*
  SD Card Interface code for ESP32
  SPI Pins of ESP32 SD card as follows:
  CS    = 23;
  MOSI  = 17;
  MISO  = 2;
  SCK   = 16;
*/

#include <SPI.h>
#include <SD.h>

// 定义一个文件对象
File myFile; 

const int CS = 23; // 定义SPI通信中CS(Chip Select)信号的常量
const int MOSI_PIN = 17; // 定义SPI通信中MOSI(Master Out Slave In)信号的常量
const int MISO_PIN = 2; // 定义SPI通信中MISO(Master In Slave Out)信号的常量
const int SCK_PIN = 16; // 定义SPI通信中SCK(Serial Clock)信号的常量

// 定义一个自定义的SPI类实例
SPIClass CustomSPI;
/**
 * @brief 将指定消息写入到文件中。
 * 
 * @param path 指向要写入的文件路径的字符指针。
 * @param message 指向要写入文件的消息的字符指针。
 * 说明:函数不返回任何值,但会在串口打印操作的结果。
 */
void WriteFile(const char *path, const char *message)
{
  // 尝试打开文件以便写入
  myFile = SD.open(path, FILE_WRITE);
  if (myFile)
  {
    // 打印正在写入的文件路径
    Serial.printf("Writing to %s ", path);
    // 写入消息到文件,并在末尾添加换行符
    myFile.println(message);
    // 关闭文件
    myFile.close(); 
    // 打印写入操作完成的通知
    Serial.println("completed.");
  }

  else
  {
    // 打印打开文件失败的通知
    Serial.println("error opening file ");
    // 打印失败的文件路径
    Serial.println(path);
  }
}

/**
 * 读取指定路径的文件
 * 
 * @param path 指向要打开的文件路径的字符指针
 * 
 * 该函数尝试打开指定路径的文件,如果成功打开,则逐字节读取文件内容并通过串口打印。
 * 如果无法打开文件,将打印错误信息。
 */
void ReadFile(const char *path)
{
  myFile = SD.open(path); // 尝试打开文件
  
  if (myFile) // 如果文件成功打开
  {
    Serial.printf("Reading file from %s\n", path); // 打印读取文件的路径信息
    while (myFile.available()) // 循环读取文件中的所有内容
    {
      Serial.write(myFile.read()); // 将读取到的每个字节通过串口发送
    }
    myFile.close(); // 关闭文件
  }
  else // 如果文件打开失败
  {
    Serial.println("error opening test.txt"); // 打印错误信息
  }
}

/**
 * @brief 初始化设置函数
 * 该函数主要完成以下初始化工作:
 * 1. 初始化串口通信,设置波特率为9600;
 * 2. 初始化自定义SPI通信,并传入SCK、MISO、MOSI引脚及CS控制信号;
 * 3. 等待串口完全初始化;
 * 4. 初始化SD卡,如果初始化失败则打印错误信息并返回;
 * 5. 写入测试文件"/test.txt";
 * 6. 读取测试文件"/test.txt"的内容。
 * 
 * 该函数没有参数和返回值。
 */
void setup()
{
  // 初始化串口通信,设置波特率为9600,并延迟500ms
  Serial.begin(9600);
  delay(500);

  // 初始化自定义SPI通信,传入SCK、MISO、MOSI引脚及CS控制信号
  CustomSPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS);

  // 等待直到串口完全初始化
  while (!Serial)
  {
    ;
  } 

  // 打印初始化SD卡的开始信息
  Serial.println("Initializing SD card...");
  
  // 初始化SD卡,如果初始化失败则打印错误信息并返回
  if (!SD.begin(CS, CustomSPI, 1000000))
  {
    Serial.println("initialization failed!");
    return;
  }
  
  // 打印SD卡初始化成功的消息
  Serial.println("initialization done.");

  // 写入测试文件"/test.txt"
  WriteFile("/test.txt", "myfirstmessage");
  
  // 读取测试文件"/test.txt"的内容
  ReadFile("/test.txt");
  //打印读取到的内容
  Serial.println("Reading from test.txt");

}

void loop()
{

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1616077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区块链安全应用-------压力测试

基于已有的链进行测试&#xff08;build_chain默认建的链 四个节 点&#xff09;&#xff1a; 第一步&#xff1a;搭链 1. 安装依赖 在ubuntu操作系统中&#xff0c;操作步骤如下&#xff1a; sudo apt install -y openssl curl 2. 创建操作目录, 下载安装脚本 ## 创建操作…

HDFS分布式文件存储系统

1-1 HDFS的存储机制 按块&#xff08;block&#xff09;存储 hdfs在对文件数据进行存储时&#xff0c;默认是按照128M(包含)大小进行文件数据拆分&#xff0c;将不同拆分的块数据存储在不同datanode服务器上 拆分后的块数据会被分别存储在不同的服务器上 副本机制 为了保证hdfs…

标题Selenium IDE 常见错误笔记

Selenium IDE 常见错误笔记 错误1&#xff1a;Failed:Exceeded waiting time for new window to appear 2000ms 这个错误通常出现在第一次运行时&#xff0c;有两个原因&#xff1a; Firefox阻止了弹出式窗口&#xff0c;在浏览器设置里允许这个操作即可。 有些网站设置了反…

轻松上手,无缝对接:详述如何接入企讯通空号检测接口API

企讯通空号检测接口API作为一款高效、精准的手机号码状态检测工具&#xff0c;能够帮助企业及开发者快速识别手机号码的有效性&#xff0c;优化通讯资源&#xff0c;提升营销效果。本篇文章将带领您一步步了解如何轻松、无缝地对接企讯通空号检测接口API&#xff0c;让您的业务…

HIVE无法启动问题

​ 启动不了hive 一直在加载中&#xff01; 问题&#xff1a;当我们打开电脑 想要学习hive时 我们却发现 它一直卡在启动页面 true一直后没有信息或者报错 原因&#xff1a;我们在之前学习时 在配置hdfs的高可用时&#xff08;High Availability 简称HA&#xff09; 高可用…

stm32HAL_GPIO输入

学会使用 GPIO 采集 KEY 的数据信息&#xff0c;这种信息采集技术在生活中常见于对大自 然环境的各种信息的采集。比如环境温度&#xff0c;湿度等等。我们这里以 key 为入门设 备。 一&#xff0c;什么是信息采集 比如环境温度&#xff0c;湿度等等。我们需要把这些温度&am…

Spire.PDF for .NET【文档操作】演示:更改 PDF 版本

在某些平台上上传或提交 PDF 文件时&#xff0c;您有时会面临平台需要特定版本的 PDF 文件的困境。如果您的PDF文件无法满足要求&#xff0c;则需要将其转换为不同版本以实现兼容性。本文将演示如何使用Spire.PDF for .NET以编程方式在不同版本之间转换 PDF。 Spire.PDF for .…

探秘数据库中间件:ProxySQL与MaxScale的优势与劣势

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 探秘数据库中间件&#xff1a;ProxySQL与MaxScale的优势与劣势 前言功能对比负载均衡故障转移查询路由使用场景和业务需求下的选择建议 性能对比响应速度并发连接数不同负载条件下的性能表现 高可用性…

R语言绘制动态网络图Network教程WGCNA

今天分享的笔记是使用NetworkD3对WGCNA的共表达网络进行可视化&#xff0c;创建交互式动态网络图&#xff0c;展示基因之间的相互关系&#xff0c;可以用于转录组或者其他调控网络展示。 加权基因共表达网络分析 (WGCNA, Weighted correlation network analysis)是用来描述不同…

大语言模型(LLM)漏洞爆发,AI模型无一幸免

本文概述了人工智能初创公司Anthropic于2024年04月03日发表的一篇针对人工智能安全的论文&#xff0c;该公司在本论文中宣布的一种新的“越狱”技术&#xff0c;名为Many-shot Jailbreaking&#xff08;多轮越狱&#xff09;。文章详细描述了目前大语言模型&#xff08;LLM&…

AI大模型探索之路-实战篇2:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

Godot3D学习笔记1——界面布局简介

创建完成项目之后可以看到如下界面&#xff1a; Godot引擎也是场景式编程&#xff0c;这里的一个场景相当于一个关卡。 这里我们点击左侧“3D场景”按钮创建一个3D场景&#xff0c;现在在中间的画面中会出现一个球。在左侧节点视图中选中“Node3D”&#xff0c;右键创建子节点…

day_8题解

利用最大公约数求最小公倍数 #include<iostream> using namespace std;int gcd(int a,int b) {return b?gcd(b,a%b):a; }int main() {long long a,b;cin>>a>>b;long long ansgcd(a,b);cout<<(a*b)/ans<<endl;return 0; }排序遍历&#xff0c;记…

国内开通chatgpt plus会员方法

ChatGPT镜像 今天在知乎看到一个问题&#xff1a;“平民不参与内测的话没有账号还有机会使用ChatGPT吗&#xff1f;” 从去年GPT大火到现在&#xff0c;关于GPT的消息铺天盖地&#xff0c;真要有心想要去用&#xff0c;途径很多&#xff0c;别的不说&#xff0c;国内GPT的镜像…

excel中怎么用乘法、加法来替代AND和OR函数

你可以使用乘法和加法来替代Excel中的AND和OR函数&#xff0c;虽然这样做可能会增加公式的复杂度&#xff0c;但在某些情况下是可行的。 1. 使用乘法替代AND函数&#xff1a;AND函数用于判断一系列条件是否同时成立&#xff0c;如果所有条件都为TRUE&#xff0c;则返回TRUE&…

高通发布电脑CPU,比英特尔Ultra9领先51%

要说2024年最热门的关键词&#xff0c;那肯定非 AI 莫属&#xff0c;当前 AI 已经开始深入各行各业&#xff0c;AI 电视、AI 手机、AI 车机、AI 家电&#xff0c;以及 AI PC ,这些都意味着 AI 将对各个行业带来的新风向和不小的冲击。 2024 年了&#xff0c;PC 处理器还能卷出什…

idea2019.3.5版本安装配置

安装 下载地址&#xff1a;https://www.jetbrains.com/idea/download/other.html 配置idea缓存文件位置 注意&#xff1a;为了避免后续的麻烦&#xff0c;此步骤必须为安装或者重装idea的第一步骤&#xff01;&#xff01;&#xff01; 注意&#xff1a;为了避免后续的麻烦&…

Android Studio开发工具学习之Git远程仓库拉取与推送

Git远程仓库操作 1.1 推送项目到远端服务器1.1.1 进入Gitee或Github、创建一个新的仓库1.1.2 将Android Studio中项目推送至Gitee 1.2 从远端服务器拉取项目1.2.1 AS工程页拉取新项目1.2.2 AS启动页拉取项目 1.1 推送项目到远端服务器 1.1.1 进入Gitee或Github、创建一个新的仓…

Redis 如何实现分布式锁

课程地址 单机 Redis naive 版 加锁&#xff1a; SETNX ${lockName} ${value} # set if not exist如果不存在则插入成功&#xff0c;返回 1&#xff0c;加锁成功&#xff1b;否则返回 0&#xff0c;加锁失败 解锁&#xff1a; DEL ${lockName}问题1 2 个线程 A、B&#…

实验 1--SQL Server2008数据库开发环境

文章目录 实验 1--SQL Server2008数据库开发环境2.4.1 实验目的2.4.2 实验准备2.4.3 实验内容1.利用 SSMS 访问系统自带的Report Server 数据库。2.熟悉了解 SMSS对象资源管理器树形菜单相关选择项的功能。(1)右键单击数据库Report Server&#xff0c;查看并使用相关功能;(2)选…