micropython lvgl xpt2046的校准程序

话说xpt2046 这个触控屏实在是太老了 但是也太经典了
2023年了 还拿个笔在电阻屏上戳戳戳。。。
没办法 哪里都有XPT2046这货
不废话了 上代码 好好看 好好学

# import libraries
import time
from machine import Pin
import espidf as esp
import lvgl as lv
from ili9XXX import ili9341, LANDSCAPE
from xpt2046 import xpt2046
import esp32
from micropython import const
import _thread
import machine

lv.init()

# init display
disp = ili9341(
    miso=12,
    mosi=13,
    clk=14,
    cs=15, dc=23,
    rst=25, backlight=-1,
    power=-1,
    width=320,
    height=240,
    rot=LANDSCAPE
)


HRES = lv.scr_act().get_disp().driver.hor_res
VRES = lv.scr_act().get_disp().driver.ver_res


# touch calibrations stored in NVRAM
class TouchCalibration(object):

    def __init__(self):
        self._config = esp32.NVS('touch_cal')

        try:
            self._x0 = self._config.get_i32('x0')
        except OSError:
            self._x0 = 0

        try:
            self._y0 = self._config.get_i32('y0')
        except OSError:
            self._y0 = 0

        try:
            self._x1 = self._config.get_i32('x1')
        except OSError:
            self._x1 = HRES

        try:
            self._y1 = self._config.get_i32('y1')
        except OSError:
            self._y1 = VRES

        self._is_dirty = False

    def save(self):
        if self._is_dirty:
            self._config.commit()
            self._is_dirty = False

    @property
    def x0(self):
        return self._x0

    @x0.setter
    def x0(self, value):
        self._x0 = value
        self._config.set_i32('x0', value)
        self._is_dirty = True

    @property
    def y0(self):
        return self._y0

    @y0.setter
    def y0(self, value):
        self._y0 = value
        self._config.set_i32('y0', value)
        self._is_dirty = True

    @property
    def x1(self):
        return self._x1

    @x1.setter
    def x1(self, value):
        self._x1 = value
        self._config.set_i32('x1', value)
        self._is_dirty = True

    @property
    def y1(self):
        return self._y1

    @y1.setter
    def y1(self, value):
        self._y1 = value
        self._config.set_i32('y1', value)
        self._is_dirty = True

    @property
    def is_calibrated(self):
        return not (
            self.x0 == 0 and
            self.y0 == 0 and
            self.x1 == HRES and
            self.y1 == VRES
        )


touch_calibration = TouchCalibration()

# use same SPI as display, init touch
touch = xpt2046(
    spihost=esp.HSPI_HOST,
    cs=26,
    transpose=False,
    cal_x0=touch_calibration.x0,
    cal_x1=touch_calibration.x1,
    cal_y0=touch_calibration.y0,
    cal_y1=touch_calibration.y1
)

# enable backlight
backlight = Pin(2, Pin.OUT)
backlight.value(1)


def main():

    def event_handler(evt):
        code = evt.get_code()

        if code == lv.EVENT.CLICKED:
            print("Clicked event seen")
        elif code == lv.EVENT.VALUE_CHANGED:
            print("Value changed seen")

    # create a simple button
    btn1 = lv.btn(lv.scr_act())

    # attach the callback
    btn1.add_event_cb(event_handler, lv.EVENT.ALL, None)

    btn1.align(lv.ALIGN.CENTER, 0, -40)
    label = lv.label(btn1)
    label.set_text("Button")

    # create a toggle button
    btn2 = lv.btn(lv.scr_act())

    # attach the callback
    # btn2.add_event_cb(event_handler,lv.EVENT.VALUE_CHANGED,None)
    btn2.add_event_cb(event_handler, lv.EVENT.ALL, None)

    btn2.align(lv.ALIGN.CENTER, 0, 40)
    btn2.add_flag(lv.obj.FLAG.CHECKABLE)
    # btn2.set_height(lv.SIZE_CONTENT)

    label = lv.label(btn2)
    label.set_text("Toggle")
    label.center()


if touch_calibration.is_calibrated:
    main()
else:
    # Run calibration
    class Tpcal_point:

        def __init__(self, x, y, name):
            self.display_coordinates = lv.point_t({'x': x, 'y': y})
            self.touch_coordinate = None
            self.name = name

        def __repr__(self):
            return "%s: (%d, %d)" % (
                self.name,
                self.touch_coordinate.x,
                self.touch_coordinate.y
            )


    CIRCLE_SIZE = const(20)
    CIRCLE_OFFSET = const(20)
    TP_MAX_VALUE = const(10000)
    LV_COORD_MAX = const((1 << (8 * 2 - 1)) - 1000)
    LV_RADIUS_CIRCLE = const(LV_COORD_MAX)


    class Tpcal:

        def __init__(self, points, calibrate_func, touch_count=5):
            self.points = points
            self.calibrate = calibrate_func
            self.touch_count = touch_count

            # Storage point to calculate median
            self.med = [lv.point_t() for _ in range(0, self.touch_count)]

            self.cur_point = 0
            self.cur_touch = 0

            self.scr = lv.obj(None)
            self.scr.set_size(TP_MAX_VALUE, TP_MAX_VALUE)
            lv.scr_load(self.scr)

            # Create a big transparent button screen to receive clicks
            style_transp = lv.style_t()
            style_transp.init()
            style_transp.set_bg_opa(lv.OPA.TRANSP)
            self.big_btn = lv.btn(lv.scr_act())
            self.big_btn.set_size(TP_MAX_VALUE, TP_MAX_VALUE)
            self.big_btn.add_style(style_transp, lv.PART.MAIN)
            self.big_btn.add_style(style_transp, lv.PART.MAIN)

            self.big_btn.add_event_cb(
                self.calibrate_clicked,
                lv.EVENT.CLICKED,
                None
            )

            # Create the screen, circle and label

            self.label_main = lv.label(lv.scr_act())

            style_circ = lv.style_t()
            style_circ.init()
            style_circ.set_radius(LV_RADIUS_CIRCLE)

            self.circ_area = lv.obj(lv.scr_act())
            self.circ_area.set_size(CIRCLE_SIZE, CIRCLE_SIZE)
            self.circ_area.add_style(style_circ, lv.STATE.DEFAULT)
            self.circ_area.clear_flag(
                lv.obj.FLAG.CLICKABLE
            )

            self.show_circle()

        def show_text(self, txt):
            self.label_main.set_text(txt)
            self.label_main.set_pos(
                (HRES - self.label_main.get_width()) // 2,
                (VRES - self.label_main.get_height()) // 2
            )

        def show_circle(self):
            point = self.points[self.cur_point]
            self.show_text(
                "Click the circle in\n" +
                point.name + "\n" +
                "%d left" % (self.touch_count - self.cur_touch)
            )

            if point.display_coordinates.x < 0:
                point.display_coordinates.x += HRES

            if point.display_coordinates.y < 0:
                point.display_coordinates.y += VRES

            self.circ_area.set_pos(
                point.display_coordinates.x - CIRCLE_SIZE // 2,
                point.display_coordinates.y - CIRCLE_SIZE // 2
            )

        def calibrate_clicked(self, event):
            point = self.points[self.cur_point]
            indev = lv.indev_get_act()
            indev.get_point(self.med[self.cur_touch])
            self.cur_touch += 1

            if self.cur_touch == self.touch_count:
                med_x = sorted([med.x for med in self.med])
                med_y = sorted([med.y for med in self.med])
                x = med_x[len(med_x) // 2]
                y = med_y[len(med_y) // 2]
                point.touch_coordinate = lv.point_t({'x': x, 'y': y})

                self.cur_point += 1
                self.cur_touch = 0

            if self.cur_point == len(self.points):
                self.calibrate(self.points)
                # letting the thread go so it is able to restart the ESP32
                self.show_text("Calibration Complete")
                t_lock.release()
                
                # self.big_btn.set_event_cb(
                #     self.check,
                #     lv.EVENT.PRESSING,
                #     None
                # )
            else:
                self.show_circle()

        def check(self, event):
            point = lv.point_t()
            indev = lv.indev_get_act()
            indev.get_point(point)
            self.circ_area.set_pos(
                point.x - CIRCLE_SIZE // 2,
                point.y - CIRCLE_SIZE // 2
            )

    # Calculate calibration, and calibrate

    def calibrate(points):
        visual_width = (
                points[1].display_coordinates.x -
                points[0].display_coordinates.x
        )
        visual_height = (
                points[1].display_coordinates.y -
                points[0].display_coordinates.y
        )
        touch_width = points[1].touch_coordinate.x - points[
            0].touch_coordinate.x
        touch_height = points[1].touch_coordinate.y - points[
            0].touch_coordinate.y

        pixel_width = touch_width / visual_width
        pixel_height = touch_height / visual_height

        x0 = (
                points[0].touch_coordinate.x -
                points[0].display_coordinates.x *
                pixel_width
        )
        y0 = (
                points[0].touch_coordinate.y -
                points[0].display_coordinates.y *
                pixel_height
        )

        x1 = (
                points[1].touch_coordinate.x +
                (HRES - points[1].display_coordinates.x) *
                pixel_width
        )
        y1 = (
                points[1].touch_coordinate.y +
                (VRES - points[1].display_coordinates.y) *
                pixel_height
        )

        print(
            "Calibration result: x0=%d, y0=%d, x1=%d, y1=%d" %
            (round(x0), round(y0), round(x1), round(y1))
        )
        touch.calibrate(round(x0), round(y0), round(x1), round(y1))
        touch_calibration.x0 = int(round(x0))
        touch_calibration.y0 = int(round(y0))
        touch_calibration.x1 = int(round(x1))
        touch_calibration.y1 = int(round(y1))
        touch_calibration.save()

    t_lock = _thread.allocate_lock()

    def _run():
        t_lock.acquire()
        tpcal = Tpcal([Tpcal_point(20, 20, "upper left-hand corner"), Tpcal_point(-40, -40, "lower right-hand corner")], calibrate)
        # we do a second acquire to hold the thread from exiting. once the
        # calibration has finished the lock will be released and then the module
        # will get rebooted
        t_lock.acquire()
        # sleep for 3 seconds so the user can see the 
        # calibration complete message
        time.sleep_ms(3000)
        machine.reset()

    _thread.start_new_thread(_run, ())





转自GITHUB lvgl issue 原作者是谁我真不知道,反正不是我

猜你喜欢

转载自blog.csdn.net/jd3096/article/details/129458887