本文原创自微信公众号【PY学习笔记】,经用户王传福进行加工,共同完成了该文章。
我们对两位创作者的辛勤付出和无限创意深表感激,他们的共同努力令本文焕发更加耀眼的光芒。特此向两位创作者表达我们诚挚的谢意,感谢他们对生态的珍贵贡献,以及他们通过开源分享促进了分享文化的精神。
原著链接:
前言
TIP
您是否曾梦想打造属于自己的智能监控系统?或者想象着制作一个能够远程传送实时图像的遥控器?又或是希望拥有一款实用的随身小相机,记录生活中的美妙瞬间?实现这一切,现在触手可及。
由立创·ESP32S3开发板设计的摄像头扩展板,集成了OV2640摄像头,具备读写SD卡的能力,并能够在屏幕上实时显示图像。利用MicroPython的便捷性,即使是编程新手也能轻松掌握,让您快速入门应用,走在实现创意项目的前沿。
功能丰富,发挥你的创意
- 硬件集成性:一个小巧的扩展板集成了OV2640摄像头、SD卡槽和显示屏接口,不仅易于连接,而且互操作性强。
- 软件支持:我们提供详尽的MicroPython教程,助您快速掌握图像处理和数据存取。
- 案例驱动的学习:透过实际可运行的项目案例,您可以接触到无线Web监控、图传遥控器和随身小相机的构建过程。
案例项目突破想象的边界
- 无线Web监控:构建一个安全监控系统或婴儿监护器,即使在外也能实时查看您家的情况。
- 图传遥控器:将传统的遥控器提升到新高度,实时传输图像数据,让您的遥控体验更加直观和精确。
- 随身小相机:忘掉沉重的摄影设备,用这个轻便的小相机捕捉和分享每一次的旅行和冒险。
友好的步骤指导,轻松掌握编程
我们的教程将带您走过每一个关键的步骤,从硬件的接线到软件的编程。无论您是MicroPython的初学者还是有经验的开发者,我们的逐步指导都能确保您顺利完成项目,同时留下扩展和深入学习的空间。
代码示例和视觉成果,激发您的实际操作
为了让您更直观地理解每一步的作用和结果,我们提供了详细的代码示例和成品项目的截图、视频。您可以实时看到每一行代码背后的意义和产出,让学习变得具有成就感。
1. 硬件设计
1.1 器件选型
1.1.1 摄像头
摄像头采用的是OV2640,它是一款受欢迎的低成本CMOS摄像头传感器,由OmniVision Technologies生产。它是一款2百万像素的传感器,还有一款5640是500万像素。常用于嵌入式系统和小型摄像头项目中,如无人机、手机、网络摄像头和其他便携式设备。由于它的小尺寸和高集成度,OV2640特别适合于空间受限的设计。
OV2640能提供最高达1600x1200像素的分辨率,支持JPEG压缩输出,同样可以提供YUV422、YUV420和RGB565格式输出,这些功能使得它非常适应于多种图形接口和微控制器。它还具有自动曝光控制、自动增益控制、自动白平衡等功能,可以通过SCCB(Serial Camera Control Bus)接口进行配置,这是一种类似于I2C的通信协议。
OV2640的基本特性有:
- 图像传感器:1/4" CMOS 2MP
- 分辨率:最大1600x1200
- 照片格式:JPEG、YUV(422/420)、RGB565等
- 视角:可通过不同镜头获得(通常有标准、广角等选项)
- 接口:SCCB(控制)、DVP(数字视频端口)
- 特殊功能:自动曝光控制、自动增益控制及自动白平衡等
OV2640摄像头模块通常配备以下接口:
- SCCB接口,用于对摄像头设置进行控制。
- DVP接口,用于传输图像数据。
- 时钟输入(XCLK)。
- 电源输入(3.3V供电和地)。
- 复位信号(RESET)。
- 电源使能(PWDN,Power Down)。
OV2640摄像头的驱动电路,一般包含以下几个部分:
稳压电源 为了保证OV2640的稳定工作,一般需要提供多种的稳定电源,使用的时候可能会使用LDO(Low Dropout Regulator)线性稳压器来从大电压的电源(例如5V或更高)降至摄像头所需的3.3V,2.8V或者1.2V。
时钟源 摄像头模块需要一个高频时钟信号驱动其操作,这通常通过一个外部晶振(如12MHz或者更高)或者由主控驱动提供,这个时钟信号通常通过一个时钟产生电路供给摄像头模块的XCLK引脚。
接口电平匹配 如果主控制器(例如ESP32S3)的I/O电压不同于摄像头模块,则需要电平转换电路来确保两者之间的信号电平兼容,这样我们就可以安全地连接SCCB和DVP接口,而不会因为电压问题导致设备损坏。
写驱动程序时,需要初始化摄像头模块,配置传感器的寄存器,这涉及到设置分辨率、图像格式、帧速率以及其他摄像头特征。然后,你的程序需要通过DVP接口来接收帧数据,处理并显示或存储这些数据。
1.1.2 SD卡
SD卡(Secure Digital Card)是一种非常流行的存储介质,广泛用于便携式设备,如数码相机、手机、平板电脑、个人电脑以及嵌入式系统等。SD卡是基于闪存(flash memory)技术的,它具有较高的存储密度、固态耐用性和良好的数据稳定性。
SD卡通常支持三种通讯模式:一位串行模式(SD模式)、四位串行模式(4-bit SD模式)以及SPI模式。 在嵌入式应用中,尤其是在微控制器领域,SPI模式特别受欢迎,因为它接口简单,线路要求较少,对硬件的要求也不如SD模式高。
SPI协议控制的SD卡,需要以下几个信号线:
- CS (Chip Select) - 片选。通过这个信号,主设备可以选中或忽略SD卡,使之启用或禁用。
- MOSI (Master Out Slave In) - 主设备输出,SD卡输入。用于发送命令和数据到SD卡。
- MISO (Master In Slave Out) - 主设备输入,SD卡输出。SD卡通过这条线将数据发送回主设备。
- SCK (Serial Clock) - 串行时钟。用于同步数据的传输。
- VCC 供电电压。SD卡一般使用3.3V电源供电,但有些模块带有5V到3.3V的电压转换。
- GND 地线。
SD卡驱动电路的设计一般涉及以下几部分:
- 电源稳压:SD卡通常需要3.3V稳定供电。如果系统电源高于这个电压,如5V,那么就需要使用LDO或DC-DC转换器来降压。
- 电平转换:假如微控制器的I/O口为5V,而SD卡工作在3.3V电平,那么SPI通信线路(CS, MOSI, MISO, SCK)就需要电平转换电路,以避免对SD卡造成损害。
- 信号隔离:在某些工作环境中,为了防止信号干扰和电源噪声,可能要对信号线进行隔离处理。
驱动SD卡涉及的软件方面,程序需要通过SPI接口与SD卡通信,实现命令的发送和数据的读取。驱动程序必须能够初始化卡、识别其存储容量以及读写文件系统。
在MicroPython等高级编程环境中,通常有现成的库可以直接用来处理SD卡,如machine.SDcard模块,让开发者可以相对容易地集成SD卡读写功能。这些库提供了打开、读取、写入和关闭文件的方法,通常也支持文件系统操作,如创建和列出目录等。开发者只需通过几行代码,就可以实现文件在SD卡上的存储和检索。
在使用时,确保对应的SPI通讯引脚已经正确配置,并按照SD卡的通讯规范发送正确的命令,以保障数据的顺畅读写。
1.1.3 屏幕显示
在嵌入式系统中,常见的几款屏幕主要以液晶显示器(LCD)和有机发光二极管显示器(OLED)为主。不同类型的显示屏在技术参数、显示效果、功耗和成本等方面都有所差异。
我们选择的是2.4寸240x320像素的ST7789驱动的LCD屏幕。
购买链接:https://item.taobao.com/item.htm?_u=l2t4uge5dd15&id=758981467180&spm=a1z09.2.0.0.4fe32e8dFRJa8Y
现在,我们来详细介绍ST7789 TFT LCD。ST7789是一款常见的TFT液晶显示驱动芯片,由Sitronix Technology Corporation生产。它广泛应用于多种小型显示屏上,尤其是那些分辨率为320x240像素的2.4寸RGB屏幕。
ST7789显示屏的功能特点包括:
- 分辨率:ST7789控制器通常用于240x320(QVGA)分辨率的屏幕。
- 颜色深度:支持16-bit(65K色)和18-bit(262K色)模式。
- 尺寸:ST7789控制器常配备1.44寸、1.8寸和2.4寸等不同尺寸的屏幕。
- 接口:支持SPI接口,使其易于与各种微控制器连接。一些变体还可能支持并行接口。
在使用SPI协议通信的情况下,ST7789 屏幕需要连接以下信号线:
- SCL (Serial Clock) - SPI时钟线,控制数据传输的时序。
- SDA (Serial Data) - SPI数据线,用于发送数据到显示器,有的时候,数据线分为两条,分别为SDI (输入)和SDO(输出)。
- RS (Register Select) 或 DC (Data/Command) - 数据/命令控制线,用于区分发送的SPI数据是数据还是命令。
- CS (Chip Select) - 片选控制线,用于激活显示器的SPI通信。
- RST (Reset) - 用于硬件复位显示器的控制线。
- BLK (Backlight) - 背光控制线,用于打开或调整屏幕背光。
ST7789驱动电路的设计通常包括:
- 电源供应:屏幕需要3.3V的电源,应该使用稳压电路来确保稳定的电压供应,避免电压波动影响显示效果。
- 背光控制:根据具体需求,背光通常会有一个PWM调光电路,用于调节屏幕背光的亮度。有时候,靠简单的开关控制也可以打开或关闭背光。
- 复位电路:RST引脚可能需要接拉高或拉低电阻,以保证在启动时能正确复位显示器。
- 通信接口电路:确保SPI接口引脚的稳定连接。
软件上的驱动通常包括初始化显示屏、配置屏幕参数(比如分辨率、颜色模式),以及绘制像素、文字、图形等功能。在许多现代微控制器平台上,比如使用Arduino框架或者MicroPython,都可找到ST7789的库,这些库已经实现了与屏幕相关的基本控制函数。开发者只需简单配置屏幕参数和SPI通信设置,就可以通过调用相应的库函数来控制屏幕显示内容。
1.2 原理图设计
1.2.1 摄像头硬件外围电路
1.2.2 SD卡槽接口电路
1.2.3 LCD显示电路
1.3 PCB设计
【ProProject_摄像头扩展板_2024-04-12.epro】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
将以上.epro文件导入到嘉立创EDA专业版中,即可看到原理图与PCB。
2. 固件编译
2.1 环境搭建
2.1.1 基本环境搭建
使用VMware+Ubuntu22.04.3进行环境搭建,这两个的安装参考:
https://zhuanlan.zhihu.com/p/569274366
2.1.2 固件环境安装
安装依赖包
打开命令行,输入以下命令安装依赖包。
sudo apt-get install git wget libncurses-dev flex bison gperf python3 python3-pip python3-setuptools python3-serial python3-click python3-cryptography python3-future python3-pyparsing python3-pyelftools cmake ninja-build ccache libffi-dev libssl-dev python-is-python3
pip源配置
Esp-IDF安装过程中会在 python virtual environment 中使用 pip 安装所需的包,但默认情况下,pip 使用的是国外的官方源,使得安装非常慢。使用以下命令将pip源配置到阿里云。
pip config set global.index-url http://mirrors.aliyun.com/pypi/simple
pip config set global.trusted-host mirrors.aliyun.com
2
下载esp-idf与MicroPython
mkdir -p ~/esp
cd ~/esp
git clone https://gitee.com/EspressifSystems/esp-gitee-tools.git
git clone https://gitee.com/EspressifSystems/esp-idf.git
git clone https://github.com/micropython/micropython.git
2
3
4
5
如果git micropython失败,那使用下面的:
git clone https://gitee.com/yangyoulikedog/micropython.git
如果micropython实在下载不了,将下面文件复制到虚拟机的 ~/esp下解压,重新命名为 micropython。
【micropython-master.zip】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
确认MicroPython支持的esp-idf版本
进入micropython/ports/esp32/README.md中确认支持的版本号:
切换ESP-IDF的版本
cd esp-idf
git checkout v5.0.4
2
提示:HEAD 目前位于 5181de8ac5 versions: Update version to 5.0.4。 说明成功。
配置esp-idf
先更新子模块:要求执行以下命令不能有任何错误!!有错误就重新执行
git submodule update --init --recursive
如果使用上面的命令失败,提示:
那就先进行下一步。
官方为了解决国内开发者从 github 克隆 esp 相关仓库慢的问题,已将 esp-idf 和部分重要仓库及其关联的子模块镜像到了 jihu。根据官方建议,使用以下命令将仓库的URL替换为jihu的URL,并更新子模块,完成安装。
cd ~/esp/esp-gitee-tools
./jihu-mirror.sh set
./submodule-update.sh ~/esp/esp-idf/
./install.sh ~/esp/esp-idf/
2
3
4
可能会提示Python virtual environment未安装成功。按照建议执行以下命令,并重新安装。
sudo apt install python3.10-venv
./install.sh ~/esp/esp-idf/
2
安装一大堆东西后,提示:
All done! You can now run:
. /home/yle/esp/esp-idf/export.sh
2
表示安装成功。在命令行添加环境变量:
cd ~/esp/esp-idf
source export.sh
2
提示:idf.py build 说明成功。
注意 install.sh步骤只需要执行一次。每次新会话都需要使用export.sh。
2.2 固件编译
构建固件
在命令行中输入以下命令:
cd ~/esp/micropython
make -C mpy-cross
cd ports/esp32
make submodules
make
2
3
4
5
如果顺利的话,就会在~/esp/micropython/ ports/esp32/build-ESP32_GENERIC/中生成一个firmware.bin固件。但是通常在 make submodules 和 make 命令报错,这里需要确定micropython和esp-idf的版本要一致。不然就是这个命令:git submodule update --init --recursive 没有搞好。如果搞不好就将版本换一下。
git checkout v5.0.4,换成为另一半版本,比如之前看的可以是v5.1.2。
添加camera固件
2.2.1 下载idf环境的相机驱动
cd ~/esp/esp-idf/components
git clone https://github.com/espressif/esp32-camera
2
2.2.2 安装mciropython的相机驱动
cd ~/esp/esp-idf/components
git clone https://github.com/espressif/esp32-camera
2
如果 git clone https://github.com/lemariva/micropython-camera-driver
执行失败,那么下载下面这个文件:
【micropython-camera-driver-master.zip】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
将它解压在 ~/esp/micropython/ports/esp32 下:
在 ~/esp/micropython/examples/usercmodule/
下新建cam文件夹,将micropython-camera-driver/src
中的4个文件micropython.cmake、micropython.mk、modcamera.c、modecamera.h拷贝到cam文件夹中。
2.2.3 ST7789驱动安装
ST7789驱动为C语言的,只能通过编译固件才能使用。
先git下库:
git clone https://github.com/russhughes/st7789_mpy.git
如果下载失败,请下载下面的文件。
【st7789_mpy-master.zip】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
将st7789_mpy文件中的st7789文件夹整个放到usercmodules目录中:
~/esp/micropython/examples/usercmodules/
这次要将camera驱动、ST7789驱动同时编译成为固件,需要编辑uesrmodules文件夹的micropython.cmake文件,让两个驱动同时生效:
启动默认的8M的PSRAM。在下图的路径文件:
在 set SDKCONFIG_DEFAULTS 中, 增加 boards/sdkconfig.spiram_oct,结果如下:
2.2.4 编译ESP32-S3固件
esp-idf默认是编译ESP32的固件,要编译ESP32-S3的固件,需要修改Makefile文件。打开~/esp/micropython/ports/esp32下的Makefile文件,将12行的BOARD ?= ESP32_GENERIC改为BOARD ?= ESP32_GENERIC_S3
将camera模块添加进micropython
修改camera模块中的modcamera.c,删除24行的#if MODULE_CAMERA_ENABLED。
注意,是修改~/esp/micropython/examples/usercmodule/cam
路径下的文件!
删除最后一行的#endif,修改倒数第二行的MP_REGISTER_MODULE(MP_QSTR_camera, mp_module_camera_system, MODULE_CAMERA_ENABLED);为:
MP_REGISTER_MODULE(MP_QSTR_camera, mp_module_camera_system);
最后,编译固件:
编译成功结果:
这时就会在~/esp/micropython/ ports/esp32/build-ESP32_GENERIC_S3/
中生成一个firmware.bin固件。这个固件就是我们编译好的micropython固件。烧录地址为0x0。
2.3 固件烧录验证
2.3.1 固件烧录
固件的烧录请参考MicroPython入门手册的环境安装章节的1.2 烧录固件
: MicroPython入门手册
将固件换成为我们编译好的属于我们自己的固件,烧录地址为0x0。
如果大家的固件没有编译成功,可以使用以下固件。
【LCKFB_MicroPython_cam_st7789_8Mpsram_20240221.bin】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
2.3.2 固件验证
验证支持camera、st7789两个驱动,并支持SPIRAM和16M FLASH: 开发板连接上Thonny,在下方的命令台窗口输入以下代码:
import camera
import st7789
import micropython
import esp
micropython.mem_info()
esp.flash_size()/1024/1024
2
3
4
5
6
如果成功将会正常显示如下:
3. 屏幕显示
3.1 API介绍
屏幕初始化设置
st7789.ST7789(spi, width, height, dc, reset, cs, backlight, rotations, rotation, custom_init, color_order, inversion, options, buffer_size)
必需的位置参数:
- spiSPI器件
- width显示宽度
- height显示高度
必需的关键字参数:
- dc设置连接到显示数据/命令选择输入的引脚。 此参数始终是必需的。
可选关键字参数:
- reset设置连接到显示器硬件复位输入的引脚。如果 显示器复位引脚为高电平,参数未 必填。reset
- cs设置连接到显示器片选输入的引脚。如果 显示器的 CS 引脚低电平,显示器必须是唯一的设备 连接到 SPI 端口。显示将始终处于选中状态 device,并且该参数不是必需的。
- backlight将连接到显示器背光的引脚设置为使能 输入。显示器的背光输入通常可以保持悬空或 断开连接,因为某些显示器上的背光灯始终处于开机状态,并且 无法关闭。
- rotations设置方向表。方向表是一个列表 每个元组用于设置 MADCTL 寄存器、显示宽度、 显示高度、start_x和start_y值。rotation
以下 st7789 和 st7735 包含默认值 显示尺寸:rotations
您可以根据需要定义任意数量的旋转。
- rotation根据方向表设置显示旋转。默认方向表定义了 240x320、240x240、 134x240、128x160 和 128x128 显示器,LCD 的带状电缆位于显示屏底部。 默认旋转为纵向(0 度)。
- custom_init在 display init() 期间发送到显示器的显示配置命令列表。 该列表包含带有 bytes 对象的元组,可以选择后跟以 ms 为单位指定的延迟。第一个 bytes 对象的 byte 包含要发送的命令(可选),后跟数据字节。 请参阅文件或示例。
- color_order设置驱动程序 (st7789.RGB 或 st7789。BGR)
- inversion如果设置为 True,则设置显示颜色反转模式,如果为 False,则不显示颜色反转模式。
- options设置驱动程序选项标志。
- buffer_size如果未指定buffer_size,则动态分配 根据需要创建并释放缓冲区。如果设置了buffer_size,则必须 足够大以包含最大的位图、字体字符和 使用的解码JPG图像(行列2字节,RGB565中的16位颜色 表示法)。动态分配速度较慢,可能会导致堆碎片, 因此,应启用垃圾回收 (GC)。
屏幕初始化运行
- init()
必须调用才能初始化显示。
颜色翻转显示
inversion_mode(bool)
如果bool为 True,则设置显示颜色反转模式,如果bool 为 False,则不显示颜色反转模式。
查询屏幕宽高
width()
返回显示的当前逻辑宽度。(即 135x240 显示器 旋转 90 度是 240 像素宽)
height()
返回显示器的当前逻辑高度。(即 135x240 显示器 旋转 90 度是 135 像素高)
设置屏幕旋转
rotation(r)
设置逆时针方向旋转逻辑显示。 0-纵向(0 度)、1-横向(90 度)、2-反向纵向(180 度)、3 逆景观(270 度)
背光控制
on()
如果在初始化期间定义了背光引脚,将打开背光。
off()
如果在初始化期间定义了背光引脚,将关闭背光。
睡眠模式
sleep_mode(value)
如果 value 为 True,则使显示器进入睡眠模式,否则如果 value 为 False,则唤醒。在睡眠期间,可能无法保留显示内容。
全屏颜色填充
- fill(color)
用指定的颜色填充显示屏。颜色参考:
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define PURPLE 0x780F //紫色
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
#define LIGHTGREEN 0X841F //浅绿色
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
画点
- pixel(x, y, color)
将指定的像素显示位置设置为给定的color颜色
画线
line(x0, y0, x1, y1, color) 用提供的坐标起始点(x0,y0)到坐标结束点(x1,y1) 绘制一条color颜色的线。
hline(x, y, length, color)
用提供的坐标起始点(x,y)和 color颜色绘制一条length长度的水平线。此外,这是一个快速版本,具有较少的 SPI 调用。
- vline(x, y, length, color)
用提供的坐标起始点(x,y)和 color颜色绘制一条length长度的垂直线。
画矩形
- rect(x, y, width, height, color)
用提供的坐标起始点(x,y)绘制具有相应尺寸(width,height)的空心矩形。
- fill_rect(x, y, width, height, color)
用提供的坐标起始点(x,y)绘制具有相应尺寸(width,height)的填充矩形。
画圆
- circle(x, y, r, color)
以坐标点(x,y)作为圆心,绘制一个半径为r,color颜色的空心圆。
- fill_circle(x, y, r, color)
以坐标点(x,y)作为圆心,绘制一个半径为r,color颜色的填充圆。
显示字符串
- text(font, s, x, y[, fg, bg])
使用指定的位图将(整数、字符串或字节)写入显示,坐标作为文本的左上角。
- write(bitmap_font, s, x, y[, fg, bg, background_tuple, fill_flag])
使用指定的比例位图或等宽位图将文本写入显示器,坐标作为文本的左上角。
- write_len(bitap_font, s)
如果以指定的字体打印,则返回字符串的宽度(以像素为单位)。
- draw(vector_font, s, x, y[, fg, scale])
使用指定的 Hershey 矢量字体将文本绘制到显示屏上,并带有xy坐标作为文本的左下角。
- draw_len(vector_font, s[, scale])
如果使用指定的字体绘制,则返回字符串的宽度(以像素为单位)。
显示图片
- jpg(jpg, x, y [, method]) 在显示屏上绘制一个给定的坐标作为 图像的左上角。 可以是包含文件名的字符串 或包含 JPEG 图像数据的缓冲区。
解码和显示 JPG 所需的内存可能相当可观,因为全屏 320x240 JPG 至少需要 3100 字节的工作区域 + 320 * 240 * 2 用于缓冲映像的 RAM 字节。
- jpg_decode(jpg_filename [, x, y, width, height])
解码 jpg 文件并将其或其中的一部分作为元组返回,该元组由 (缓冲区、宽度、高度)。缓冲区是 color565 blit_buffer兼容字节 数组。缓冲区需要宽度 * 高度 2 字节的内存。
- png(png_filename, x, y [, mask])
在显示屏上绘制一个 PNG 文件,图像的左上角位于给定的坐标处。如果 PNG 无法完全安装在显示器上,它将被剪裁。这 PNG 将一次绘制一条线。由于驱动程序不包含帧缓冲区, 不支持透明度。
3.2 屏幕显示验证
注意,显示字符需要上传以下代码到开发板的内存中。
【vga1_16x16.py】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
运行以下示例代码:
import machine
from machine import SPI,Pin,UART,PWM,SoftSPI
import time,camera,sdcard,st7789,os
import vga1_16x16 as font
machine.freq(240000000) # 设置CPU的工作频率为 240 MHz
#spi初始化
spi=SPI(2,baudrate=40000000, sck=Pin(41), mosi=Pin(46), miso=Pin(48))
#创建一个屏幕对象,设置屏幕引脚与参数,并且关闭颜色翻转
tft=st7789.ST7789(spi, 240, 320, reset=Pin(15, Pin.OUT), dc=Pin(42, Pin.OUT), cs=Pin(45, Pin.OUT),inversion=False)
#屏幕初始化
tft.init()
#颜色测试
tft.fill(0xF800) #全屏刷新红色
time.sleep(0.5) #延时500ms
tft.fill(0x07E0) #全屏刷新绿色
time.sleep(0.5) #延时500ms
tft.fill(0x001F) #全屏刷新蓝色
time.sleep(0.5) #延时500ms
#画点测试
for i in range(100):
tft.pixel(i, i, 0xFFFF)#画白色点
time.sleep(1)
#画线测试
tft.line(20, 20, 200, 20, 0x0000)#画黑色线
time.sleep(1)
#画矩形测试
tft.rect(20, 30, 200, 20, 0xF800)#画红色空心矩形
tft.fill_rect(25, 35, 190, 10, 0xF800)#画红色填充矩形
time.sleep(1)
#画圆测试
tft.circle( int(240/2), int(320/2), 20, 0xFFE0)#画黄色空心圆
tft.fill_circle( int(240/2), int(320/2), 10, 0xFFE0)#画黄色填充圆
time.sleep(1)
#字符串显示测试
tft.text(font, b'hello', 100, 100)
time.sleep(1)
#屏幕旋转显示测试
tft.rotation(0)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
tft.rotation(1)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
tft.rotation(2)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
tft.rotation(3)
tft.fill(0xFFFF)
tft.text(font, b'hello', 100, 100)
time.sleep(1)
#图像显示测试(需要接入摄像头)
camera.deinit()
try:
camera.init(0, d0=21, d1=17, d2=18, d3=16, d4=40, d5=38, d6=1, d7=3,
format=camera.JPEG, framesize=camera.FRAME_QVGA,
fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=4, vsync=5, reset=-1, pwdn=-1,
sioc=6, siod=7, xclk=2, pclk=39)
except Exception as e:
camera.deinit()
camera.init(0, d0=21, d1=17, d2=18, d3=16, d4=40, d5=38, d6=1, d7=3,
format=camera.JPEG, framesize=camera.FRAME_QVGA,#320x240
#framesize=camera.FRAME_240X240,#240x240
fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=4, vsync=5, reset=-1, pwdn=-1,
sioc=6, siod=7, xclk=2, pclk=39)
while True:
tft.jpg(camera.capture(), 0, 0)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
验证结果:
4. SD卡读写
在MicroPython的源码中,有关于SD卡的操作源码。
从网站 https://github.com/micropython/micropython/tree/v1.19/drivers/sdcard 下载最新的Micropython关于sdcard的驱动代码。
如果无法进入网站,可以直接下载下面的这个文件。
【sdcard.py】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
将 sdcard.py 文件保存到ESP32S3开发板;(在Thonny中连接开发板,打开sdcard.py文件的对应路径,右键选择上传到/
,将文件上传到开发板中)
4.1 API介绍
SD卡初始化
- classmachine.SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None, freq=20000000)
此类使用专用 SD/MMC 接口硬件或通过 SPI 通道提供对 SD 或 MMC 存储卡的访问。该类实现了由 定义的块协议uos.AbstractBlockDev。
构造函数采用以下参数:
- slot选择要使用的可用接口。不设置此项将选择默认界面。我们通常将其改为SPI接口
- width选择 SD/MMC 接口的总线宽度。
- cd可用于指定卡检测引脚。
- wp可用于指定写保护引脚。
- sck可用于指定 SPI 时钟引脚。
- miso可用于指定 SPI miso 引脚。
- mosi可用于指定 SPI mosi 引脚。
- cs可用于指定 SPI 片选引脚。
- freq以 Hz 为单位选择 SD/MMC 接口频率(仅在 ESP32 上支持)。
在sdcard.py文件中,官方已经为我们配置好了,我们只需要配置引脚即可。
例如使用软件SPI配置SD卡的通信引脚:
sd = sdcard.SDCard(SoftSPI(2, sck=Pin(13), mosi=Pin(12), miso=Pin(14)), Pin(11))
SD卡挂载
- os.mount(fsobj, mount_point, *, readonly)
将文件系统对象fsobj挂载到mount_point字符串给定的路径中的位置 。 fsobj就是我们调用sdcard.SDCard()
后的对象。mount_point
可能是/
将fsobj挂载在根目录,也可能是挂载在根/< name >
目录下的子目录。
如果readonly参数为True,则文件系统以只读方式挂载。
在挂载过程中,该方法mount() 在文件系统对象上被调用。
OSError(EPERM) 如果mount_point已经安装,则会引发错误。
SD卡卸载
- uos.umount(mount_point)
卸载文件系统。mount_point可以是命名挂载位置的字符串,也可以是先前挂载的文件系统对象。在卸载过程中,该方法 umount()在文件系统对象上被调用。
如果未找到mount_point将引发OSError(EINVAL)。
在MicroPython中,基础的文件操作主要通过内置的open函数来实现,该函数可以打开指定路径的文件,并返回一个文件对象。然后,可以使用文件对象的方法来进行读取、写入和其他操作。
下面是常见的文件操作步骤:
打开文件
file = open('example.txt', 'r')
'r'代表读取模式
读取文件内容
content = file.read() #读取整个文件
line = file.readline() #读取一行
lines = file.readlines() #读取所有行并返回列表
2
3
写入文件内容
file = open('example.txt', 'w') #'w'代表写入模式,会覆盖原有内容
file.write('Hello, World!') #写入字符串到文件
2
追加内容到文件
file = open('example.txt', 'w') #'w'代表写入模式,会覆盖原有内容
file.write('Hello, World!') #写入字符串到文件
2
追加内容到文件
file = open('example.txt', 'a') #'a'代表追加模式
file.write('Hello, again!') #在文件末尾追加内容
2
关闭文件
file.close() #关闭文件,释放资源
还可以使用with语句来打开文件,这样可以保证文件在使用后会被正确关闭,即使在读取或写入时发生异常也是如此:
with open('example.txt', 'r') as file:
content = file.read() #文件在这个with代码块结束后会自动关闭
2
以上是基础的文件操作,后面的实际使用中还会涉及到文件的模式选择(如文本模式和二进制模式)、文件指针移动,以及对异常的处理等高级操作。
注意
每打开一个文件操作完成之后,必须执行关闭文件操作,否则之前的操作内容会失效,并且可能会导致文件异常无法打开等。
还有更多的文件操作请参考官方MicroPython文档:
http://www.micropython.com.cn/en/latet/library/uos.html#filesystem-mounting
4.2 SD卡读写验证
插入SD卡,运行以下代码
import sdcard
from machine import SoftSPI, Pin
import os,time
#SD卡初始化配置
sd = sdcard.SDCard(SoftSPI(2, sck=Pin(13), mosi=Pin(12), miso=Pin(14)), Pin(11))
#挂载SD卡
os.mount(sd, '/sd')
#打开example.txt文件并且写入,如果没有则创建该文件
file = open('/sd/example.txt', 'w') # 'w'代表写入模式,会覆盖原有内容
file.write('Hello, World!') # 写入字符串到文件
file.close() # 关闭文件,释放资源
#打开example.txt文件并且追加写入,如果没有则创建该文件
file = open('/sd/example.txt', 'a') # 'a'代表追加模式
file.write('Hello, again!') # 在文件末尾追加内容
file.close() # 关闭文件,释放资源
#打开example.txt文件并且追加写入,如果没有则创建该文件
file = open('/sd/example.txt', 'r') # 'r'代表读取模式
content = file.read() # 读取整个文件
print("content: " + content)
print('\n')
file.close() # 关闭文件,释放资源
file = open('/sd/example.txt', 'r') # 'r'代表读取模式
line = file.readline() # 读取一行
print("line: " + line)
print('\n')
file.close() # 关闭文件,释放资源
file = open('/sd/example.txt', 'r') # 'r'代表读取模式
lines = file.readlines() # 读取所有行并返回列表
# 遍历列表,打印每一行
print('lines:')
for line in lines:
print(line, end='') # 加上 end='' 参数来防止print自动添加额外的换行符
print('\n')
file.close() # 关闭文件,释放资源
# 先已读取模式打开一个文件
with open('/sd/example.txt', 'r') as file:
# 循环读取每一行
while True:
line = file.readline()
# 如果读取到文件末尾,则停止循环(line为''时)
if not line:
break
# 处理读取到的行
print(line.strip()) # 打印每行内容,使用strip()移除末尾的换行符
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
验证结果
Thonny命令台结果
SD卡中文件的结果:
5. 图像采集
5.1 API介绍
5.2 图像采集验证
6. 项目案例
6.1 无线Web监控
介绍
MicroPython 目前有两个 Web 框架:microWebSrv 和 microdot。由于 microWebSrv 不支持 ESP,所以,我们选择学习如何使用microdot。
microdot源码官方开源链接:
https://github.com/miguelgrinberg/microdot
Microdot 是一个受 Flask 启发的简约 Python Web 框架,被设计为轻量级的 Web 服务器,适用于资源受限的嵌入式设备,例如 ESP32,ESP8266。它只需要很少的 RAM 和存储空间,并且具有较低的 CPU 消耗.
你可以通过定义多个路由来处理不同的 URL 请求。每个路由由 URL 路径和相应的处理函数组成。当收到匹配的请求时,服务器将调用相应的处理函数。Microdot 还支持静态文件服务,可以轻松地将静态文件(如 HTML、CSS、JavaScript、图像等)提供给客户端。你只需要指定一个目录,服务器将自动处理静态文件的请求。集成了简单的模板引擎,使您可以轻松地生成动态的HTML响应。您可以在 HTML 文件中定义占位符,然后使用模板引擎将占位符替换为实际的值。
Microdot 支持 HTTP 的 GET 和 POST 请求。您可以通过定义相应的路由和处理函数来处理不同类型的请求。
下面是一个简单的介绍如何使用 Microdot:
首先,我们需要在 Microdot 的 GitHub 仓库下载对应的文件
microdot.pyopen in new window。
如果下载失败,则直接使用下方提供的.py文件。
【microdot.py】下载
📌 在 下载中心
->【入门手册资料】百度网盘链接
->第08章.【立创·ESP32S3R8N8】项目案例
->基于ESP32S3开发板的摄像头扩展板资料
中。
将其上传到开发板中即可。
源码
from microdot import Microdot
import time
import camera
import network
import machine
machine.freq(240000000) # 设置CPU的工作频率为 240 MHz
def connect():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('esp32s3正在联网...')
wlan.connect('ESP32S3_TEST', '12345678')
while not wlan.isconnected():
pass
print('网络信息为: ', wlan.ifconfig())
ifconfig = wlan.ifconfig()
print('请在浏览器打开:{}:5000'.format(ifconfig[0]))
connect()
app = Microdot()
# 初始化摄像头
for i in range(5):
cam = camera.init(0, d0=21, d1=17, d2=18, d3=16, d4=40, d5=38, d6=1, d7=3,
format=camera.JPEG, framesize=camera.FRAME_HVGA,#FRAME_HVGA,
fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=4, vsync=5, reset=-1, pwdn=-1,
sioc=6, siod=7, xclk=2, pclk=39)
print("摄像头是否成功初始化?: ", cam)
if cam:
print("是")
break
else:
time.sleep(2)
else:
print('超时')
reset()
@app.route('/')
def index(request):
return '''<!doctype html>
<html>
<head>
<title>ESP32S3网页图传</title>
<meta charset="UTF-8">
</head>
<body>
<h1>ESP32S3网页图传</h1>
<img src="/video_feed" width="30%">
</body>
</html>''', 200, {'Content-Type': 'text/html; charset=utf-8'}
@app.route('/video_feed')
def video_feed(request):
def stream():
yield b'--frame\r\n'
while True:
frame = camera.capture()
yield b'Content-Type: image/jpeg\r\n\r\n' + frame + \
b'\r\n--frame\r\n'
return stream(), 200, {'Content-Type':
'multipart/x-mixed-replace; boundary=frame'}
if __name__ == '__main__':
app.run(debug=True)
#camera.deinit()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
实验
编译器端显示
网页端显示
6.2 随身小相机
SD卡、屏幕和摄像头结合