搜索
bottom↓
回复: 0

《ESP32-S3使用指南—MicroPython版 V1.0》第二十九章 SD卡实验

[复制链接]

出0入234汤圆

发表于 3 小时前 | 显示全部楼层 |阅读模式
2.jpg
1)实验平台:正点原子ESP32S3开发板
2)购买链接:https://detail.tmall.com/item.htm?id=768499342659
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-347618-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学ESP32S3快速入门视频教程:https://www.bilibili.com/video/BV1sH4y1W7Tc
6)正点原子FPGA交流群:132780729
1.png
3.png

第二十九章 SD卡实验


       SD卡是最常见的小型可移动存储介质之一,它有多种尺寸和物理外形。MMC卡是类似的可移动存储设备,而eMMC设备是电气类似的存储设备,旨在嵌入其他系统。所有这三种形式共享一个通用协议来与它们的主机系统进行通信,并且高级支持对它们来说看起来都是一样的。因此,在MicroPython中,它们被抽象为一个名为machine.SDCard的对象。在本章中,我们将通过machine.SDCard对象来驱动这些存储设备。
       本章分为如下几个小节:
       29.1 SD卡操作模块
       29.2 硬件设计
       29.3 软件设计
       29.4 下载验证

       29.1 SD卡操作模块
       在MicroPython中,uos模块和machine.SDCard对象都与SD卡操作有关。uos模块提供了一些用于操作文件系统的函数,例如listdir(列出目录中的文件)、mkdir(创建目录)、chdir(切换当前工作目录)、getcwd(获取当前工作目录)、remove(删除文件)、rename(重命名文件或文件夹)、stat(获取文件或文件夹的状态信息)、chmod(改变文件或文件夹的权限)、utime(修改文件或文件夹的访问时间和修改时间)以及system(执行系统命令)。
       而machine.SDCard对象是MicroPython中用于表示SD卡的抽象对象。它提供了一组统一的API来与SD卡进行通信,包括初始化SD卡、获取SD卡信息、读取和写入块等操作。在使用MicroPython进行SD卡操作时,通常会结合使用uos模块和machine.SDCard对象。
       现在,作者将对这些模块的构造函数和对象的使用方法进行讲解。

       29.1.1 uos模块
       MicroPython的内置模块uos主要提供文件系统操作服务。该模块实现了CPython模块的一个子集,同时具有一些特殊的特点和限制。以下是其主要特点和应用场景,以及需要注意的事项。

       一、主要特点:

       1,提供基本的“操作系统”服务,如获取系统信息、生成随机数、更改或获取当前目录、列出或创建或删除或重命名文件或目录等。

       2,提供了文件系统访问和挂载的功能,例如在虚拟文件系统中挂载多个“真实”文件系统,或者使用不同类型的文件系统格式,如FAT、littlefs等。

       3,提供终端重定向和复制的功能,例如在给定的类似流对象上复制或切换MicroPython终端(REPL)。

       4,uos模块使用的文件系统操作语法是CPython os模块的一个子集,也是POSIX标准文件系统操作的一个子集。支持的函数和方法有:uname、urandom、chdir、getcwd、ilistdir、listdir、mkdir、remove、rmdir、rename、stat、statvfs、sync、mount、umount、dupterm等。不支持的有:chown、chmod、link、symlink等。

       二、应用场景:

       1,对文件系统进行管理和操作,例如创建或删除或修改文件或目录,或者获取文件或目录的属性或状态。

       2,对不同类型的存储设备进行访问和挂载,例如使用SD卡或SPI闪存等外部存储设备扩展内部存储空间,或者使用不同的文件系统格式适应不同的性能和兼容性需求。

       3,对终端进行重定向和复制,例如在不同的通信接口上使用MicroPython终端(REPL),或者在多个终端上同时输出或输入数据。

       三、需注意事项:

       1,uos模块的功能和性能可能因不同的端口而异,因此在开发可移植的MicroPython应用程序时,应该尽量避免依赖特定的文件系统操作语法或结果。

       2,uos模块在编译和执行文件系统操作时可能会消耗较多的内存和时间,因此在处理大量或复杂的文件或目录时,应该注意优化代码和资源管理。

       3,uos模块在编译和执行文件系统操作时可能会遇到无效或不合法的路径、参数、数据等,或者文件错误、权限错误、设备错误等异常情况。这些情况会引发OSError或ValueError异常,并给出错误信息。应该使用try-except语句来捕获并处理这些异常。

       下面我们打开Thonny软件,在Shell交互窗口下使用dir命令获取uos模块提供的函数,如下所示:
  1. >>> import machine, uos
  2. >>> dir(uos)
  3. ['__class__', '__name__', 'remove', 'VfsFat', 'VfsLfs2', '__dict__', 'chdir', 'dupterm', 'dupterm_notify', 'getcwd', 'ilistdir', 'listdir', 'mkdir', 'mount', 'rename', 'rmdir', 'stat', 'statvfs', 'sync', 'umount', 'uname', 'unlink', 'urandom']
  4. >>>
复制代码
       可以看到。MicroPython的uos模块提供了十几种方法(函数),这些方法足够我们去操作SD卡了。

       29.1.2 machine.SDCard对象
       machine.SDCard是一个用于表示SD卡的抽象对象,它提供了一组统一的API来访问和操作SD卡。通过使用machine.SDCard对象,开发人员可以轻松地读取和写入SD卡上块的地址、获取SD卡的容量和可用空间等操作。下面讲解的是SDCard对象的构造函数与方法。

       一、SDCard构造函数
       SDCard的构造对象方法如下:
  1. class machine.SDCard(slot=1, width=1, cd=None, wp=None, sck=None,
  2. miso=None, mosi=None, cs=None, freq=20000000)
  3. 使用示例:sd = machine.SDCard(slot=2,width=8,sck=12, miso=13, mosi=11, cs=2)
复制代码
       该构造方法的参数描述,如下表所示。

1.png
表29.1.1 machine.SDCard构造方法参数描述

       返回值:SDCard对象。
       上表的slot参数选择接口如下表所示。

2.png
表29.1.2 Slot端号分配

       从上表可知,如果我们使用SPI驱动SD卡,则选择2与3号端口。
       注意:正点原子ESP32-S3开发板的SD卡使用的是SPI协议进行通信,所以SD卡构造函数中,我们仅使用上表绿色的参数。

       二、SDCard类的方法
       打开Thonny软件,在Shell交互窗口下使用dir命令获取SDCard类的方法,如下所示:
  1. >>> import machine
  2. >>> dir(machine.SDCard)
  3. ['__class__', '__name__', '__bases__', '__del__', '__dict__', 'deinit', 'info', 'ioctl', 'readblocks', 'writeblocks']
  4. >>>
复制代码
       可以看到。通过使用machine.SDCard对象,开发人员可以轻松地读取和写入SD卡上块的地址、获取SD卡的容量和可用空间等操作。

       29.2 硬件设计

       1. 例程功能
       本章实验功能简介:系统打开SD卡根目录下的test.txt文件,然后在此文件下写入“Hello ALIENTEK”字符串数据,写入完成后读取此文件的内容,并输出至SPILCD显示屏上。

       2. 硬件资源

       1)XL9555
              IIC_INT-IO0(需在P5连接IO0)
              IIC_SDA-IO41
              IIC_SCL-IO42

       2)SPILCD
              CS-IO21
              SCK-IO12
              SDA-IO11
              DC-IO40(在P5端口,使用跳线帽将IO_SET和LCD_DC相连)
              PWR- IO1_3(XL9555)
              RST- IO1_2(XL9555)

       3)SD
              CS-IO2
              SCK-IO12
              MOSI-IO11
              MISO-IO13

       3. 原理图
       SD接口与ESP32-S3的连接关系,如下图所示:

第二十九章 SD卡实验3757.png
图29.2.1 SD接口与ESP32-S3的连接电路图

       29.3 软件设计

       29.3.1 程序流程图
       程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图。

第二十九章 SD卡实验3897.png
图29.3.1.1 程序流程图

       29.3.2 程序解析
       本书籍的代码都在main.py脚本下编写的,读者可在光盘资料下找到对应的源码。SD卡实验main.py源码如下:
  1. import machine, uos
  2. import time


  3. """
  4. * @brief       程序入口
  5. * @param       无
  6. * @retval      无
  7. """
  8. if  __name__ == '__main__':
  9.    
  10.     # Slot 2 uses pins sck = 12, cs = 2, miso = 13, mosi = 11
  11.     sd = machine.SDCard(slot=2,width=8,sck=12, miso = 13, mosi=11, cs=2)
  12.     # 重新当前系统文件目录
  13.     print('挂载SD前的系统目录:{}'.format(uos.listdir()))
  14.     # 使用uos.VfsFat类创建一个FAT文件系统对象
  15.     vfs = uos.VfsFat(sd)
  16.     # 挂在到SD/sd
  17.     uos.mount(vfs,'/sd')
  18.     # 重新查询系统文件目录
  19.     print('挂载SD后的系统目录:{}'.format(uos.listdir()))
  20.     # 打开test.txt文件,如果SD卡目录没有会重新创建test.txt文件
  21.     with open("/sd/test.txt", "w") as f:
  22.         for i in range(1, 50):
  23.             # 从这个文件写数据
  24.             f.write(str(i)+"\n")
  25.     # 从sd卡目录下读取test.txt文件内容
  26.     with open("/sd/test.txt", "r") as f:
  27.         # 打印读取的内容
  28.         print(f.read())
  29.     # 卸載SD卡  
  30.     uos.umount('/sd')
复制代码
       首先,我们需要实例化SD卡对象,并配置SPI协议通信和SPI管脚。然后,使用uos.VfsFat类创建一个FAT文件系统对象,并调用uos.mount方法挂载SD卡。接着,我们需要检查SD卡的挂载是否成功。如果挂载失败,系统目录将不显示SD卡目录。最后,我们需要打开SD卡根目录下的test.txt文件,在此文件下写入1到50的数字,写入完成后,读取此文件的内容,并在串口上输出读取的内容。
       在使用这种方法驱动SD卡的情况下,可能会引发一个问题,导致SPI LCD显示屏无法正常显示。问题的根源在于正点原子ESP32-S3开发板的SD卡与SPI LCD共享一个SPI接口。在这种情况下,MicroPython提供的machine_sdcard.c驱动并没有返回SPI控制块,这使得LCD驱动无法获取到SPI控制块以调用SPI收发函数发送相关的数据和命令。
       因此,为了实现SD卡与SPI LCD的兼容性,作者引用了别人的一个用于驱动SD卡Python脚本(SPI接口)。通过该脚本,可以在实例化SPI的情况下驱动SD卡和SPI LCD显示屏。下面是sdcard.py脚本的代码示例:
  1. from micropython import const
  2. import time


  3. _CMD_TIMEOUT = const(100)

  4. _R1_IDLE_STATE = const(1 << 0)
  5. # R1_ERASE_RESET = const(1 << 1)
  6. _R1_ILLEGAL_COMMAND = const(1 << 2)
  7. # R1_COM_CRC_ERROR = const(1 << 3)
  8. # R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
  9. # R1_ADDRESS_ERROR = const(1 << 5)
  10. # R1_PARAMETER_ERROR = const(1 << 6)
  11. _TOKEN_CMD25 = const(0xFC)
  12. _TOKEN_STOP_TRAN = const(0xFD)
  13. _TOKEN_DATA = const(0xFE)


  14. class SDCard:
  15.     def __init__(self, spi, cs, baudrate=20000000):
  16.         self.spi = spi
  17.         self.cs = cs

  18.         self.cmdbuf = bytearray(6)
  19.         self.dummybuf = bytearray(512)
  20.         self.tokenbuf = bytearray(1)
  21.         for i in range(512):
  22.             self.dummybuf = 0xFF
  23.         self.dummybuf_memoryview = memoryview(self.dummybuf)

  24.         # initialise the card
  25.         self.init_card(baudrate)

  26.     def init_spi(self, baudrate):
  27.         try:
  28.             master = self.spi.MASTER
  29.         except AttributeError:
  30.             # on ESP8266
  31.             self.spi.init(baudrate=baudrate, phase=0, polarity=0)
  32.         else:
  33.             # on pyboard
  34.             self.spi.init(master, baudrate=baudrate, phase=0, polarity=0)

  35.     def init_card(self, baudrate):

  36.         # init CS pin
  37.         self.cs.init(self.cs.OUT, value=1)

  38.         # init SPI bus; use low data rate for initialisation
  39.         self.init_spi(100000)

  40.         # clock card at least 100 cycles with cs high
  41.         for i in range(16):
  42.             self.spi.write(b"\xff")

  43.         # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
  44.         for _ in range(5):
  45.             if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
  46.                 break
  47.         else:
  48.             raise OSError("no SD card")

  49.         # CMD8: determine card version
  50.         r = self.cmd(8, 0x01AA, 0x87, 4)
  51.         if r == _R1_IDLE_STATE:
  52.             self.init_card_v2()
  53.         elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
  54.             self.init_card_v1()
  55.         else:
  56.             raise OSError("couldn't determine SD card version")

  57.         # get the number of sectors
  58.         # CMD9: response R2 (R1 byte + 16-byte block read)
  59.         if self.cmd(9, 0, 0, 0, False) != 0:
  60.             raise OSError("no response from SD card")
  61.         csd = bytearray(16)
  62.         self.readinto(csd)
  63.         if csd[0] & 0xC0 == 0x40:  # CSD version 2.0
  64.             self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024
  65.         elif csd[0] & 0xC0 == 0x00:  # CSD version 1.0 (old, <=2GB)
  66.             c_size = (csd[6] & 0b11) << 10 | csd[7] << 2 | csd[8] >> 6
  67.             c_size_mult = (csd[9] & 0b11) << 1 | csd[10] >> 7
  68.             read_bl_len = csd[5] & 0b1111
  69.             capacity = (c_size + 1) * (2 ** (c_size_mult + 2))
  70. * (2**read_bl_len)
  71.             self.sectors = capacity // 512
  72.         else:
  73.             raise OSError("SD card CSD format not supported")
  74.         # print('sectors', self.sectors)

  75.         # CMD16: set block length to 512 bytes
  76.         if self.cmd(16, 512, 0) != 0:
  77.             raise OSError("can't set 512 block size")

  78.         # set to high data rate now that it's initialised
  79.         self.init_spi(baudrate)

  80.     def init_card_v1(self):
  81.         for i in range(_CMD_TIMEOUT):
  82.             self.cmd(55, 0, 0)
  83.             if self.cmd(41, 0, 0) == 0:
  84.                 # SDSC card, uses byte addressing in read/write/erase commands
  85.                 self.cdv = 512
  86.                 # print("[SDCard] v1 card")
  87.                 return
  88.         raise OSError("timeout waiting for v1 card")

  89.     def init_card_v2(self):
  90.         for i in range(_CMD_TIMEOUT):
  91.             time.sleep_ms(50)
  92.             self.cmd(58, 0, 0, 4)
  93.             self.cmd(55, 0, 0)
  94.             if self.cmd(41, 0x40000000, 0) == 0:
  95. # 4-byte response, negative means keep the first byte
  96.                 self.cmd(58, 0, 0, -4)  
  97. # get first byte of response, which is OCR
  98.                 ocr = self.tokenbuf[0]  
  99.                 if not ocr & 0x40:
  100.                     self.cdv = 512
  101.                 else:
  102.                     self.cdv = 1
  103.                 # print("[SDCard] v2 card")
  104.                 return
  105.         raise OSError("timeout waiting for v2 card")

  106.     def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
  107.         self.cs(0)

  108.         # create and send the command
  109.         buf = self.cmdbuf
  110.         buf[0] = 0x40 | cmd
  111.         buf[1] = arg >> 24
  112.         buf[2] = arg >> 16
  113.         buf[3] = arg >> 8
  114.         buf[4] = arg
  115.         buf[5] = crc
  116.         self.spi.write(buf)

  117.         if skip1:
  118.             self.spi.readinto(self.tokenbuf, 0xFF)

  119.         # wait for the response (response[7] == 0)
  120.         for i in range(_CMD_TIMEOUT):
  121.             self.spi.readinto(self.tokenbuf, 0xFF)
  122.             response = self.tokenbuf[0]
  123.             if not (response & 0x80):
  124.                 if final < 0:
  125.                     self.spi.readinto(self.tokenbuf, 0xFF)
  126.                     final = -1 - final
  127.                 for j in range(final):
  128.                     self.spi.write(b"\xff")
  129.                 if release:
  130.                     self.cs(1)
  131.                     self.spi.write(b"\xff")
  132.                 return response

  133.         # timeout
  134.         self.cs(1)
  135.         self.spi.write(b"\xff")
  136.         return -1

  137.     def readinto(self, buf):
  138.         self.cs(0)

  139.         # read until start byte (0xff)
  140.         for i in range(_CMD_TIMEOUT):
  141.             self.spi.readinto(self.tokenbuf, 0xFF)
  142.             if self.tokenbuf[0] == _TOKEN_DATA:
  143.                 break
  144.             time.sleep_ms(1)
  145.         else:
  146.             self.cs(1)
  147.             raise OSError("timeout waiting for response")

  148.         # read data
  149.         mv = self.dummybuf_memoryview
  150.         if len(buf) != len(mv):
  151.             mv = mv[: len(buf)]
  152.         self.spi.write_readinto(mv, buf)

  153.         # read checksum
  154.         self.spi.write(b"\xff")
  155.         self.spi.write(b"\xff")

  156.         self.cs(1)
  157.         self.spi.write(b"\xff")

  158.     def write(self, token, buf):
  159.         self.cs(0)

  160.         # send: start of block, data, checksum
  161.         self.spi.read(1, token)
  162.         self.spi.write(buf)
  163.         self.spi.write(b"\xff")
  164.         self.spi.write(b"\xff")

  165.         # check the response
  166.         if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05:
  167.             self.cs(1)
  168.             self.spi.write(b"\xff")
  169.             return

  170.         # wait for write to finish
  171.         while self.spi.read(1, 0xFF)[0] == 0:
  172.             pass

  173.         self.cs(1)
  174.         self.spi.write(b"\xff")

  175.     def write_token(self, token):
  176.         self.cs(0)
  177.         self.spi.read(1, token)
  178.         self.spi.write(b"\xff")
  179.         # wait for write to finish
  180.         while self.spi.read(1, 0xFF)[0] == 0x00:
  181.             pass

  182.         self.cs(1)
  183.         self.spi.write(b"\xff")

  184.     def readblocks(self, block_num, buf):
  185.         nblocks = len(buf) // 512
  186.         assert nblocks and not len(buf) % 512, "Buffer length is invalid"
  187.         if nblocks == 1:
  188.             # CMD17: set read address for single block
  189.             if self.cmd(17, block_num * self.cdv, 0, release=False) != 0:
  190.                 # release the card
  191.                 self.cs(1)
  192.                 raise OSError(5)  # EIO
  193.             # receive the data and release card
  194.             self.readinto(buf)
  195.         else:
  196.             # CMD18: set read address for multiple blocks
  197.             if self.cmd(18, block_num * self.cdv, 0, release=False) != 0:
  198.                 # release the card
  199.                 self.cs(1)
  200.                 raise OSError(5)  # EIO
  201.             offset = 0
  202.             mv = memoryview(buf)
  203.             while nblocks:
  204.                 # receive the data and release card
  205.                 self.readinto(mv[offset : offset + 512])
  206.                 offset += 512
  207.                 nblocks -= 1
  208.             if self.cmd(12, 0, 0xFF, skip1=True):
  209.                 raise OSError(5)  # EIO

  210.     def writeblocks(self, block_num, buf):
  211.         nblocks, err = divmod(len(buf), 512)
  212.         assert nblocks and not err, "Buffer length is invalid"
  213.         if nblocks == 1:
  214.             # CMD24: set write address for single block
  215.             if self.cmd(24, block_num * self.cdv, 0) != 0:
  216.                 raise OSError(5)  # EIO

  217.             # send the data
  218.             self.write(_TOKEN_DATA, buf)
  219.         else:
  220.             # CMD25: set write address for first block
  221.             if self.cmd(25, block_num * self.cdv, 0) != 0:
  222.                 raise OSError(5)  # EIO
  223.             # send the data
  224.             offset = 0
  225.             mv = memoryview(buf)
  226.             while nblocks:
  227.                 self.write(_TOKEN_CMD25, mv[offset : offset + 512])
  228.                 offset += 512
  229.                 nblocks -= 1
  230.             self.write_token(_TOKEN_STOP_TRAN)

  231.     def ioctl(self, op, arg):
  232.         if op == 4:  # get number of blocks
  233.             return self.sectors
  234.         if op == 5:  # get block size in bytes
  235.             return 512
复制代码
       可以看到,这个脚本通过使用SD命令来实现对SD卡的读写操作。在脚本的构造函数中,需要传入三个参数来实例化SD卡对象,分别是SPI控制块、CS片选管脚以及SPI的速率。这些参数在实例化SD卡对象时是必需的。此外,值得注意的是,驱动SD卡的速率一般不能超过24M,相关内容可以参考SD卡数据手册。
       首先,作者在Thonny软件中新建了一个文本文件。然后,在此文本文件中粘贴了上述的SD卡驱动代码,并将其命名为sdcard.py文件。接着,将这个文件保存到了MicroPython设备中,如下图所示:

第二十九章 SD卡实验14315.png
图29.3.2.1 添加sdcard.py脚本

       在main.py脚本的测试代码,如下所示:
  1. from machine import Pin,SPI,I2C
  2. from sdcard import SDCard
  3. import atk_xl9555 as io_ex
  4. import atk_lcd as lcd
  5. import time
  6. import uos

  7. """
  8. * @brief       程序入口
  9. * @param       无
  10. * @retval      无
  11. """
  12. if __name__ == '__main__':
  13.    
  14.     x = 0
  15.     # IIC初始化
  16.     i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
  17.     # XL9555初始化
  18.     xl9555 = io_ex.init(i2c0)
  19.    
  20.     # 复位LCD
  21.     xl9555.write_bit(io_ex.SLCD_RST,0)
  22.     time.sleep_ms(100)
  23.     xl9555.write_bit(io_ex.SLCD_RST,1)
  24.     time.sleep_ms(100)
  25.    
  26.     # 初始化SPI
  27.     spi = SPI(2,baudrate = 20000000, sck = Pin(12), mosi=Pin(11), miso=Pin(13))
  28.     # 初始化LCD,lcd = 0为正点原子2.4寸屏幕;lcd = 1为正点原子1.3寸SPILCD屏幕;
  29. display = lcd.init(spi,dc = Pin(40,Pin.OUT,Pin.PULL_UP,value = 1),
  30. cs = Pin(21,Pin.OUT,Pin.PULL_UP,value = 1),dir = 1,lcd = 0)
  31.     # 打开背光
  32.     xl9555.write_bit(io_ex.SLCD_PWR,1)
  33.     time.sleep_ms(100)
  34.     sd = SDCard(spi,Pin(2,Pin.OUT))
  35.     # 实验信息
  36.     display.string(30, 50, 240, 32, 32, "ESP32-S3",lcd.RED)
  37.     display.string(30, 80, 240, 24, 24, "SD TEST",lcd.RED)
  38.     display.string(30, 110, 240, 16, 16, "ATOM@ALIENTEK",lcd.RED)
  39.     display.string(30, 130, 200, 16, 16, "File Read:", lcd.BLUE)
  40.     # 挂在到SD/sd
  41.     uos.mount(sd,'/sd')
  42.     # 重新查询系统文件目录
  43.     print('挂载SD后的系统目录:{}'.format(uos.listdir()))
  44.     with open("/sd/test.txt", "w") as f:
  45.             f.write(str("Hello ALIENTEK"))

  46.     # 从sd卡目录下读取hello.txt文件内容
  47.     with open("/sd/test.txt", "r") as f:
  48.         # 打印读取的内容
  49.         data = f.read()
  50.    
  51.     display.string(130, 130, 200, 16, 16, str(data), lcd.BLUE)
  52.     # 卸載SD卡  
  53.     uos.umount('/sd')
复制代码
       在上述源代码中,首先实例化了IIC、XL9555、SPI、LCD和SD卡对象。接着,系统显示了实验信息。随后,使用了uos模块的方法来挂载SD卡。最后,在SD卡的目录下创建了一个名为test.txt的文件,并将字符串数据“Hello ALIENTEK”写入该文件。同时,读取了该文件的内容,并将其显示在LCD显示屏上。

       29.4 下载验证
       程序下载到开发板后,可以看到SPILCD显示SD卡目录下的test.txt文件的内容,如下图所示。

第二十九章 SD卡实验16170.png
图30.4.1 RGBLCD显示效果图

阿莫论坛20周年了!感谢大家的支持与爱护!!

该献的血还是要献的。你不献他不献。难道让我去献? --- 出自坛友:lovejp1981
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-28 19:11

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表