一、目的

        这一节我们学习如何使用我们的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)

十五、最后

        不对的地方大家评论区留言。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐