一、目的
这一节我们学习如何使用我们的ESP32开发板来控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程:控件显示。
二、环境
ESP32 + ILI9341 3.2寸TFT-LCD触摸屏+ Thonny IDE + 几根杜邦线
接线方法:见前面文章。
三、滑杆代码
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948) # 触摸屏芯片型号xpt2046
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 创建滑块slider组件
self.slider = lv.slider(scr)
self.slider.set_width(180) # 设置滑块的长度
# self.slider.set_range(10, 50) # 默认值是0-100
self.slider.center() # 在窗口的中间位置
self.slider.add_event_cb(self.slider_event_cb, lv.EVENT.VALUE_CHANGED, None) # 添加事件的回调函数
# 创建一个标签label
self.label = lv.label(scr)
self.label.set_text("0") # 默认值
self.label.align_to(self.slider, lv.ALIGN.OUT_TOP_MID, 0, -15) # label的中间与滑块的上外边框中间对齐,然后y向上15像素 x不变
def slider_event_cb(self, evt):
slider = evt.get_target()
# 修改label的值
self.label.set_text(str(slider.get_value()))
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下键盘Ctrl+C键结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
这里告诉大家一个小技巧:我们除了按下Ctrl+C结束程序。还可以按开发板上EN按钮。
然后看到打印如下,此时开发板已经重启。
四、显示图片代码
我们先准备一张图片,从这个网站下载你需要的图片:
https://www.iconfont.cn/iconfont-国内功能很强大且图标内容很丰富的矢量图标库,提供矢量图标下载、在线存储、格式转换等功能。阿里巴巴体验团队倾力打造,设计和前端开发的便捷工具https://www.iconfont.cn/ 我下载的是这个图片,下载时选择png下载
然后下载到开发板上
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# Create an image from the png file
try:
with open('./music.png', 'rb') as f:
png_data = f.read()
except:
print("找不到图片文件...")
sys.exit()
img = lv.img_dsc_t({"data_size": len(png_data),"data": png_data})
# 创建样式
img_style = lv.style_t()
img_style.init()
# 设置背景颜色,圆角
img_style.set_radius(5)
img_style.set_bg_opa(lv.OPA.COVER)
img_style.set_bg_color(lv.palette_lighten(lv.PALETTE.GREY, 3))
# 设置边框以及颜色
img_style.set_border_width(2)
img_style.set_border_color(lv.palette_main(lv.PALETTE.BLUE))
# 创建lvgl中的图片组件
obj = lv.img(scr)
# 添加图片数据
obj.set_src(img)
# 添加样式
obj.add_style(img_style, 0)
# 将图片居中
obj.center()
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
我没运行成功,大家可以试一试,为什么?有知道的说一下:
五、划线代码
我们随便画个线:
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 创建 线 对象
obj_line = lv.line(scr)
# 创建样式
style = lv.style_t()
style.init()
style.set_line_color(lv.palette_main(lv.PALETTE.GREY))
style.set_line_width(6)
style.set_line_rounded(True)
# 添加样式
obj_line.add_style(style, 0)
point = [{"x": 10, "y": 30}, {"x": 30, "y": 50}, {"x": 100, "y": 0}, {"x": 200, "y": 30}]
obj_line.set_points(point, len(point))
obj_line.center()
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
六、圆弧代码
我们随便画个圆弧
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 创建圆弧对象
arc = lv.arc(scr)
# 设置角度
arc.set_end_angle(135) # 角度是 顺时针方向
# 设置宽高
arc.set_size(150, 150)
# 设置事件处理回调函数
arc.add_event_cb(self.event_cb, lv.EVENT.VALUE_CHANGED, None)
# 居中显示
arc.center()
# 创建文本
self.label = lv.label(scr)
self.label.set_text("0%") # 设置文字内容
# 居中显示
self.label.center()
def event_cb(self, evt):
arc = evt.get_target()
current_value = arc.get_value()
print()
self.label.set_text("%d%%" % current_value)
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
七、进度条代码
我们随便画个进度条
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 1. 创建进度条对象
self.bar = lv.bar(scr)
# 2. 创建样式对象
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_opa(lv.OPA.COVER)
style_indic.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_indic.set_bg_grad_color(lv.palette_main(lv.PALETTE.BLUE))
style_indic.set_bg_grad_dir(lv.GRAD_DIR.VER)
# 3. 给进度条设置样式
self.bar.add_style(style_indic, lv.PART.INDICATOR)
self.bar.set_size(20, 200)
self.bar.set_range(-20, 40)
# 4. 创建动画对象
anim_obj = lv.anim_t()
anim_obj.init()
anim_obj.set_var(self.bar)
anim_obj.set_values(-20, 40)
anim_obj.set_time(2000) # 设置从当前效果到指定效果的过度时间
anim.set_playback_time(2000) # 设置从指定效果到之前效果的过度时间
anim_obj.set_repeat_count(lv.ANIM_REPEAT_INFINITE) # 设置重复
anim_obj.set_custom_exec_cb(self.set_temp) # 设置动画回调函数
lv.anim_t.start(anim_obj)
# 5. 进度条放到中间
self.bar.center()
def set_temp(self, anim_obj, value):
self.bar.set_value(value, lv.ANIM.ON)
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
八、用进度条进行温度显示代码
开发板接上我们之前学的温度传感器。
物联网开发笔记(38)- 使用Micropython开发ESP32开发板之控制温度传感器(DS18B20)_魔都飘雪的博客-CSDN博客_micropython onewire使用Micropython开发ESP32开发板之控制温度传感器(DS18B20)https://blog.csdn.net/zhusongziye/article/details/127794068?spm=1001.2014.3001.5501温度传感器的信号角接在GPIO15上。
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 0. 获取温度
current_temp = self.get_temp()
text_temp = current_temp
if not current_temp:
current_temp = -20
text_temp = "Error"
# 1. 创建进度条对象
self.bar = lv.bar(scr)
# 2. 创建样式对象
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_opa(lv.OPA.COVER)
style_indic.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_indic.set_bg_grad_color(lv.palette_main(lv.PALETTE.BLUE))
style_indic.set_bg_grad_dir(lv.GRAD_DIR.VER)
# 3. 给进度条设置样式
self.bar.add_style(style_indic, lv.PART.INDICATOR)
self.bar.set_size(20, 200)
self.bar.set_range(-20, 60)
# 4. 创建动画对象
anim_obj = lv.anim_t()
anim_obj.init()
anim_obj.set_var(self.bar)
anim_obj.set_values(-20, current_temp)
anim_obj.set_time(2000) # 设置从当前效果到指定效果的过度时间
# anim_obj.set_playback_time(2000) # 设置从指定效果到之前效果的过度时间
# anim_obj.set_repeat_count(lv.ANIM_REPEAT_INFINITE) # 设置重复
anim_obj.set_custom_exec_cb(self.set_bar_temp) # 设置动画回调函数
lv.anim_t.start(anim_obj)
# 5. 进度条放到中间
self.bar.center()
# 6. 创建一个标签label
self.label = lv.label(scr)
self.label.set_text(str(text_temp)) # 默认值
self.label.align_to(self.bar, lv.ALIGN.OUT_BOTTOM_MID, 0, 5) # label的中间与滑块的上外边框中间对齐,然后y向下5像素 x不变
def set_bar_temp(self, anim_obj, value):
"""设置显示的温度信息"""
self.bar.set_value(value, lv.ANIM.ON)
def get_temp(self):
"""获取温度"""
ds_pin = Pin(15)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))
roms = ds_sensor.scan()
print('发现设备: %d个' % len(roms))
if roms:
ds_sensor.convert_temp()
for rom in roms:
temp = ds_sensor.read_temp(rom)
if isinstance(temp, float):
return int(temp)
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
九、仪表盘效果
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 1. 创建仪表盘对象
self.meter = lv.meter(scr)
self.meter.center() # 屏幕居中
self.meter.set_size(200, 200) # width: 200 height: 200
# 2. 创建刻度线对象
scale = self.meter.add_scale()
# -------- 子刻度线 --------
# 51:短线的个数
# 2:短线宽度(单位像素)
# 10:短线长度
# 最后1个参数:颜色
self.meter.set_scale_ticks(scale, 51, 2, 10, lv.palette_main(lv.PALETTE.GREY))
# -------- 主刻度线 --------
# 10: 多少个子刻度线显示1个主刻度线
# 4: 宽度
# 15: 长度
# 下一个参数:颜色
# 10: 文字与线的距离 10像素
self.meter.set_scale_major_ticks(scale, 10, 4, 15, lv.color_black(), 20)
# 3. 添加警示刻度线
# 在起点添加蓝色弧
blue_arc = self.meter.add_arc(scale, 2, lv.palette_main(lv.PALETTE.BLUE), 0)
self.meter.set_indicator_start_value(blue_arc, 0)
self.meter.set_indicator_end_value(blue_arc, 20)
# 在刻度开始处使刻度线为蓝色
blue_arc_scale = self.meter.add_scale_lines(scale, lv.palette_main(lv.PALETTE.BLUE), lv.palette_main(lv.PALETTE.BLUE), False, 0)
self.meter.set_indicator_start_value(blue_arc_scale, 0)
self.meter.set_indicator_end_value(blue_arc_scale, 20)
# 在末端添加红色弧
red_arc = self.meter.add_arc(scale, 2, lv.palette_main(lv.PALETTE.RED), 0)
self.meter.set_indicator_start_value(red_arc, 80)
self.meter.set_indicator_end_value(red_arc, 100)
# 使刻度线在刻度末端变为红色
red_arc_scale = self.meter.add_scale_lines(scale, lv.palette_main(lv.PALETTE.RED), lv.palette_main(lv.PALETTE.RED), False, 0)
self.meter.set_indicator_start_value(red_arc_scale, 80)
self.meter.set_indicator_end_value(red_arc_scale, 100)
# 4. 仪表指针
# 4: 宽度
# 下一参数:颜色
# -10:指针与刻度线距离
self.indic = self.meter.add_needle_line(scale, 4, lv.palette_main(lv.PALETTE.GREY), -10)
# 5. 创建动画对象
a = lv.anim_t()
a.init()
a.set_var(self.indic)
a.set_values(0, 100)
a.set_time(2000)
a.set_repeat_delay(100)
a.set_playback_time(500)
a.set_playback_delay(100)
a.set_repeat_count(lv.ANIM_REPEAT_INFINITE)
a.set_custom_exec_cb(self.set_value)
lv.anim_t.start(a)
def set_value(self, anmi_obj, value):
"""动画回调函数"""
self.meter.set_indicator_value(self.indic, value)
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
十、定时器效果
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 1. 创建仪表盘对象
self.meter = lv.meter(scr)
self.meter.center() # 屏幕居中
self.meter.set_size(200, 200) # width: 200 height: 200
# 2. 创建刻度线对象
scale = self.meter.add_scale()
# -------- 子刻度线 --------
# 51:短线的个数
# 2:短线宽度(单位像素)
# 10:短线长度
# 最后1个参数:颜色
self.meter.set_scale_ticks(scale, 51, 2, 10, lv.palette_main(lv.PALETTE.GREY))
# -------- 主刻度线 --------
# 10: 多少个子刻度线显示1个主刻度线
# 4: 宽度
# 15: 长度
# 下一个参数:颜色
# 10: 文字与线的距离 10像素
self.meter.set_scale_major_ticks(scale, 10, 4, 15, lv.color_black(), 10)
# 3. 添加警示刻度线
# 在起点添加蓝色弧
blue_arc = self.meter.add_arc(scale, 2, lv.palette_main(lv.PALETTE.BLUE), 0)
self.meter.set_indicator_start_value(blue_arc, 0)
self.meter.set_indicator_end_value(blue_arc, 20)
# 在刻度开始处使刻度线为蓝色
blue_arc_scale = self.meter.add_scale_lines(scale, lv.palette_main(lv.PALETTE.BLUE), lv.palette_main(lv.PALETTE.BLUE), False, 0)
self.meter.set_indicator_start_value(blue_arc_scale, 0)
self.meter.set_indicator_end_value(blue_arc_scale, 20)
# 在末端添加红色弧
red_arc = self.meter.add_arc(scale, 2, lv.palette_main(lv.PALETTE.RED), 0)
self.meter.set_indicator_start_value(red_arc, 80)
self.meter.set_indicator_end_value(red_arc, 100)
# 使刻度线在刻度末端变为红色
red_arc_scale = self.meter.add_scale_lines(scale, lv.palette_main(lv.PALETTE.RED), lv.palette_main(lv.PALETTE.RED), False, 0)
self.meter.set_indicator_start_value(red_arc_scale, 80)
self.meter.set_indicator_end_value(red_arc_scale, 100)
# 4. 仪表指针
# 4: 宽度
# 下一参数:颜色
# -10:指针与刻度线距离
self.indic = self.meter.add_needle_line(scale, 4, lv.palette_main(lv.PALETTE.GREY), -10)
# 5. 创建动画对象
a = lv.anim_t()
a.init()
a.set_var(self.indic)
a.set_values(0, 100)
a.set_time(2000)
a.set_repeat_delay(100)
a.set_playback_time(500)
a.set_playback_delay(100)
a.set_repeat_count(lv.ANIM_REPEAT_INFINITE)
a.set_custom_exec_cb(self.set_value)
lv.anim_t.start(a)
# 6. 添加定时器
lv.timer_create(self.timer_cb, 1000, None)
def set_value(self, anmi_obj, value):
"""动画回调函数"""
self.meter.set_indicator_value(self.indic, value)
def timer_cb(self, timer):
"""定时器回调函数"""
print("定时器....") # 这里会被1秒钟执行1次,重复执行
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
十一、实时温度效果
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 1. 创建仪表盘对象
self.meter = lv.meter(scr)
self.meter.center() # 屏幕居中
self.meter.set_size(200, 200) # width: 200 height: 200
# 2. 创建刻度线对象
scale = self.meter.add_scale()
# -------- 子刻度线 --------
# 51:短线的个数
# 2:短线宽度(单位像素)
# 10:短线长度
# 最后1个参数:颜色
self.meter.set_scale_ticks(scale, 51, 2, 10, lv.palette_main(lv.PALETTE.GREY))
# -------- 主刻度线 --------
# 10: 多少个子刻度线显示1个主刻度线
# 4: 宽度
# 15: 长度
# 下一个参数:颜色
# 10: 文字与线的距离 10像素
self.meter.set_scale_major_ticks(scale, 10, 4, 15, lv.color_black(), 10)
# 3. 添加警示刻度线
# 在起点添加蓝色弧
blue_arc = self.meter.add_arc(scale, 2, lv.palette_main(lv.PALETTE.BLUE), 0)
self.meter.set_indicator_start_value(blue_arc, 0)
self.meter.set_indicator_end_value(blue_arc, 20)
# 在刻度开始处使刻度线为蓝色
blue_arc_scale = self.meter.add_scale_lines(scale, lv.palette_main(lv.PALETTE.BLUE), lv.palette_main(lv.PALETTE.BLUE), False, 0)
self.meter.set_indicator_start_value(blue_arc_scale, 0)
self.meter.set_indicator_end_value(blue_arc_scale, 20)
# 在末端添加红色弧
red_arc = self.meter.add_arc(scale, 2, lv.palette_main(lv.PALETTE.RED), 0)
self.meter.set_indicator_start_value(red_arc, 80)
self.meter.set_indicator_end_value(red_arc, 100)
# 使刻度线在刻度末端变为红色
red_arc_scale = self.meter.add_scale_lines(scale, lv.palette_main(lv.PALETTE.RED), lv.palette_main(lv.PALETTE.RED), False, 0)
self.meter.set_indicator_start_value(red_arc_scale, 80)
self.meter.set_indicator_end_value(red_arc_scale, 100)
# 4. 仪表指针
# 4: 宽度
# 下一参数:颜色
# -10:指针与刻度线距离
self.indic = self.meter.add_needle_line(scale, 4, lv.palette_main(lv.PALETTE.GREY), -10)
# 7. 初始化温度相关信息
ds_pin = Pin(15)
self.ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))
self.roms = self.ds_sensor.scan()
print('发现设备: %d个' % len(self.roms))
# 5. 创建动画对象
a = lv.anim_t()
a.init()
a.set_var(self.indic)
temp = self.timer_cb()
a.set_values(0, temp)
a.set_time(500)
# a.set_repeat_delay(100)
# a.set_playback_time(500)
# a.set_playback_delay(100)
# a.set_repeat_count(lv.ANIM_REPEAT_INFINITE)
a.set_custom_exec_cb(self.set_value)
lv.anim_t.start(a)
# 6. 添加定时器
lv.timer_create(self.timer_cb, 1000, None) # 1000毫秒
def set_value(self, anmi_obj, value):
"""动画回调函数"""
self.meter.set_indicator_value(self.indic, value)
def timer_cb(self, timer=None):
"""定时器回调函数"""
if self.roms:
self.ds_sensor.convert_temp()
for rom in self.roms:
temp = self.ds_sensor.read_temp(rom)
if isinstance(temp, float):
ret = int(temp)
print("当前温度:", ret)
self.meter.set_indicator_value(self.indic, ret)
return ret
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
# ------------------------------ 看门狗,用来重启ESP32设备 --start------------------------
try:
from machine import WDT
wdt = WDT(timeout=1000) # enable it with a timeout of 2s
print("提示: 按下Ctrl+C结束程序")
while True:
wdt.feed()
time.sleep(0.9)
except KeyboardInterrupt as ret:
print("程序停止运行,ESP32已经重启...")
time.sleep(10)
# ------------------------------ 看门狗,用来重启ESP32设备 --stop-------------------------
十二、数字键盘效果
蜂鸣器的信号角接GPIO15
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 创建文本框
ta = lv.textarea(scr)
ta.set_one_line(True) # 设置为1行模式
ta.set_size(120, 50) # 设置宽高
ta.align(lv.ALIGN.TOP_MID, 0, 20) # 设置位置
ta.add_event_cb(lambda e: self.textarea_event_handler(e, ta), lv.EVENT.READY, None) # 添加回调函数
ta.add_state(lv.STATE.FOCUSED) # 设置光标
# 定义数字键盘要显示的内容
btnm_map = ["1", "2", "3", "\n",
"4", "5", "6", "\n",
"7", "8", "9", "\n",
lv.SYMBOL.BACKSPACE, "0", lv.SYMBOL.NEW_LINE, ""]
# 按钮矩阵
btnm = lv.btnmatrix(scr)
btnm.set_size(220, 220) # 设置宽高
btnm.align(lv.ALIGN.BOTTOM_MID, 0, -10) # 设置位置
btnm.add_event_cb(lambda e: self.btnm_event_handler(e, ta), lv.EVENT.VALUE_CHANGED, None)
btnm.clear_flag(lv.obj.FLAG.CLICK_FOCUSABLE) # 设置为非活跃,即文本框中的光标一直聚焦
btnm.set_map(btnm_map) # 设置要显示的内容(数字键盘)
# 设置有源蜂鸣器引脚
self.p15 = Pin(15, Pin.OUT)
self.p15.value(1) # 不响
def textarea_event_handler(self, e, ta):
print("按下了回车键,当前的文本框内容是: " + ta.get_text())
def btnm_event_handler(self, e, ta):
obj = e.get_target()
txt = obj.get_btn_text(obj.get_selected_btn()) # 获取被点击的按钮的内容,例如数字3
if txt == lv.SYMBOL.BACKSPACE: # 如果是退格键,那么就删除1个字符
ta.del_char()
elif txt == lv.SYMBOL.NEW_LINE: # 如果是回车键,那么就触发事件
lv.event_send(ta, lv.EVENT.READY, None)
elif txt:
ta.add_text(txt) # 如果不是回车键,那么就将当前数字显示到文本框
# 让蜂鸣器响1声
self.p15.value(0)
time.sleep(0.2)
self.p15.value(1) # 不响
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
十三、密码锁
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 创建文本框
ta = lv.textarea(scr)
ta.set_one_line(True) # 设置为1行模式
ta.set_size(120, 50) # 设置宽高
ta.align(lv.ALIGN.TOP_MID, 0, 20) # 设置位置
ta.add_event_cb(lambda e: self.textarea_event_handler(e, ta), lv.EVENT.READY, None) # 添加回调函数
ta.add_state(lv.STATE.FOCUSED) # 设置光标
# 定义数字键盘要显示的内容
btnm_map = ["1", "2", "3", "\n",
"4", "5", "6", "\n",
"7", "8", "9", "\n",
lv.SYMBOL.BACKSPACE, "0", lv.SYMBOL.NEW_LINE, ""]
# 按钮矩阵
btnm = lv.btnmatrix(scr)
btnm.set_size(220, 220) # 设置宽高
btnm.align(lv.ALIGN.BOTTOM_MID, 0, -10) # 设置位置
btnm.add_event_cb(lambda e: self.btnm_event_handler(e, ta), lv.EVENT.VALUE_CHANGED, None)
btnm.clear_flag(lv.obj.FLAG.CLICK_FOCUSABLE) # 设置为非活跃,即文本框中的光标一直聚焦
btnm.set_map(btnm_map) # 设置要显示的内容(数字键盘)
# 设置有源蜂鸣器引脚
self.p15 = Pin(15, Pin.OUT)
self.p15.value(1) # 不响
# 设置锁相关引脚
self.p12 = Pin(12, Pin.OUT)
self.p13 = Pin(13, Pin.OUT)
self.p12.value(0)
self.p13.value(0)
def textarea_event_handler(self, e, ta):
number = ta.get_text()
print("按下了回车键,当前的文本框内容是: " + number)
if number == "123123":
mbox1 = lv.msgbox(scr, "Success", "Welcome", [], True)
mbox1.center()
self.p12.value(0)
self.p13.value(1)
else:
mbox1 = lv.msgbox(scr, "Error", "Password error", [], True)
mbox1.center()
self.p12.value(1)
self.p13.value(0)
def btnm_event_handler(self, e, ta):
obj = e.get_target()
txt = obj.get_btn_text(obj.get_selected_btn()) # 获取被点击的按钮的内容,例如数字3
if txt == lv.SYMBOL.BACKSPACE: # 如果是退格键,那么就删除1个字符
ta.del_char()
elif txt == lv.SYMBOL.NEW_LINE: # 如果是回车键,那么就触发事件
lv.event_send(ta, lv.EVENT.READY, None)
elif txt:
ta.add_text(txt) # 如果不是回车键,那么就将当前数字显示到文本框
# 让蜂鸣器响1声
self.p15.value(0)
time.sleep(0.2)
self.p15.value(1) # 不响
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
十四、控制LED开关
import lvgl as lv
import time
from espidf import VSPI_HOST
from ili9XXX import ili9341
from xpt2046 import xpt2046
import fs_driver
from machine import Pin
import onewire, ds18x20
# ------------------------------ 屏幕初始化操作 --start------------------------
# 屏幕宽高
WIDTH = 240
HEIGHT = 320
# 创建显示屏对象
disp = ili9341(miso=19, mosi=23, clk=18, cs=5, dc=26, rst=27, power=14, backlight=-1, backlight_on=0, power_on=0, rot=0x80,
spihost=VSPI_HOST, mhz=60, factor=16, hybrid=True, width=WIDTH, height=HEIGHT,
invert=False, double_buffer=True, half_duplex=False, initialize=True)
# 创建触摸屏对象
touch = xpt2046(cs=25, spihost=VSPI_HOST, mosi=-1, miso=-1, clk=-1, cal_y0 = 423, cal_y1=3948)
# ------------------------------ 屏幕初始化操作 --stop------------------------
# 1. 创建显示screen对象。将需要显示的组件添加到这个screen才能显示
scr = lv.obj() # scr====> screen 屏幕
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
scr = lv.scr_act()
scr.clean()
# 2. 封装要显示的组件
class MyWidget():
def __init__(self, scr):
# 创建开关按钮
btn = lv.btn(lv.scr_act())
# 添加回调函数
btn.add_event_cb(self.open_or_close_led, lv.EVENT.ALL, None)
# 简单布局
btn.align(lv.ALIGN.CENTER, 0, 40)
btn.add_flag(lv.obj.FLAG.CHECKABLE)
btn.set_height(lv.SIZE_CONTENT)
# 创建label
self.label = lv.label(btn)
self.label.set_text("Open LED")
self.label.center()
# 创建LED对应引脚对象
self.led = Pin(2, Pin.OUT)
self.led.value(0) # 默认不亮
# 定义变量用来存储led的亮灭状态
self.led_status = False
def open_or_close_led(self, evt):
code = evt.get_code()
if code == lv.EVENT.CLICKED:
print("Clicked event seen")
elif code == lv.EVENT.VALUE_CHANGED:
print("Value changed seen")
if self.led_status is False:
self.led.value(1)
self.label.set_text("Close LED")
else:
self.led.value(0)
self.label.set_text("Open LED")
self.led_status = not self.led_status
# 3. 创建要显示的组件
MyWidget(scr)
# 4. 显示screen对象中的内容
lv.scr_load(scr)
十五、最后
不对的地方大家评论区留言。