#include "HTTPClient.h" #include "WiFi.h" #include "Wire.h" #include "XL9535_driver.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_rgb.h" #include "esp_lcd_panel_vendor.h" #include "factory_ui.h" #include "img.h" #include "lvgl.h" #include "pin_config.h" #include #include "OneButton.h" #define USING_2_1_INC_CST820 1 // Full circle 2.1 inches using CST820 touch screen #define TOUCH_MODULES_CST_SELF #include "TouchLib.h" TouchLib touch(Wire, IIC_SDA_PIN, IIC_SCL_PIN, CTS820_SLAVE_ADDRESS, TP_RES_PIN); typedef struct { uint8_t cmd; uint8_t data[16]; uint8_t databytes; // No of data in data; bit 7 = delay after set; 0xFF = end of cmds. } lcd_init_cmd_t; DRAM_ATTR static const lcd_init_cmd_t st_init_cmds[] = { {0xFF, {0x77, 0x01, 0x00, 0x00, 0x10}, 0x05}, {0xC0, {0x3b, 0x00}, 0x02}, {0xC1, {0x0b, 0x02}, 0x02}, {0xC2, {0x07, 0x02}, 0x02}, {0xCC, {0x10}, 0x01}, {0xCD, {0x08}, 0x01}, // 用565时屏蔽 666打开 {0xb0, {0x00, 0x11, 0x16, 0x0e, 0x11, 0x06, 0x05, 0x09, 0x08, 0x21, 0x06, 0x13, 0x10, 0x29, 0x31, 0x18}, 0x10}, {0xb1, {0x00, 0x11, 0x16, 0x0e, 0x11, 0x07, 0x05, 0x09, 0x09, 0x21, 0x05, 0x13, 0x11, 0x2a, 0x31, 0x18}, 0x10}, {0xFF, {0x77, 0x01, 0x00, 0x00, 0x11}, 0x05}, {0xb0, {0x6d}, 0x01}, {0xb1, {0x37}, 0x01}, {0xb2, {0x81}, 0x01}, {0xb3, {0x80}, 0x01}, {0xb5, {0x43}, 0x01}, {0xb7, {0x85}, 0x01}, {0xb8, {0x20}, 0x01}, {0xc1, {0x78}, 0x01}, {0xc2, {0x78}, 0x01}, {0xc3, {0x8c}, 0x01}, {0xd0, {0x88}, 0x01}, {0xe0, {0x00, 0x00, 0x02}, 0x03}, {0xe1, {0x03, 0xa0, 0x00, 0x00, 0x04, 0xa0, 0x00, 0x00, 0x00, 0x20, 0x20}, 0x0b}, {0xe2, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x0d}, {0xe3, {0x00, 0x00, 0x11, 0x00}, 0x04}, {0xe4, {0x22, 0x00}, 0x02}, {0xe5, {0x05, 0xec, 0xa0, 0xa0, 0x07, 0xee, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x10}, {0xe6, {0x00, 0x00, 0x11, 0x00}, 0x04}, {0xe7, {0x22, 0x00}, 0x02}, {0xe8, {0x06, 0xed, 0xa0, 0xa0, 0x08, 0xef, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x10}, {0xeb, {0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00}, 0x07}, {0xed, {0xff, 0xff, 0xff, 0xba, 0x0a, 0xbf, 0x45, 0xff, 0xff, 0x54, 0xfb, 0xa0, 0xab, 0xff, 0xff, 0xff}, 0x10}, {0xef, {0x10, 0x0d, 0x04, 0x08, 0x3f, 0x1f}, 0x06}, {0xFF, {0x77, 0x01, 0x00, 0x00, 0x13}, 0x05}, {0xef, {0x08}, 0x01}, {0xFF, {0x77, 0x01, 0x00, 0x00, 0x00}, 0x05}, {0x36, {0x08}, 0x01}, {0x3a, {0x66}, 0x01}, {0x11, {0x00}, 0x80}, {0x29, {0x00}, 0x80}, {0, {0}, 0xff} }; XL9535 xl; OneButton button(0, true); const int backlightPin = EXAMPLE_PIN_NUM_BK_LIGHT; bool click = false; bool lastStatus = false; TaskHandle_t pvCreatedTask; void deep_sleep(void); void tft_init(void); void lcd_cmd(const uint8_t cmd); void lcd_data(const uint8_t *data, int len); bool touchDevicesOnline = false; uint8_t touchAddress = 0; const char *getTouchAddr() { if (touchAddress == FT5x06_ADDR) { return "FT3267"; } else if (touchAddress == CST820_ADDR) { return "CST820"; } else if (touchAddress == GT911_ADDR) { return "GT911"; } #ifdef USING_2_1_INC_CST820 return "CST820"; #else return "UNKONW"; #endif } void scanDevices(void) { byte error, address; int nDevices = 0; Serial.println("Scanning for I2C devices ..."); for (address = 0x01; address < 0x7f; address++) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.printf("I2C device found at address 0x%02X\n", address); if (address == FT5x06_ADDR) { Serial.println("Find FT5X06 touch device!"); touchDevicesOnline = true; touchAddress = FT5x06_ADDR; } else if (address == CST820_ADDR) { Serial.println("Find CST820 touch device!"); touchDevicesOnline = true; touchAddress = CST820_ADDR; } else if (address == GT911_ADDR) { Serial.println("Find GT911 touch device!"); touchDevicesOnline = true; touchAddress = GT911_ADDR; } nDevices++; } else if (error != 2) { Serial.printf("Error %d at address 0x%02X\n", error, address); } } if (nDevices == 0) { Serial.println("No I2C devices found"); } } static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) { esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data; int offsetx1 = area->x1; int offsetx2 = area->x2; int offsety1 = area->y1; int offsety2 = area->y2; esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); lv_disp_flush_ready(drv); } static void lv_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) { static uint16_t lastX, lastY; touch_point_t p = {0}; if (touch.read()) { TP_Point t = touch.getPoint(0); data->point.x = p.x = t.x; data->point.y = p.y = t.y; data->state = LV_INDEV_STATE_PR; // Serial.println("t.x " + t.x); // Serial.println("t.y " + t.y); } else { data->state = LV_INDEV_STATE_REL; } lv_msg_send(MSG_TOUCH_UPDATE, &p); } void waitInterruptReady() { Serial.println("Click"); uint32_t timeout = millis() + 500; while (timeout > millis()) { while (!digitalRead(TP_INT_PIN)) { delay(20); timeout = millis() + 500; } } delay(10); } void setBrightness(uint8_t value) { static uint8_t level = 0; static uint8_t steps = 16; if (value == 0) { digitalWrite(backlightPin, 0); delay(3); level = 0; return; } if (level == 0) { digitalWrite(backlightPin, 1); level = steps; delayMicroseconds(30); } int from = steps - level; int to = steps - value; int num = (steps + to - from) % steps; for (int i = 0; i < num; i++) { digitalWrite(backlightPin, 0); digitalWrite(backlightPin, 1); } level = value; } void setup() { static lv_disp_draw_buf_t disp_buf; static lv_disp_drv_t disp_drv; static lv_indev_drv_t indev_drv; Serial.begin(115200); pinMode(BAT_VOLT_PIN, ANALOG); Wire.begin(IIC_SDA_PIN, IIC_SCL_PIN); xl.begin(); uint8_t pin = (1 << PWR_EN_PIN) | (1 << LCD_CS_PIN) | (1 << TP_RES_PIN) | (1 << LCD_SDA_PIN) | (1 << LCD_CLK_PIN) | (1 << LCD_RST_PIN) | (1 << SD_CS_PIN); xl.pinMode8(0, pin, OUTPUT); xl.digitalWrite(PWR_EN_PIN, HIGH); delay(100); xl.digitalWrite(TP_RES_PIN, LOW); delay(300); xl.digitalWrite(TP_RES_PIN, HIGH); delay(300); pinMode(TP_INT_PIN, INPUT); touch.init(); tft_init(); esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_rgb_panel_config_t panel_config = { .clk_src = LCD_CLK_SRC_PLL160M, .timings = { .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, .h_res = EXAMPLE_LCD_H_RES, .v_res = EXAMPLE_LCD_V_RES, // The following parameters should refer to LCD spec .hsync_pulse_width = 1, .hsync_back_porch = 30, .hsync_front_porch = 50, .vsync_pulse_width = 1, .vsync_back_porch = 30, .vsync_front_porch = 20, .flags = { .pclk_active_neg = 1, }, }, .data_width = 16, // RGB565 in parallel mode, thus 16bit in width .psram_trans_align = 64, .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC, .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC, .de_gpio_num = EXAMPLE_PIN_NUM_DE, .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK, .data_gpio_nums = { // EXAMPLE_PIN_NUM_DATA0, EXAMPLE_PIN_NUM_DATA13, EXAMPLE_PIN_NUM_DATA14, EXAMPLE_PIN_NUM_DATA15, EXAMPLE_PIN_NUM_DATA16, EXAMPLE_PIN_NUM_DATA17, EXAMPLE_PIN_NUM_DATA6, EXAMPLE_PIN_NUM_DATA7, EXAMPLE_PIN_NUM_DATA8, EXAMPLE_PIN_NUM_DATA9, EXAMPLE_PIN_NUM_DATA10, EXAMPLE_PIN_NUM_DATA11, EXAMPLE_PIN_NUM_DATA1, EXAMPLE_PIN_NUM_DATA2, EXAMPLE_PIN_NUM_DATA3, EXAMPLE_PIN_NUM_DATA4, EXAMPLE_PIN_NUM_DATA5, }, .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN, .on_frame_trans_done = NULL, .user_ctx = NULL, .flags = { .fb_in_psram = 1, // allocate frame buffer in PSRAM }, }; ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); lv_init(); lv_color_t *buf1 = (lv_color_t *)ps_malloc(EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(lv_color_t)); assert(buf1); lv_color_t *buf2 = (lv_color_t *)ps_malloc(EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(lv_color_t)); assert(buf2); lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES); Serial.println("Register display driver to LVGL"); lv_disp_drv_init(&disp_drv); disp_drv.hor_res = EXAMPLE_LCD_H_RES; disp_drv.ver_res = EXAMPLE_LCD_V_RES; disp_drv.flush_cb = example_lvgl_flush_cb; disp_drv.draw_buf = &disp_buf; disp_drv.user_data = panel_handle; lv_disp_t *disp = lv_disp_drv_register(&disp_drv); lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = lv_touchpad_read; lv_indev_drv_register(&indev_drv); LV_IMG_DECLARE(photo2); lv_obj_t *img = lv_img_create(lv_scr_act()); lv_img_set_src(img, &photo2); lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); const lv_img_dsc_t *photo[] = { &photo2}; button.attachClick([]() { click = true; }); waitInterruptReady(); lv_task_handler(); pinMode(backlightPin, OUTPUT); //LilyGo T-RGB control backlight chip has 16 levels of adjustment range for (int i = 0; i < 16; ++i) { setBrightness(i); delay(30); } int i = 1; while (i <= 1) { if (click || !digitalRead(TP_INT_PIN)) { click = false; lv_img_set_src(img, photo[i]); i++; waitInterruptReady(); } button.tick(); lv_task_handler(); delay(5); } lv_obj_del(img); ui_begin(); } void loop() { // put your main code here, to run repeatedly: static uint32_t Millis; delay(2); lv_timer_handler(); if (millis() - Millis > 50) { float v = (analogRead(BAT_VOLT_PIN) * 2 * 3.3) / 4096; lv_msg_send(MSG_BAT_VOLT_UPDATE, &v); Millis = millis(); } bool touched = digitalRead(TP_INT_PIN) == LOW; if (touched) { lastStatus = touched; lv_msg_send(MSG_TOUCH_INT_UPDATE, &touched); } else if (!touched && lastStatus) { lastStatus = false; lv_msg_send(MSG_TOUCH_INT_UPDATE, &touched); } } void lcd_send_data(uint8_t data) { uint8_t n; for (n = 0; n < 8; n++) { if (data & 0x80) xl.digitalWrite(LCD_SDA_PIN, 1); else xl.digitalWrite(LCD_SDA_PIN, 0); data <<= 1; xl.digitalWrite(LCD_CLK_PIN, 0); xl.digitalWrite(LCD_CLK_PIN, 1); } } void lcd_cmd(const uint8_t cmd) { xl.digitalWrite(LCD_CS_PIN, 0); xl.digitalWrite(LCD_SDA_PIN, 0); xl.digitalWrite(LCD_CLK_PIN, 0); xl.digitalWrite(LCD_CLK_PIN, 1); lcd_send_data(cmd); xl.digitalWrite(LCD_CS_PIN, 1); } void lcd_data(const uint8_t *data, int len) { uint32_t i = 0; if (len == 0) return; // no need to send anything do { xl.digitalWrite(LCD_CS_PIN, 0); xl.digitalWrite(LCD_SDA_PIN, 1); xl.digitalWrite(LCD_CLK_PIN, 0); xl.digitalWrite(LCD_CLK_PIN, 1); lcd_send_data(*(data + i)); xl.digitalWrite(LCD_CS_PIN, 1); i++; } while (len--); } void tft_init(void) { xl.digitalWrite(LCD_CS_PIN, 1); xl.digitalWrite(LCD_SDA_PIN, 1); xl.digitalWrite(LCD_CLK_PIN, 1); // Reset the display xl.digitalWrite(LCD_RST_PIN, 1); vTaskDelay(200 / portTICK_PERIOD_MS); xl.digitalWrite(LCD_RST_PIN, 0); vTaskDelay(200 / portTICK_PERIOD_MS); xl.digitalWrite(LCD_RST_PIN, 1); vTaskDelay(200 / portTICK_PERIOD_MS); int cmd = 0; while (st_init_cmds[cmd].databytes != 0xff) { lcd_cmd(st_init_cmds[cmd].cmd); lcd_data(st_init_cmds[cmd].data, st_init_cmds[cmd].databytes & 0x1F); if (st_init_cmds[cmd].databytes & 0x80) { vTaskDelay(100 / portTICK_PERIOD_MS); } cmd++; } Serial.println("Register setup complete"); } void seeimg(void){ LV_IMG_DECLARE(photo2); lv_obj_t *img = lv_img_create(lv_scr_act()); lv_img_set_src(img, &photo2); lv_obj_align(img, LV_ALIGN_CENTER, 0, 0); const lv_img_dsc_t *photo[] = { &photo2}; lv_img_set_src(img, photo[1]); } void deep_sleep(void){ Serial.print("deep_sleep"); if (pvCreatedTask) { vTaskDelete(pvCreatedTask); } WiFi.disconnect(); pinMode(TP_INT_PIN, INPUT); waitInterruptReady(); delay(2000); for (int i = 16; i >= 0; --i) { setBrightness(i); delay(30); } waitInterruptReady(); delay(1000); esp_sleep_enable_ext1_wakeup(1ULL << TP_INT_PIN, ESP_EXT1_WAKEUP_ALL_LOW); esp_deep_sleep_start(); }