ESP32 开发笔记(三)源码示例 9_SPI_SDCard 使用SPI总线实现TF卡文件系统示例

开发板购买链接

https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111deb2Ij1As&ft=t&id=626366733674

开发板简介
开发环境搭建 windows

ESP32例程为C语言开发,并非Python/Arduino/AT指令开发,基于ESP-IDF_V4.2框架库,采用纯C语言开发,开发工具为Visual Studio Code

Android(安卓)例程全部为原生Android开发,例程全部支持到SDK版本29  Android 10.0(Q) 开发工具为Andirod Studio 4.0

PC源码例程为Visual Studio 2013开发,C++语言,基于MFC

送的MQTT账号,仅用于同学们开发测试,大家不要用到实际产品上,不定期更换密码,会在QQ群公布


以下列出的例程源码均编写完成(不断增加中),开发教程正在编写
基础例程:
    0_Hello Bug (ESP_LOGX与printf)    工程模板/打印调试输出
    1_LED                                                    LED亮灭控制       
    2_LED_Task                                          使用任务方式控制LED
    3_LEDC_PWM                                      使用LEDC来控制LED实现呼吸灯效果
    4_ADC_LightR                                      使用ADC读取光敏电阻实现光照传感
    5_KEY_Short_Long                              按钮长按短按实现
    6_TouchPad_Interrupt                          电容触摸中断实现
    7_WS2812_RMT                                  使用RMT实现RGB_LED彩虹变色示例
    8_DHT11_RMT                                    使用RMT实现读取DHT11温湿度传感器
    9_SPI_SDCard                                    使用SPI总线实现TF卡文件系统示例
    10_IIC_ADXL345                                使用IIC总线实现读取ADXL345角度加速度传感器
    11_IIC_AT24C02                                 使用IIC总线实现小容量数据储存测试
    12_IR_Rev_RMT                                使用RMT实现红外遥控接收解码(NEC编码)
    13_IR_Send_RMT                              使用RMT实现红外数据发送(NEC编码)
    14_WIFI_Scan                                    附近WIFI信号扫描示例    
    15_WIFI_AP                                        创建软AP示例
    16_WIFI_AP_TCP_Server                  在软AP模式下实现TCP服务端
    17_WIFI_AP_TCP_Client                   在软AP模式下实现TCP客户端
    18_WIFI_AP_UDP                              在软AP模式下实现UDP通讯
    19_WIFI_STA                                      创建STA站模连接路由器
    20_WIFI_STA_TCP_Server                在站模式STA下实现TCP服务端
    21_WIFI_STA_TCP_Client                 在站模式STA下实现TCP客户端
    22_WIFI_STA_UDP                            在站模式STA下实现UDP通讯
    23_LCD_Test                                      LCD液晶触摸屏显示测试
    24_XPT2046_Touch_Test                   电阻触摸XPT2046驱动测试触摸校正
ESP32应用例程
    Bluetooth_RGBLight                          Android手机通过蓝牙控制RGB灯变色
    Bluetooth_Sensor                              Android手机通过蓝牙读取开发板姿态和温度湿度参数
    Bluetooth_Test                                   Android手机通过蓝牙与开发板通讯
    Encryption_MD5                                MD5加密
    Encryption_SHA1                              SHA1加密
    Encryption_SHA256                          SHA256加密
    EncryptionDecrypt_AES_CBC          AES_CBC加密
    EncryptionDecrypt_AES_ECB          AES_ECB加密
    ESP32_SmartConfig                         通过Android手机配置WIFI连网
    HTTP_GET_Request_Weather        HTTP Get请求天气预报
    JSON_Package                                创建JSON数据包
    JSON_Parsing                                  解析JSON数据包
    LCD JPEG_Effect                             解码JGEG图片特效显示
    MQTT                                                MQTT通讯测试
Android(安卓)工具源码
 
  ESP32_Bluetooth_Chat                   Android通过蓝牙与开发板通讯测试
    ESP32_Bluetooth_RGBLight           Android通过蓝牙控制开发板RGB灯
    ESP32_Bluetooth_Sensor               Android通过蓝牙读取开发板3D姿态和温度湿度数据
    ESP32_SmartConfig                       Android手机配置WIFI配网
    MQTT_Test                                     Android与开发板通过MQTT协议通讯
    TCP_Client                                     Android作为TCP客户端与开发板通讯 
    UDP_Client                                     Android通过UDP协议与开发板通讯
PC(Visual Studio 2013 C++ MFC)工具源码
    MQTT_调试助手                                 PC通过MQTT与开发板通讯
    TCP 调试助手                                     PC通过TCP服务器/客户端与开发板通讯
    UDP 调试助手                                     PC通过UDP与开发板通讯
LVGL源码   
    LVGL_Full_Test                                  LVGL官方例程(使用到了大分部控件)
    LVGL_Arc_Test                                  圆弧指示器通过触摸动态改变值
    LVGL_Bar_Test                                  通过动画方式动态演示Bar进度条的使用方法
    LVGL_Button_Test                             通过5种不同动态效果的按钮学习按钮的创建与使用
    LVGL_ButtonMatrix_Test                   创建一个计算器布局来演示矩阵按钮控件的使用
    LVGL_Calendar_Test                         日历控件的创建和使用
    LVGL_Canvas_Test                           透明画布和画一个圆角过渡色矩形并旋转角度学习画布的使用
    LVGL_Chart_Test                               通过创建三个不同风格的图表来学习图表控件的使用
    LVGL_Checkbox_Test                        学习复选框控件的创建和使用
    LVGL_ColorPicker_Test                     创建一个颜色选择器并动态显示当前颜色的RGB值
    LVGL_Container_Test                        在内容控件上动态创建三个文本标签学习内容控件的自适应布局
    LVGL_Drop_down_List_Test              创建三个不同类型的下拉选择控件
    LVGL_Gauge_Test                             创建一个动态仪表和静态多指针仪表
    LVGL_Image_Test                              通过四个滑动条控件控制图片颜色的变化来学习图像控件的使用
    LVGL_ImageButton_Test                  创建一个图片背景的图像按钮
    LVGL_Keyboard_Test                       通过一个文本输入框控件还学习键盘控件的调用关闭设置
    LVGL_Label_Test                              创建内容颜色可变,长文本滚动展示,带阴影3D效果三个标签控件
    LVGL_LED_Test                                创建三个LED,学习LED控件的调光,颜色,开关的设置
    LVGL_Line_Test                                通过二维数组创建一段折线来演示线控件的使用
    LVGL_LineMeter_Test                      创建两个不同的线段弧形指示器动态展示数据
    LVGL_List_Test                                 创建一个带图标的列表控件
    LVGL_MessageBox_Test                  创建一个带按钮的消息框控件
    LVGL_ObjectMask_Test                    创建一个变幻色的文本学习蒙版遮罩效果
    LVGL_Page_Test                            学习页面控件的使用
    LVGL_Roller_Test                           通过示例学习滑动列表选择器控件
    LVGL_Slider_Test                           创建一个单向和一个双向滑动条控件
    LVGL_Spinbox_Test                        学习微调控件的使用
    LVGL_Spinner_Test                        创建三个不同的环形加载器
    LVGL_Switch_Test                          创建两个不同的开关控件
    LVGL_Table_Test                            创建一个简单的表格
    LVGL_Tabview_Test                       实现三页的页面切换学习Tabview控件
    LVGL_Textarea_Test                       长按实现打字机效果的Textarea控件
    LVGL_Tileview_Test                        实现四面环形触摸切换的Tileview控件
    LVGL_Window_Test                        创建一个窗口,带设置子窗口学习窗口控件的使用

 

Micro SD Card,原名Trans-flash Card(TF卡),2004年正式更名为Micro SD Card,由SanDisk(闪迪)公司发明,主要用于移动电话。
在Micro SD面市之前,手机制造商都采用嵌入式记忆体,虽然这类模组容易装设,然而有着无法应实际应潮流需求的困扰——容量被限制住了,无法再有升级空间。Micro SD仿效SIM卡的应用模式,即是同一张卡可以应用在不同型号的行动电话内,让行动电话制造商不用再为插卡式的研发设计而伤脑筋。 Micro SD卡足以堪称可移动式的储存IC。
Micro SD卡是一种极细小的快闪存储器卡,其格式源自SanDisk创造,原本这种记忆卡称为T-Flash,及后改称为Trans Flash;而重新命名为Micro SD的原因是因为被SD协会 (SDA) 采立。另一些被SDA采立的记忆卡包括Mini SD和SD卡。其主要应用于移动电话,但因它的体积微小和储存容量的不断提高,已经使用于GPS设备、便携式音乐播放器和一些快闪存储器盘中。它的体积为 15mm x 11mm x1mm ,差不多相等于手指甲的大小,是现时最细小的记忆卡。它也能通过SD转接卡来接驳于SD卡插槽中使用。 现时MicroSD卡提供128MB、256MB、512MB、1G、2G、4G、8G、16G、32G、64G、128G的容量(MWC 2014 世界移动通信大会期间,SanDisk(闪迪)打破了储存卡最高64GB容量的传统,正式发布了一款容量高达128GB的 Micro SD XC 储存卡。

SD卡的操作模式:SD卡模式(SDIO)、SPI模式(默认为SD模式)。

其中SD卡模式的信号线有:CLK、CMD、DAT0-DAT3,6根线。

SPI模式的信号线有:CS、CLK、MISO(DATAOUT)、MOSI(DATAIN),4根线。

SDIO

  1. CLK 时钟同步线
  2. CMD 命令信号线,主机发出的命令以及从机对命令的响应都是通过这条线进行传输
  3. DAT[3:0] 表示4条数据线,主机和从机的数据都是从这四条数据线上传输

SPI

SD卡只能使用3.3V的I/O电平。SPI模式下信号线要加10-100K的上拉电阻。

SD卡有五个寄存器:

名称宽度描述
CID128卡标识寄存器
RCA16相对地址寄存器(Relative Card Address):本地系统中卡的地址,动态变化,在主机初始化的时候确定,SPI模式中没有。
CSD128卡描述数据:卡操作条件相关的信息数据
SCR64SD配置寄存器:SD卡特定信息数据
OCR32操作条件寄存器

SD卡的命令格式:

命令CMD0就是0,CMD16就是16,以此类推。

SPI命令格式为6字节构成,高位在前(MSB)。

字节1字节2-5字节6
765-0
01command

字节1的最高2位固定是01,低6位为命令号(CMD0就是0,CMD16就是16,以此类推),字节2-5为命令参数,有些命令是没有参数的;字节6的高7位为CRC,最低位恒为1。

SD卡的命令总共有12类,下表为几个比较重要的命令:
SD卡的主要相关各种命令解析
CMD0: SD卡进入IDLE和复位SD卡
CMD1: 读OCR,是否为SD卡
CMD2: 获取卡CID信息
CMD3: 获取SD卡所分配的相对地址
CMD9: 获取SD卡的存储信息(容量、块大小等)
CMD12:停止传输操作
CMD13:获取卡的状态
CMD16:设置SD卡块大小
CMD17:使SD卡进入传输状态、读取单个块
CMD18: 使SD卡进入传输状态、读取多个块,直到收到CMD12为止
CMD24:使SD卡进入传输状态、写入单个块
CMD25: 使SD卡进入传输状态、写入多个块

命令参数回应描述
CMD0(0X00)NONER1复位SD卡
CMD8(0X08)VHS+Check PatternR7发送接口状态命令
CMD9(0X09)NONER1读取卡特定数据寄存器
CMD10(0X0A)NONER1读取卡标志数据寄存器
CMD16(0X10)块大小R1设置块大小(字节数)
CMD17(0X11)地址R1读取一个块的数据
CMD24(0X18)地址R1写入一个块的数据
CMD41(0X29)NONER3发送给主机容量支持信息和激活卡初始化过程
CMD55(0X37)NONER1告诉SD卡,下一个是特定应用命令
CMD58(0X3A)NONER3读取OCR寄存器

SD卡和单片机的通信采用发送应答机制:

发送应答机制

 

ESP32 FAT 文件系统

ESP-IDF 使用 FatFs 库来实现 FAT 文件系统。FatFs 库位于 fatfs 组件中,您可以直接使用,也可以借助 C 标准库和 POSIX API 通过 VFS(虚拟文件系统)使用 FatFs 库的大多数功能。

此外,对 FatFs 库进行了扩展,新增了支持可插拔磁盘 I/O 调度层,从而允许在运行时将 FatFs 驱动映射到物理磁盘。

FatFs 与 VFS 配合使用

函数 esp_vfs_fat_register() 分配一个 FATFS 结构,并在 VFS 中注册特定路径前缀。如果文件路径以此前缀开头,则对此文件的后续操作将转至 FatFs API。函数 esp_vfs_fat_unregister_path() 删除在 VFS 中的注册,并释放 FATFS 结构。

多数应用程序在使用 esp_vfs_fat_ 函数时,采用如下步骤:

调用 esp_vfs_fat_register(),指定:

      挂载文件系统的路径前缀(例如,"/sdcard" 或 "/spiflash")
      FatFs 驱动编号
      一个用于接收指向 FATFS 结构指针的变量

调用 ff_diskio_register() 为上述步骤中的驱动编号注册磁盘 I/O 驱动;
调用 FatFs 函数 f_mount,或 f_fdisk, f_mkfs,并使用与传递到 esp_vfs_fat_register() 相同的驱动编号挂载文件系统。请参考 FatFs 文档,
调用 C 标准库和 POSIX API 对路径中带有步骤 1 中所述前缀的文件(例如,"/sdcard/hello.txt")执行打开、读取、写入、擦除、复制等操作。
您可以选择直接调用 FatFs 库函数,但需要使用没有 VFS 前缀的路径(例如,"/hello.txt");
关闭所有打开的文件;
调用 f_mount 并使用 NULL FATFS* 参数为与上述编号相同的驱动卸载文件系统;
调用 FatFs 函数 ff_diskio_register() 并使用 NULL ff_diskio_impl_t* 参数和相同的驱动编号来释放注册的磁盘 I/O 驱动。
调用 esp_vfs_fat_unregister_path() 并使用文件系统挂载的路径将 FatFs 从 NVS 中移除,并释放步骤 1 中分配的 FatFs 结构。
esp_vfs_fat_sdmmc_mount 和 esp_vfs_fat_sdmmc_unmount 这两个便捷函数对上述步骤进行了封装,并加入对 SD 卡初始化的处理,非常便捷。

一、硬件设计/原理

查看开发板原理图,TF卡使用SPI总线连接到ESP32主控,对信号线进行10K上拉。

二、程序设计

先引用必要头文件

// SD card and FAT filesystem example

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "sdkconfig.h"

定义SPI总线GPIO

static const char *TAG = "TF Card Fat Example";
#define MOUNT_POINT "/sdcard"
#define SPI_DMA_CHAN    1

//在测试SD和SPI模式时,请记住,一旦在SPI模式下初始化了卡,在不接通卡电源的情况下就无法在SD模式下将其重新初始化。
#define PIN_NUM_MISO		19
#define PIN_NUM_MOSI		23
#define PIN_NUM_CLK			18
#define PIN_NUM_CS			5

主函数,测试文件系统,读取,写入、获取总容量、卡信息、剩余容量、更名、删除等操作


void app_main(void)
{
	esp_err_t ret;								// ESP错误定义
	sdmmc_card_t* card;							// SD / MMC卡信息结构
	const char mount_point[] = MOUNT_POINT;		// 根目录
	char ReadFileBuff[64];

	esp_vfs_fat_sdmmc_mount_config_t mount_config = {	// 文件系统挂载配置
		.format_if_mount_failed = false,				// 如果挂载失败:true会重新分区和格式化/false不会重新分区和格式化
		.max_files = 5,									// 打开文件最大数量
		.allocation_unit_size = 16 * 1024
	};

	printf("%s->Initializing SD card\r\n",TAG);
	printf("%s->Using SPI peripheralr\r\n",TAG);
	sdmmc_host_t host = SDSPI_HOST_DEFAULT();
	spi_bus_config_t bus_cfg = {
		.mosi_io_num = PIN_NUM_MOSI,
		.miso_io_num = PIN_NUM_MISO,
		.sclk_io_num = PIN_NUM_CLK,
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,
		.max_transfer_sz = 4000,
	};
	// SPI总线初始化
	ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
	if (ret != ESP_OK) {
		printf("%s->Failed to initialize bus.\r\n",TAG);
		return;
	}
	// 这将初始化没有卡检测(CD)和写保护(WP)信号的插槽。
	// 如果您的主板有这些信号,请修改slot_config.gpio_cd和slot_config.gpio_wp。
	sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
	slot_config.gpio_cs = PIN_NUM_CS;
	slot_config.host_id = host.slot;
	// 挂载文件系统
	ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
	if (ret != ESP_OK) {
		if (ret == ESP_FAIL) {
			printf("%s->Failed to mount filesystem.%s\r\n",TAG,
				"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
		} else {
			printf("%s->Failed to initialize the card %s  (%s). ",TAG,
				"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
		}
		return;
	}
	// TF卡已经初始化,打印TF卡属性
	sdmmc_card_print_info(stdout, card);

    // Print FAT FS size information
    size_t bytes_total, bytes_free;
    get_fatfs_usage(&bytes_total, &bytes_free);
    printf("%s->FAT FS Total: %d MB, Free: %d MB \r\n",TAG, bytes_total / 1024, bytes_free / 1024);


	// 使用POSIX和C标准库函数来处理文件。
	printf("%s->Opening file\r\n",TAG);
	FILE* f = fopen(MOUNT_POINT"/hello.txt", "w");// 创建一个文件
	if (f == NULL) {
		printf("%s->Failed to open file for writing\r\n",TAG);
		return;
	}
	fprintf(f, "Hello %s!\n", card->cid.name);
	fclose(f);
	printf("%s->File written\r\n",TAG);

	// 重命名前检查目标文件是否存在
	struct stat st;
	if (stat(MOUNT_POINT"/foo.txt", &st) == 0) {
		unlink(MOUNT_POINT"/foo.txt");// 删除(如果存在)
	}

	// 重命名文件
	printf("%s->Renaming file\r\n",TAG);
	if (rename(MOUNT_POINT"/hello.txt", MOUNT_POINT"/foo.txt") != 0) {
		printf("%s->Rename failed\r\n",TAG);
		return;
	}

	// 读取文件
	printf("%s->Reading file\r\n",TAG);
	f = fopen(MOUNT_POINT"/foo.txt", "r");// 读取方式打开文件
	if (f == NULL) {
		printf("%s->Failed to open file for reading\r\n",TAG);
		return;
	}
	fgets(ReadFileBuff, sizeof(ReadFileBuff), f);	// 读取一行数据
	fclose(f);										// 关闭文件 
	char* pos = strchr(ReadFileBuff, '\n');			// 在字符串中查找换行
	if (pos) {
		*pos = '\0';								// 替换为结束符
	}
	printf("%s->Read from file: '%s'\r\n",TAG,ReadFileBuff);

	// 卸载分区并禁用SDMMC或SPI外设
	esp_vfs_fat_sdcard_unmount(mount_point, card);
	printf("%s->Card unmounted\r\n",TAG);
	//卸载总线
	spi_bus_free(host.slot);
}

三、下载测试

打开ESP-IDF Command Prompt

cd命令进入此工程目录

cd F:\ESP32_DevBoard_File\9_SPI_SDCard

查看电脑设备管理器中开发板的串口号

执行idf.py -p COM9 flash monitor从串口9下载并运行打开口显示设备调试信息   Ctrl+c退出运行,查看串口信息输出

测试卡为16G闪迪 class 10 TF卡

 

  • 6
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值