【MicroPython ESP32】通过sdcard模块读取SD卡实例


  • 本实验基于Thonny平台开发。esp32固件版本MicroPython v1.19.1 on 2022-06-18; ESP32 module with ESP32

  • Micro SD卡模块(TF卡读写卡器 SPI 带电平转换芯片)

  • sdcard模块

  • MicroPython源码:https://github.com/micropython/micropython

sdcard模块可以在MicroPython源码中找到。

"""
MicroPython driver for SD cards using SPI bus.Requires an SPI bus and a CS pin.  Provides readblocks and writeblocks
methods so the device can be mounted as a filesystem.Example usage on pyboard:import pyb, sdcard, ossd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5)pyb.mount(sd, '/sd2')os.listdir('/')Example usage on ESP8266:import machine, sdcard, ossd = sdcard.SDCard(machine.SPI(1), machine.Pin(15))os.mount(sd, '/sd')os.listdir('/')"""from micropython import const
import time_CMD_TIMEOUT = const(100)_R1_IDLE_STATE = const(1 << 0)
# R1_ERASE_RESET = const(1 << 1)
_R1_ILLEGAL_COMMAND = const(1 << 2)
# R1_COM_CRC_ERROR = const(1 << 3)
# R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
# R1_ADDRESS_ERROR = const(1 << 5)
# R1_PARAMETER_ERROR = const(1 << 6)
_TOKEN_CMD25 = const(0xFC)
_TOKEN_STOP_TRAN = const(0xFD)
_TOKEN_DATA = const(0xFE)class SDCard:def __init__(self, spi, cs, baudrate=1320000):self.spi = spiself.cs = csself.cmdbuf = bytearray(6)self.dummybuf = bytearray(512)self.tokenbuf = bytearray(1)for i in range(512):self.dummybuf[i] = 0xFFself.dummybuf_memoryview = memoryview(self.dummybuf)# initialise the cardself.init_card(baudrate)def init_spi(self, baudrate):try:master = self.spi.MASTERexcept AttributeError:# on ESP8266self.spi.init(baudrate=baudrate, phase=0, polarity=0)else:# on pyboardself.spi.init(master, baudrate=baudrate, phase=0, polarity=0)def init_card(self, baudrate):# init CS pinself.cs.init(self.cs.OUT, value=1)# init SPI bus; use low data rate for initialisationself.init_spi(100000)# clock card at least 100 cycles with cs highfor i in range(16):self.spi.write(b"\xff")# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)for _ in range(5):if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:breakelse:raise OSError("no SD card")# CMD8: determine card versionr = self.cmd(8, 0x01AA, 0x87, 4)if r == _R1_IDLE_STATE:self.init_card_v2()elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):self.init_card_v1()else:raise OSError("couldn't determine SD card version")# get the number of sectors# CMD9: response R2 (R1 byte + 16-byte block read)if self.cmd(9, 0, 0, 0, False) != 0:raise OSError("no response from SD card")csd = bytearray(16)self.readinto(csd)if csd[0] & 0xC0 == 0x40:  # CSD version 2.0self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024elif csd[0] & 0xC0 == 0x00:  # CSD version 1.0 (old, <=2GB)c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7read_bl_len = csd[5] & 0b1111capacity = (c_size + 1) * (2 ** (c_size_mult + 2)) * (2**read_bl_len)self.sectors = capacity // 512else:raise OSError("SD card CSD format not supported")# print('sectors', self.sectors)# CMD16: set block length to 512 bytesif self.cmd(16, 512, 0) != 0:raise OSError("can't set 512 block size")# set to high data rate now that it's initialisedself.init_spi(baudrate)def init_card_v1(self):for i in range(_CMD_TIMEOUT):self.cmd(55, 0, 0)if self.cmd(41, 0, 0) == 0:# SDSC card, uses byte addressing in read/write/erase commandsself.cdv = 512# print("[SDCard] v1 card")returnraise OSError("timeout waiting for v1 card")def init_card_v2(self):for i in range(_CMD_TIMEOUT):time.sleep_ms(50)self.cmd(58, 0, 0, 4)self.cmd(55, 0, 0)if self.cmd(41, 0x40000000, 0) == 0:self.cmd(58, 0, 0, -4)  # 4-byte response, negative means keep the first byteocr = self.tokenbuf[0]  # get first byte of response, which is OCRif not ocr & 0x40:# SDSC card, uses byte addressing in read/write/erase commandsself.cdv = 512else:# SDHC/SDXC card, uses block addressing in read/write/erase commandsself.cdv = 1# print("[SDCard] v2 card")returnraise OSError("timeout waiting for v2 card")def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):self.cs(0)# create and send the commandbuf = self.cmdbufbuf[0] = 0x40 | cmdbuf[1] = arg >> 24buf[2] = arg >> 16buf[3] = arg >> 8buf[4] = argbuf[5] = crcself.spi.write(buf)if skip1:self.spi.readinto(self.tokenbuf, 0xFF)# wait for the response (response[7] == 0)for i in range(_CMD_TIMEOUT):self.spi.readinto(self.tokenbuf, 0xFF)response = self.tokenbuf[0]if not (response & 0x80):# this could be a big-endian integer that we are getting here# if final<0 then store the first byte to tokenbuf and discard the restif final < 0:self.spi.readinto(self.tokenbuf, 0xFF)final = -1 - finalfor j in range(final):self.spi.write(b"\xff")if release:self.cs(1)self.spi.write(b"\xff")return response# timeoutself.cs(1)self.spi.write(b"\xff")return -1def readinto(self, buf):self.cs(0)# read until start byte (0xff)for i in range(_CMD_TIMEOUT):self.spi.readinto(self.tokenbuf, 0xFF)if self.tokenbuf[0] == _TOKEN_DATA:breaktime.sleep_ms(1)else:self.cs(1)raise OSError("timeout waiting for response")# read datamv = self.dummybuf_memoryviewif len(buf) != len(mv):mv = mv[: len(buf)]self.spi.write_readinto(mv, buf)# read checksumself.spi.write(b"\xff")self.spi.write(b"\xff")self.cs(1)self.spi.write(b"\xff")def write(self, token, buf):self.cs(0)# send: start of block, data, checksumself.spi.read(1, token)self.spi.write(buf)self.spi.write(b"\xff")self.spi.write(b"\xff")# check the responseif (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05:self.cs(1)self.spi.write(b"\xff")return# wait for write to finishwhile self.spi.read(1, 0xFF)[0] == 0:passself.cs(1)self.spi.write(b"\xff")def write_token(self, token):self.cs(0)self.spi.read(1, token)self.spi.write(b"\xff")# wait for write to finishwhile self.spi.read(1, 0xFF)[0] == 0x00:passself.cs(1)self.spi.write(b"\xff")def readblocks(self, block_num, buf):nblocks = len(buf) // 512assert nblocks and not len(buf) % 512, "Buffer length is invalid"if nblocks == 1:# CMD17: set read address for single blockif self.cmd(17, block_num * self.cdv, 0, release=False) != 0:# release the cardself.cs(1)raise OSError(5)  # EIO# receive the data and release cardself.readinto(buf)else:# CMD18: set read address for multiple blocksif self.cmd(18, block_num * self.cdv, 0, release=False) != 0:# release the cardself.cs(1)raise OSError(5)  # EIOoffset = 0mv = memoryview(buf)while nblocks:# receive the data and release cardself.readinto(mv[offset : offset + 512])offset += 512nblocks -= 1if self.cmd(12, 0, 0xFF, skip1=True):raise OSError(5)  # EIOdef writeblocks(self, block_num, buf):nblocks, err = divmod(len(buf), 512)assert nblocks and not err, "Buffer length is invalid"if nblocks == 1:# CMD24: set write address for single blockif self.cmd(24, block_num * self.cdv, 0) != 0:raise OSError(5)  # EIO# send the dataself.write(_TOKEN_DATA, buf)else:# CMD25: set write address for first blockif self.cmd(25, block_num * self.cdv, 0) != 0:raise OSError(5)  # EIO# send the dataoffset = 0mv = memoryview(buf)while nblocks:self.write(_TOKEN_CMD25, mv[offset : offset + 512])offset += 512nblocks -= 1self.write_token(_TOKEN_STOP_TRAN)def ioctl(self, op, arg):if op == 4:  # get number of blocksreturn self.sectorsif op == 5:  # get block size in bytesreturn 512

引脚接线说明

  • 使用的是VSPI总线
SPI MOSI MISO CLK CS
VSPI 23 19 18 5

  • SPI通讯
1.GND-for the ground pins.
2.VCC-for the supply voltage.
3.MISO-for the SPI Master Input Slave Output pin.
4.MOSI-for the SPI Master Output Slave Input pin.
5.SCK-for the SPI Serial Clock pin.
6.CS-for the SPI Chip Select pin.
  1. gnd -用于接地插脚。
  2. vcc- 电源电压。
  3. miso-用于SPI主输入从输出引脚。
  4. mosi -用于SPI主输出从输入引脚。
  5. sck -用于SPI串行时钟引脚。
  6. cs -用于SPI芯片选择引脚。

  • esp32 Devkeit
sck=Pin(17),
mosi=Pin(23),
miso=Pin(19)
SD_CS= Pin(5)
  • 本实例需要引入sdcard模块

运行代码前,需要先将sdcard模块保存到MicroPython设备当中。

程序实例一代码

import machine, sdcard, os
from machine import SPI
from machine import Pin
SD_CS = Pin(5)
sd = sdcard.SDCard(SPI(2,sck=Pin(17), mosi=Pin(23),miso=Pin(19)), SD_CS)
# 初始化⽂件系统
vfs = os.VfsFat(sd)# fat挂载卡到⽬录下
os.mount(sd,"/sd")# SD/sd
dirs=os.listdir('/sd')
for file in dirs:   print(file)

程序实例二代码

import os, sdcard, machine
from machine import SPI
from machine import Pindef sdtest():SD_CS = Pin(5)sd = sdcard.SDCard(SPI(2,sck=Pin(17), mosi=Pin(23),miso=Pin(19)), SD_CS)  vfs = os.VfsFat(sd)os.mount(vfs, "/fc")print("Filesystem check")print(os.listdir("/fc"))line = "abcdefghijklmnopqrstuvwxyz\n"lines = line * 200  # 5400 charsshort = "1234567890\n"fn = "/fc/rats.txt"print()print("Multiple block read/write")with open(fn, "w") as f:n = f.write(lines)print(n, "bytes written")n = f.write(short)print(n, "bytes written")n = f.write(lines)print(n, "bytes written")with open(fn, "r") as f:result1 = f.read()print(len(result1), "bytes read")fn = "/fc/rats1.txt"print()print("Single block read/write")with open(fn, "w") as f:n = f.write(short)  # one blockprint(n, "bytes written")with open(fn, "r") as f:result2 = f.read()print(len(result2), "bytes read")os.umount("/fc")print()print("Verifying data read back")success = Trueif result1 == "".join((lines, short, lines)):print("Large file Pass")else:print("Large file Fail")success = Falseif result2 == short:print("Small file Pass")else:print("Small file Fail")success = Falseprint()print("Tests", "passed" if success else "failed")if __name__ == '__main__':sdtest()

【MicroPython ESP32】通过sdcard模块读取SD卡实例相关推荐

  1. Arduino ESP32 读取SD卡接口选择参考

    ESP32 读取SD卡接口选择参考 ESP3232读取SD卡可以通过spi和sdmmc两种方式来读取,不过我们在市面上能买到的都基本上是4线的SPI接口的SD卡模块套件. 卡类型有如下,8-9Pin被 ...

  2. Arduino ESP32 第三方库读取SD卡信息(三)

    Arduino ESP32 第三方库读取SD卡信息(三) 相关篇<Arduino ESP32 第三方库读取SD卡信息(一)> <Arduino ESP32 第三方库读取SD卡信息(二 ...

  3. 《Arduino》开发 TFT_eSPI-master 库 之用 ESP32 读取SD卡上的图片并显示在1.14IPS屏幕上

    前几天解决了 TFT_eSPI-master 库 图片取模问题,但尽管是ESP32的 flash 也无法存储太多图片的数组,因此我找到了ESP32从SD卡读取图片并显示在LCD屏幕上的方法,SD卡可以 ...

  4. ESP32基于Arduino框架,SD卡+MAX98357模块+MP3播放器

    ESP32基于Arduino框架,SD卡+MAX98357模块+MP3播放器

  5. 使用Arduino开发ESP32(13):SD卡的使用

    文章目录 目的 SDMMC方式 常用方法 使用示例 SPI方式 常用方法 使用示例 注意事项 总结 目的 对于嵌入式设备来说SD卡也是个比较好用的功能,比如用来存放设备的配置文件.日志文件.执行脚本. ...

  6. 绘制STM32最小系统电路原理图、STM32F103读取SD卡的数据

    绘制STM32最小系统电路原理图.STM32F103读取SD卡的数据 文章目录 绘制STM32最小系统电路原理图.STM32F103读取SD卡的数据 1 AltiumDesigner 软件配置 2 A ...

  7. android 读取sd卡中的图片

    一.获取读取SD卡的权限 <!--在SDCard中创建与删除文件权限 --><uses-permission android:name="android.permissio ...

  8. android 音乐播放器 获取sd卡所有音乐文件,Android Studio音乐播放器无法读取SD卡,只有内部存储器...

    我很抱歉,如果这原来是一个愚蠢的问题,它可能会成为一个快速修复,但我只是无法弄清楚.我在android studio中创建了音乐播放器,并且没有任何sdcard上的歌曲不会显示在列表视图中,只有内部内 ...

  9. stm32 读取sd卡图片显示_「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验...

    1)实验平台:正点原子STM32mini开发板 2)摘自<正点原子STM32 不完全手册(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第三十五章 汉字显示实验 汉字显示在 ...

最新文章

  1. Linux中crontab定时执行python程序
  2. Linux网络管理之四:创建一个简单的vsftpd服务器
  3. 安装的 Python 版本太多互相干扰?pyenv 建议了解一下。
  4. C# WPF 之 遍历子控件
  5. 【Android Gradle 插件】Android Plugin DSL Reference 离线文档下载 ( GitHub 下载文档 | 查看文档 )
  6. excel表格最大行数
  7. 阿里云,我的一些看法
  8. 编写高性能 Web 应用程序的 10 个技巧 (转)
  9. Centos启动卡住,starting auditd: [failed]
  10. 【踩坑】Linux下配置torch-geometric
  11. 下一代操作系统与软件
  12. 基于SSM实现的房屋租赁系统【附源码】(毕设)
  13. 明翰英语教学系列之雅思听力篇V0.2(持续更新)
  14. crt软件(crt软件安装)
  15. Mandriva Linux 2012 Alpha 2 发布
  16. linux下故障硬盘点灯操作
  17. 配置基于虚拟隧道接口的IPSec隧道实验
  18. {Django基础九之中间件} 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证...
  19. 红蓝对抗之域名搜集方法总结
  20. 单片机-嵌入式相关的一些论坛

热门文章

  1. HTML元素的显示和隐藏
  2. linux mdadm 源码,linux下使用mdadm组软raid
  3. Hexo博客系统部署教程 - 最全面的Hexo部署方法,交给你了~
  4. 0x8002801D:库没有注册
  5. 再获殊荣丨酷雷曼斩获2021世界文旅产业博览会3项大奖
  6. 专业且优秀的配音软件,确定不进来看看?
  7. Nacos - 配置管理中心(阿里开源)
  8. oracle牙间刷,60支OraCleen智能牙刷送送送!
  9. 2021-09-30打气泵芯片CSU18P88开发充气泵方案
  10. IT职场人生系列之六:员工的公司观