【MicroPython + 读取SD卡存储的图片并显示到TFT屏幕】

必备

话说 ESP32 ————— ESP32官方文档
esp32
,
,
,

绪论

【 ESP32读取SD卡图片并放映到TFT显示屏 】

本章:结合Python库函数,实现ESP-WROOM-32 芯片通过SPI通信,将SD卡 存储的图片显示在TFT-ST7735S彩色显示屏 上。
① 、 ESP32有两种使用SD卡的方法,一种是使用SPI接口访问SD卡,另一种是使用SDMMC接口访问SD卡 。

,
,

1、设备、软件与库函数源

1.1 所用到的设备

  1. ESP-WROOM-32 芯片;
  2. SD卡模块 + 存储卡;
  3. TFT - ST7735S显示屏 128X160;
  4. 面包板+杜邦线若干
  5. 电脑、Type-C数据线······☺☺

1.2 所用到的软件

  1. Thonny

1.3 库函数

  1. SD卡驱动库:
    驱动函数: sdcard.py

    1. Github上的源码:sdcard.py
  2. TFT-ST7735S显示屏库:
    驱动函数: ST7735.py

    1. Github上的源码:ST7735.py
    2. 字体文件
  3. 本章源码

    1. 我的分享:点击获取实验的 Python 程序源码

注意: 与GitHub上下载的源码不同,本章涉及到两个从机设备(SD卡、TFT屏),同时用到两个 SPI协议。 因此,相关引脚的对接有所改动,请参考源码,或者文章论述。



2、实验一、读写SD卡、挂载目录

能够对TF存储卡的根目录、子目录的任意文件(.txt)读写;
还能将存储卡的目录挂在到MicroPython设备目录中。

2.1、接线

ESP32引脚SD卡引脚简诉
D14CS片选信号
D17SCK时钟
D15MOSISPI 主机输出 从机接受
D13MISOSPI 主机接受 从机输出
VNVCC本模块应接5V
GNDGND地管教

第一

2.2 文件操作指令:

1

2

3

2.2-1. 打开文件:
open(filename, mode,encoding): 打开指定路径的文件
filename为文件名,<相对路径或绝对路径+文件名+格式>
mode为打开模式('r’为只读,'w’为写入,'a’为追加,'r+'读写,'w+'读写,'a+'追加读写 等)。
encoding为打开文件编码格式

2.2-2、读取文件:
read(size)读取指定数量的数据。
readline()读取一行数据。
readlines()读取所有行数据并返回一个列表。

2.2-3、写入文件:
write(data)写入数据到文件。
writelines(lines)将列表中的所有行写入文件。

2.2-4、文件操作:
seek(offset, whence)移动文件指针到指定位置。
tell()返回当前文件指针位置。
flush()刷新文件缓冲区。

(1、f.seek(offset, whence)
	offset参数用于指定需要移动的偏移量,可以是正数、负数或零。具体含义如下:
		当offset为正数时,表示从当前位置向文件尾移动的偏移量。
		当offset为负数时,表示从当前位置向文件头移动的偏移量。
		当offset为零时,表示从文件头移动到指定位置。
	whence参数用于指定offset的起始位置,可以接受三个常量:
		0:表示起始位置为文件头。
		1:表示起始位置为当前位置。
		2:表示起始位置为文件尾。
(2、f.tell()
	返回当前文件指针的位置,(按字节计算)
	中文大部分占用3 字节
(3、f.flush()
	flush()方法可以手动地将缓冲区中的数据写入到磁盘文件中,
	从而避免缓冲区满了才写入的问题,同时也可以确保文件的实时性

2.2-5. 关闭文件:
close()关闭当前操作的文件。

例1: fb=open("/sd/test.txt",mode="r",encoding="utf-8")
	  ct = fb.read()
      print(ct)
      fb.close()
      
		当然,如果怕会忘记了使用 close() ,也可以换一种操作打开文件:
	【 with open(文件地址)as 函数名: 】
		这样就不需要你手动调用fb.close(),自动帮你关闭文件。
		
例2: with open("/sdtest.txt",mode="r",encoding="utf-8") as fb:
		ct = fb.read()
    	print(ct)

,
,

2.3、上传

11111

,

2.3、读写SD卡文件

运行程序 (一)SDmain.py

注意!仔细审核 程序和实际 中 SPI接线, 不要接错了

import time
import os, sdcard, machine
from machine import SPI
from machine import Pin

def Time_is():
    Ntime = time.localtime(time.time())           #获得本地日期(元组)
    str_time = "%s-%s-%s %s:%s:%s" % (Ntime[0],Ntime[1],Ntime[2],
    								Ntime[3],Ntime[4],Ntime[5],) #转换字符串并按格式保存
    return str_time

SD_CS = Pin(14)`在这里插入代码片`
SD_sck = Pin(17)
SD_mosi = Pin(15)
SD_miso = Pin(13)
sd = sdcard.SDCard(SPI(2, sck=SD_sck, mosi=SD_mosi, miso=SD_miso), SD_CS)

def sdtest_1():
    os.mount(sd,"/sd")
    print(os.listdir("/sd"))

    file_name="/sd/Notifications/text.txt"        #操作的文件路径
    message = "/sd/Notifications/mymsg.txt"   #文件路径

    w_txt="大家好,人生苦短,我选Python和MicroPython"
    f=open(file_name,"w")  #打开文件,进行写操作
    print(f.write(w_txt))  #写入
    f.close()  #关闭文件

    f=open(file_name)  #打开文件,进行读操作
    r_txt=f.read()
    print(r_txt)
    f.close()  #关闭文件
    
    a_txt = ",是的,这是追加写入的内容!\r\n当然,如果你想要更多,请输入:" 
    f=open(file_name,"a")  #打开文件,进行读操作
    f.write(a_txt)
    f.write("%s" % Time_is())
    f.close()  #关闭文件
    
    f=open(file_name,"r")  #打开文件,进行读操作
    r_linetxt=f.readline()  #读一行
    print(r_linetxt)
    f.close()  #关闭文件
    
    f=open(file_name,"r+")  #打开文件,进行读操作
    print(f"********第一次读取前的指针位置:{f.tell()}")
    r_stxt_1=f.read(4)   #读取前 8 个  (指针也指到这儿【中文占 3 字节,英文占 1 字节】)
    print(r_stxt_1)
    print(f"******写前的指针位置:{f.tell()}")
    f.write(r_stxt_1)
    print(f"******写后的指针位置:{f.tell()}")
    r_stxt_2 = f.read()
    print(f"******第二次读取后的指针位置:{f.tell()}")
    print(r_stxt_2)
    f.seek(-17,1)  #指针从当前位置,往后偏移17位
    print(f"******偏移后的指针位置:{f.tell()}")
    print(f.read())
    
    f.close()  #关闭文件
    
    f=open(file_name,"r")  #打开文件,进行读操作
    r_alltxt=f.read()
    print("******最后重新打开文件读取完整的内容:\n"+r_alltxt)
    f.close()  #关闭文件
    
    
if __name__ == '__main__':
    sdtest_1()

运行结果 (一)

j1

2.4 挂载SD卡目录

112

运行程序 (二)mount_sd.py

from machine import Pin,SPI
from sdcard import SDCard
import time,os,esp
 
cs = Pin(14,Pin.OUT)
spi = SPI(2,sck = Pin(17),mosi = Pin(15),miso = Pin(13))
sd = SDCard(spi,cs)
 
 #挂载SD到MicroPython设备目录
def mount_sd():
    os.VfsFat(sd)
    os.mount(sd,"/sd")  # 挂载SD卡
    dirs=os.listdir('/sd')
    fb = os.statvfs('/sd')
    print("SD capacity  = %d B %d M"%(fb[0] * fb[2],fb[0] * fb[2]/1024/1024))
    print("SD Remaining = %d B %d M"%(fb[0] * fb[3],fb[0] * fb[3]/1024/1024))
    print(dirs)
    print("esp32 Flash容量: %d M"%(esp.flash_size()/1024/1024))

#检测SD卡
def test_sd():
    vfs = os.VfsFat(sd)
    os.mount(vfs, "/fc")

    line = "abcdefghijklmnopqrstuvwxyz\n"
    lines = line * 200  # 5400 chars
    short = "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 block
        print(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 = True
    if result1 == "".join((lines, short, lines)):
        print("Large file Pass")
    else:
        print("Large file Fail")
        success = False
    if result2 == short:
        print("Small file Pass")
    else:
        print("Small file Fail")
        success = False
    print()
    print("Tests", "passed" if success else "failed")

if __name__ == "__main__":
    mount_sd()
    test_sd()

运行结果 (二)
j2

再者, 对MicroPython设备区刷新一下,你就能看到SD卡的目录了:

3

,
,



3、实验二,驱动ST7735S显示屏

3.1 有关 TFT 显示屏的

3.2 接线

ESP32引脚ST7735引脚简诉
D18SLKSIP时钟线
D21SDASPI数据线 ( mosi )
D23RST复位
D16DC数据/命令选择
D5CS片选信号
BLK留空背光控制开关
3V3VCC2.8V~3.3V
GNDGND地管教

3.3 上传

在这里插入图片描述

程序运行 (三)tftbmp.py

注意!仔细审核 程序和实际 中 SPI接线, 不要接错了

from ST7735 import TFT,TFTColor
from machine import SPI,Pin

spi_TFT = SPI(2, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(21))
tft=TFT(spi_TFT,16,23,5)    # DC,REA,CS
tft.initr()
tft.rgb(True)
tft.fill(TFT.BLACK)

f=open('test128x160.bmp', 'rb')
if f.read(2) == b'BM':  #header
    dummy = f.read(8) #file size(4), creator bytes(4)
    offset = int.from_bytes(f.read(4), 'little')
    hdrsize = int.from_bytes(f.read(4), 'little')
    width = int.from_bytes(f.read(4), 'little')
    height = int.from_bytes(f.read(4), 'little')
    if int.from_bytes(f.read(2), 'little') == 1: #planes must be 1
        depth = int.from_bytes(f.read(2), 'little')
        if depth == 24 and int.from_bytes(f.read(4), 'little') == 0:#compress method == uncompressed
            print("Image size:", width, "x", height)
            rowsize = (width * 3 + 3) & ~3
            if height < 0:
                height = -height
                flip = False
            else:
                flip = True
            w, h = width, height
            if w > 128: w = 128
            if h > 160: h = 160
            tft._setwindowloc((0,0),(w - 1,h - 1))
            for row in range(h):
                if flip:
                    pos = offset + (height - 1 - row) * rowsize
                else:
                    pos = offset + row * rowsize
                if f.tell() != pos:
                    dummy = f.seek(pos)
                for col in range(w):
                    bgr = f.read(3)
                    tft._pushcolor(TFTColor(bgr[2],bgr[1],bgr[0]))
spi_TFT.deinit()

运行结果 (三)

j3

得到:
my3

,
,
,
,
,
,

4、实验三、 读取存储卡中的图片到FT7735S显示屏

4.1接线

就是结合 2.1 和3.1 的接线
要保证与程序路线一致!

4.2 上传

首先,将 下载的资源中文件夹 pictures 里的5个照片 都 复制到 SD卡根目录下 Pictures 里,(注意目录的字母大小写)

  1. 方法1
    通过USB读卡器,插入电脑复制粘贴所有图片到目标位置;

  2. 方法2
    直接通过Thonny上传图片到目录 /sd/Pictures 。
    (前提是已经通过“实验一”将SD卡目录挂载上去,在【MicroPython设备】中点击并打开进入SD目录到 /sd/Pictures,随后在【此电脑】找到图片并上传)
    这也是挂载SD卡目录的好处之一吧,避开插拔USB读卡器上传图片。

其次,上传库函数到设备:
41

4.2 综合读写SD卡和TFT屏幕显示

运行程序 (四) main.py

import os, esp, time
from machine import Pin,SPI
from sdcard import SDCard
from ST7735 import TFT,TFTColor

#####################配置SD卡的SPI通信,调用SD卡相关库函数###############
SD_cs = Pin(14,Pin.OUT)
spi_SD = SPI(1,sck = Pin(17),mosi = Pin(15),miso = Pin(13))
sd = SDCard(spi_SD,SD_cs)
os.VfsFat(sd)
os.mount(sd,"/sd")  # 挂载SD卡

#####################配置TFT7735s显示屏的SPI通信,调用TFT相关库函数###############
spi_TFT = SPI(2, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(21))
tft=TFT(spi_TFT,16,23,5)    # DC,REA,CS
tft.initr()                #初始化红色选项版本
tft.rgb(True)                #RGB/BGR 格式  (反转颜色设置)
tft.fill(TFT.BLACK)   #用给定的颜色填充屏幕


#.bmp格式的一些照片路径:(第一个是单片机内存的bmp图片,后面的都是SD卡目录的BMP图片)
path = ['test128x160.bmp', '/sd/Pictures/test1.bmp', '/sd/Pictures/test2.bmp', '/sd/Pictures/test3.bmp', '/sd/Pictures/test4.bmp', '/sd/Pictures/jpg1.jpg']


def send_picture(Photo_path):
    with open(Photo_path, 'rb') as f:
        if f.read(2) == b'BM':    #header
            dummy = f.read(8)    #file size(4), creator bytes(4)
            offset = int.from_bytes(f.read(4), 'little')
            hdrsize = int.from_bytes(f.read(4), 'little')
            width = int.from_bytes(f.read(4), 'little')
            height = int.from_bytes(f.read(4), 'little')
            if int.from_bytes(f.read(2), 'little') == 1:       #planes must be 1
                depth = int.from_bytes(f.read(2), 'little')
                if depth == 24 and int.from_bytes(f.read(4), 'little') == 0:    #compress method == uncompressed 压缩方法 == 未压缩
                    print("Image size:", width, "x", height)
                    rowsize = (width * 3 + 3) & ~3
                    if height < 0:
                        height = -height
                        flip = False
                    else:
                        flip = True
                    w, h = width, height
                    if w > 128: w = 128
                    if h > 160: h = 160
                    
                    tft._setwindowloc((0,0),(w - 1,h - 1))     # 设置绘制颜色的矩形区域(起始坐标,终点坐标)¥¥¥¥¥¥¥¥¥¥¥
                    for row in range(h):
                        if flip:
                            pos = offset + (height - 1 - row) * rowsize
                        else:
                            pos = offset + row * rowsize
                        if f.tell() != pos:                 #读图片文件的当前指针位置
                            dummy = f.seek(pos)      #就 将当前指针位置 设置为 pos,且赋值给 dummy
                        for col in range(w):
                            bgr = f.read(3)                 #每次读取图片文件中的 3 字节
                            tft._pushcolor(TFTColor(bgr[2],bgr[1],bgr[0]))     #向设备推送读取到的颜色
#         spi.deinit()


def TFT_show():
    for i in range(1,len(path),1):
        print(f'第{i}张图片:',end='')
        send_picture(path[i])
    

def Time_is():
    Ntime = time.localtime(time.time())           #获得本地日期(元组)
    str_time = "%s-%s-%s %s:%s:%s" % (Ntime[0],Ntime[1],Ntime[2],Ntime[3],Ntime[4],Ntime[5],)     #转换字符串并按格式保存
    return str_time


def sdlog_1():
    file_name="/sd/runniglog.txt"        #日志文件路径
    
    w_txt = "欢迎来到SD卡存储空间!————%s \n" % Time_is()     #欢迎词+日期
    f=open(file_name,"a")   #打开文件,进行追加写入操作
    print(f.write(w_txt))  #写入
    f.close()  #关闭文件

    with open(file_name,"r", encoding="uft-8") as f:   #打开文件,进行只读操作
        r_txt=f.read()
        print("获取到记录内容:\n"+r_txt)
    
    
def mount_sd():
    dirs=os.listdir('/sd')
    fb = os.statvfs('/sd')
    print("SD capacity  = %d B %d M"%(fb[0] * fb[2],fb[0] * fb[2]/1024/1024))
    print("SD Remaining = %d B %d M"%(fb[0] * fb[3],fb[0] * fb[3]/1024/1024))
    print(dirs)
    print("esp32 Flash容量: %d M"%(esp.flash_size()/1024/1024))

    
if __name__ == '__main__':
    sdlog_1()
    mount_sd()
    TFT_show()

运行结果 (四)

叫

读取存储卡换图效果(视频):

ESP32读取SD卡图片,播放于ST7735S彩屏

告诉:

1、microPython不能显示中文文件名和路径名
2、

链接

1、什么是SPI协议
2、SPI 协议,看这一篇就够了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值