原生示例

#include <Arduino.h>
#include <SPI.h>
// ESP-12E (NodeMCU) 引脚定义
#define LED   D0      // GPIO16
#define CS    D8      // GPIO15
#define RS    D1      // GPIO5
#define RESET D2      // GPIO4

void SPI_Init(void)
{
    SPI.begin();
    SPI.setClockDivider(40000000); // 设置SPI速度为40MHz
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);  
}
void Lcd_Writ_Bus(uint8_t d) {
  SPI.transfer(d);
}

void Lcd_Write_Com(uint8_t VH) {   
  digitalWrite(RS, LOW);  // 使用digitalWrite替代直接端口操作
  Lcd_Writ_Bus(VH);
}

void Lcd_Write_Data(uint8_t VH) {
  digitalWrite(RS, HIGH); // 使用digitalWrite替代直接端口操作
  Lcd_Writ_Bus(VH);
}

void Lcd_Write_Com_Data(uint8_t com, uint8_t dat) {
  Lcd_Write_Com(com);
  Lcd_Write_Data(dat);
}

void Address_set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
  Lcd_Write_Com(0x2a);
  Lcd_Write_Data(x1>>8);
  Lcd_Write_Data(x1);
  Lcd_Write_Data(x2>>8);
  Lcd_Write_Data(x2);
  Lcd_Write_Com(0x2b);
  Lcd_Write_Data(y1>>8);
  Lcd_Write_Data(y1);
  Lcd_Write_Data(y2>>8);
  Lcd_Write_Data(y2);
  Lcd_Write_Com(0x2c); 							 
}

void Lcd_Init(void)
{
  digitalWrite(RESET,HIGH);
  delay(5); 
  digitalWrite(RESET,LOW);
  delay(15);
  digitalWrite(RESET,HIGH);
  delay(15);

  digitalWrite(CS,LOW);  //CS

    Lcd_Write_Com(0xF7);  
    Lcd_Write_Data(0xA9); 
    Lcd_Write_Data(0x51); 
    Lcd_Write_Data(0x2C); 
    Lcd_Write_Data(0x82);  

    Lcd_Write_Com(0xC0);  
    Lcd_Write_Data(0x11); 
    Lcd_Write_Data(0x09); 

    Lcd_Write_Com(0xC1);  
    Lcd_Write_Data(0x41); 

    Lcd_Write_Com(0xC5);  
    Lcd_Write_Data(0x00); 
    Lcd_Write_Data(0x0A); 
    Lcd_Write_Data(0x80);
 
    Lcd_Write_Com(0xB1);  
    Lcd_Write_Data(0xB0); 
    Lcd_Write_Data(0x11); 

    Lcd_Write_Com(0xB4);  
    Lcd_Write_Data(0x02); 
  
    Lcd_Write_Com(0xB6);    
    Lcd_Write_Data(0x02);
    Lcd_Write_Data(0x22);  
 
    Lcd_Write_Com(0xB7);    
    Lcd_Write_Data(0xC6);  

    Lcd_Write_Com(0xBE);    
    Lcd_Write_Data(0x00);   
    Lcd_Write_Data(0x04); 
 
    Lcd_Write_Com(0xE9);    
    Lcd_Write_Data(0x00);   
 
    Lcd_Write_Com(0x36);  
    Lcd_Write_Data(0x08);   

    Lcd_Write_Com(0x3A);    
    Lcd_Write_Data(0x66); 

    Lcd_Write_Com(0xE0);    
    Lcd_Write_Data(0x00);  
    Lcd_Write_Data(0x07); 
    Lcd_Write_Data(0x10); 
    Lcd_Write_Data(0x09); 
    Lcd_Write_Data(0x17); 
    Lcd_Write_Data(0x0B); 
    Lcd_Write_Data(0x41); 
    Lcd_Write_Data(0x89); 
    Lcd_Write_Data(0x4B); 
    Lcd_Write_Data(0x0A); 
    Lcd_Write_Data(0x0C); 
    Lcd_Write_Data(0x0E); 
    Lcd_Write_Data(0x18); 
    Lcd_Write_Data(0x1B); 
    Lcd_Write_Data(0x0F); 

    Lcd_Write_Com(0xE1);    
    Lcd_Write_Data(0x00);  
    Lcd_Write_Data(0x17); 
    Lcd_Write_Data(0x1A); 
    Lcd_Write_Data(0x04); 
    Lcd_Write_Data(0x0E); 
    Lcd_Write_Data(0x06); 
    Lcd_Write_Data(0x2F); 
    Lcd_Write_Data(0x45); 
    Lcd_Write_Data(0x43); 
    Lcd_Write_Data(0x02); 
    Lcd_Write_Data(0x0A); 
    Lcd_Write_Data(0x09); 
    Lcd_Write_Data(0x32); 
    Lcd_Write_Data(0x36); 
    Lcd_Write_Data(0x0F); 

    Lcd_Write_Com(0x11);    //Exit Sleep 
    delay(120); 			
    Lcd_Write_Com(0x29);    //Display on 

    digitalWrite(CS,HIGH);
}
void H_line(unsigned int x, unsigned int y, unsigned int l, unsigned int c)                   
{	
  unsigned int i,j;
  digitalWrite(CS,LOW);
  Lcd_Write_Com(0x02c); //write_memory_start
  //digitalWrite(RS,HIGH);
  l=l+x;
  Address_set(x,y,l,y);
  j=l*2;
  for(i=1;i<=j;i++)
  {
      Lcd_Write_Data((c>>8)&0xF8);
      Lcd_Write_Data((c>>3)&0xFC);
      Lcd_Write_Data(c<<3);
  }
  digitalWrite(CS,HIGH);   
}

void V_line(unsigned int x, unsigned int y, unsigned int l, unsigned int c)                   
{	
  unsigned int i,j;
  digitalWrite(CS,LOW);
  Lcd_Write_Com(0x02c); //write_memory_start
  //digitalWrite(RS,HIGH);
  l=l+y;
  Address_set(x,y,x,l);
  j=l*2;
  for(i=1;i<=j;i++)
  { 
      Lcd_Write_Data((c>>8)&0xF8);
      Lcd_Write_Data((c>>3)&0xFC);
      Lcd_Write_Data(c<<3);
  }
  digitalWrite(CS,HIGH);   
}

void Rect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c)
{
  H_line(x  , y  , w, c);
  H_line(x  , y+h, w, c);
  V_line(x  , y  , h, c);
  V_line(x+w, y  , h, c);
}

void Rectf(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c)
{
  unsigned int i;
  for(i=0;i<h;i++)
  {
    H_line(x  , y  , w, c);
    H_line(x  , y+i, w, c);
  }
}

int RGB(int r,int g,int b)
{
  return r << 16 | g << 8 | b;
}

void LCD_Clear(unsigned int j)                   
{	
  unsigned int i,m;
  digitalWrite(CS,LOW);
  Address_set(0,0,320,480);
  for(i=0;i<320;i++)
    for(m=0;m<480;m++)
    {
      Lcd_Write_Data((j>>8)&0xF8);
      Lcd_Write_Data((j>>3)&0xFC);
      Lcd_Write_Data(j<<3);
    }
  digitalWrite(CS,HIGH);   
}
void setup() {
  // 初始化引脚模式
  pinMode(LED, OUTPUT);
  pinMode(RS, OUTPUT);
  pinMode(RESET, OUTPUT);
  pinMode(CS, OUTPUT);
  
  // 设置初始状态
  digitalWrite(LED, HIGH);  // 背光开启
  digitalWrite(CS, HIGH);   // 初始不选中
  digitalWrite(RS, HIGH);   // 初始数据模式
  
  SPI_Init();
  Lcd_Init();
}

void loop() {
  LCD_Clear(0xf800);  // 红色
  LCD_Clear(0x07E0);  // 绿色
  LCD_Clear(0x001F);  // 蓝色
  LCD_Clear(0x0000);  // 黑色
  
  for(int i=0; i<100; i++) {  // 减少测试图形数量
    Rect(random(300), random(300), random(100), random(100), random(65535));
  }
}

GFX示例

/*******************************************************************************
 * Start of Arduino_GFX setting
 *
 * Arduino_GFX try to find the settings depends on selected board in Arduino IDE
 * Or you can define the display dev kit not in the board list
 * Defalult pin list for non display dev kit:
 * Arduino Nano, Micro and more: CS:  9, DC:  8, RST:  7, BL:  6, SCK: 13, MOSI: 11, MISO: 12
 * ESP32 various dev board     : CS:  5, DC: 27, RST: 33, BL: 22, SCK: 18, MOSI: 23, MISO: nil
 * ESP32-C3 various dev board  : CS:  7, DC:  2, RST:  1, BL:  3, SCK:  4, MOSI:  6, MISO: nil
 * ESP32-S2 various dev board  : CS: 34, DC: 38, RST: 33, BL: 21, SCK: 36, MOSI: 35, MISO: nil
 * ESP32-S3 various dev board  : CS: 40, DC: 41, RST: 42, BL: 48, SCK: 36, MOSI: 35, MISO: nil
 * ESP8266 various dev board   : CS: 15, DC:  4, RST:  2, BL:  5, SCK: 14, MOSI: 13, MISO: 12
 * Raspberry Pi Pico dev board : CS: 17, DC: 27, RST: 26, BL: 28, SCK: 18, MOSI: 19, MISO: 16
 * RTL8720 BW16 old patch core : CS: 18, DC: 17, RST:  2, BL: 23, SCK: 19, MOSI: 21, MISO: 20
 * RTL8720_BW16 Official core  : CS:  9, DC:  8, RST:  6, BL:  3, SCK: 10, MOSI: 12, MISO: 11
 * RTL8722 dev board           : CS: 18, DC: 17, RST: 22, BL: 23, SCK: 13, MOSI: 11, MISO: 12
 * RTL8722_mini dev board      : CS: 12, DC: 14, RST: 15, BL: 13, SCK: 11, MOSI:  9, MISO: 10
 * Seeeduino XIAO dev board    : CS:  3, DC:  2, RST:  1, BL:  0, SCK:  8, MOSI: 10, MISO:  9
 * Teensy 4.1 dev board        : CS: 39, DC: 41, RST: 40, BL: 22, SCK: 13, MOSI: 11, MISO: 12
 ******************************************************************************/
#include <Arduino_GFX_Library.h>

// ESP12E 引脚定义
#define TFT_CS   15   // GPIO15
#define TFT_DC   4    // GPIO4
#define TFT_RST  2    // GPIO2
#define TFT_BL   5    // GPIO5(背光控制)
void testDisplay();
// 使用硬件SPI
Arduino_DataBus *bus = new Arduino_ESP8266SPI(TFT_DC, TFT_CS);
Arduino_GFX *gfx = new Arduino_ILI9488_18bit(bus, TFT_RST); // 使用18位模式

void setup(void) {
  Serial.begin(115200);
  Serial.println("\n\nILI9488 3.5\" Display Test");
  
  // 先控制复位引脚
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, LOW);
  delay(100);
  digitalWrite(TFT_RST, HIGH);
  delay(200);  // 复位后等待
  
  // 初始化背光(尝试两种逻辑)
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);  // 尝试高电平
  delay(100);
  digitalWrite(TFT_BL, LOW);   // 尝试低电平
  delay(100);
  
  Serial.println("Initializing display...");
  
  // 初始化显示屏(降低SPI速度)
  if (!gfx->begin(27000000)) { // 27MHz SPI速度
    Serial.println("Display init failed!");
  } else {
    Serial.println("Display init success!");
  }
  
  // 执行硬件测试
  testDisplay();
  
  Serial.println("Setup complete");
}

void testDisplay() {
  // 测试背光
  Serial.println("Testing backlight...");
  for (int i = 0; i < 3; i++) {
    digitalWrite(TFT_BL, HIGH);
    delay(300);
    digitalWrite(TFT_BL, LOW);
    delay(300);
  }
  digitalWrite(TFT_BL, HIGH); // 保持开启
  
  // 颜色填充测试
  Serial.println("Color fill test...");
  gfx->fillScreen(RED);
  delay(1000);
  gfx->fillScreen(GREEN);
  delay(1000);
  gfx->fillScreen(BLUE);
  delay(1000);
  
  // 显示文本
  gfx->fillScreen(BLACK);
  gfx->setTextColor(WHITE, BLACK);
  gfx->setTextSize(2, 2);
  gfx->setCursor(30, 140);
  gfx->println("ILI9488 3.5\"");
  
  gfx->setCursor(50, 180);
  gfx->println("480x320");
  
  gfx->setCursor(80, 220);
  gfx->setTextColor(YELLOW, BLACK);
  gfx->println("WORKING!");
}

void loop() {
  // 显示动态内容
  static int counter = 0;
  gfx->fillRect(0, 0, 480, 40, BLACK); // 清空顶部区域
  
  gfx->setTextSize(2, 2);
  gfx->setCursor(10, 10);
  gfx->setTextColor(random(0xFFFF), BLACK);
  gfx->printf("Counter: %d", counter++);
  
  delay(500);
}

GFX结合LVGL

/*******************************************************************************
 * [原有Arduino_GFX设置代码保持不变]
 ******************************************************************************/
#include <Arduino_GFX_Library.h>
#include <lvgl.h> // 添加LVGL库

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
void create_test_ui();
// ESP12E 引脚定义
#define TFT_CS   15   // GPIO15
#define TFT_DC   4    // GPIO4
#define TFT_RST  2    // GPIO2
#define TFT_BL   5    // GPIO5(背光控制)

// 使用硬件SPI
Arduino_DataBus *bus = new Arduino_ESP8266SPI(TFT_DC, TFT_CS);
Arduino_GFX *gfx = new Arduino_ILI9488_18bit(bus, TFT_RST); // 使用18位模式

/* LVGL配置 */
#define LV_HOR_RES_MAX 480   // 水平分辨率
#define LV_VER_RES_MAX 320   // 垂直分辨率

#define LV_BUF_SIZE (LV_HOR_RES_MAX * 2) // 缓冲区大小(行数)

static lv_disp_draw_buf_t draw_buf;     // LVGL绘制缓冲区
static lv_color_t buf1[LV_BUF_SIZE];    // 第一缓冲区
static lv_color_t buf2[LV_BUF_SIZE];    // 第二缓冲区(双缓冲)

// 测试界面相关变量
static lv_obj_t *main_screen;
static lv_obj_t *time_label;
static lv_obj_t *counter_label;
static lv_obj_t *anim_bar;
static lv_obj_t *arc;
static uint32_t counter = 0;

void setup(void) {
  Serial.begin(115200);
  Serial.println("\n\nILI9488 with LVGL Integration");
  
  // 复位显示屏
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, LOW);
  delay(100);
  digitalWrite(TFT_RST, HIGH);
  delay(200);
  
  // 初始化背光
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);  // 保持常亮

  // 初始化显示屏
  if (!gfx->begin(27000000)) { // 27MHz SPI速度
    Serial.println("Display init failed!");
    while(1); // 停止执行
  }
  // 设置横屏模式
  gfx->setRotation(1); // 1表示90度旋转,通常是横屏
  Serial.println("Display init success!");

  /* 初始化LVGL */
  lv_init();
  
  /* 初始化双缓冲区 */
  lv_disp_draw_buf_init(&draw_buf, buf1, buf2, LV_BUF_SIZE);
  
  /* 注册显示驱动 */
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = LV_HOR_RES_MAX;
  disp_drv.ver_res = LV_VER_RES_MAX;
  disp_drv.flush_cb = my_disp_flush;  // 注册刷新回调
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register(&disp_drv);

  /* 创建测试界面 */
  create_test_ui();
  
  Serial.println("LVGL test interface initialized");
}

/* 显示刷新回调函数 */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  uint32_t w = (area->x2 - area->x1 + 1);
  uint32_t h = (area->y2 - area->y1 + 1);
  
  gfx->draw16bitRGBBitmap(
    area->x1,        // x起始位置
    area->y1,        // y起始位置
    (uint16_t *)color_p, // 数据指针
    w,               // 宽度
    h                // 高度
  );
  
  lv_disp_flush_ready(disp); // 通知LVGL刷新完成
}

/* 创建测试界面 */
void create_test_ui() {
  // 创建主屏幕
  main_screen = lv_scr_act();
  lv_obj_set_style_bg_color(main_screen, lv_color_hex(0x003060), 0);
  
  // 标题
  lv_obj_t *title = lv_label_create(main_screen);
  lv_label_set_text(title, "LVGL Test Interface");
  // 移除字体设置,使用默认字体
  lv_obj_set_style_text_color(title, lv_color_white(), 0);
  lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);
  
  // 时间显示标签
  time_label = lv_label_create(main_screen);
  lv_label_set_text(time_label, "Time: 0s");
  // 移除字体设置,使用默认字体
  lv_obj_set_style_text_color(time_label, lv_color_white(), 0);
  lv_obj_align(time_label, LV_ALIGN_TOP_MID, 0, 50);
  
  // 计数器显示标签
  counter_label = lv_label_create(main_screen);
  lv_label_set_text(counter_label, "Counter: 0");
  // 移除字体设置,使用默认字体
  lv_obj_set_style_text_color(counter_label, lv_color_white(), 0);
  lv_obj_align(counter_label, LV_ALIGN_TOP_MID, 0, 80);
  
  // 弧形进度条
  arc = lv_arc_create(main_screen);
  lv_obj_set_size(arc, 150, 150);
  lv_arc_set_rotation(arc, 180);
  lv_arc_set_bg_angles(arc, 0, 360);
  lv_arc_set_value(arc, 0);
  lv_obj_align(arc, LV_ALIGN_CENTER, 0, -20);
  
  // 弧形标签
  lv_obj_t *arc_label = lv_label_create(main_screen);
  lv_label_set_text(arc_label, "Arc Progress");
  lv_obj_set_style_text_color(arc_label, lv_color_white(), 0);
  lv_obj_align_to(arc_label, arc, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
  
  // 进度条
  anim_bar = lv_bar_create(main_screen);
  lv_obj_set_size(anim_bar, 300, 20);
  lv_obj_align(anim_bar, LV_ALIGN_BOTTOM_MID, 0, -50);
  lv_bar_set_range(anim_bar, 0, 100);
  lv_bar_set_value(anim_bar, 0, LV_ANIM_ON);
  
  // 进度条标签
  lv_obj_t *bar_label = lv_label_create(main_screen);
  lv_label_set_text(bar_label, "Animated Bar");
  lv_obj_set_style_text_color(bar_label, lv_color_white(), 0);
  lv_obj_align_to(bar_label, anim_bar, LV_ALIGN_OUT_TOP_MID, 0, -5);
  
  // 创建动画
  lv_anim_t a;
  lv_anim_init(&a);
  lv_anim_set_var(&a, anim_bar);
  lv_anim_set_values(&a, 0, 100);
  lv_anim_set_time(&a, 3000);
  lv_anim_set_playback_time(&a, 3000);
  lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
  lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_bar_set_value);
  lv_anim_start(&a);
}

void loop() {
  // 更新时间显示
  static uint32_t last_update = 0;
  uint32_t current_time = millis() / 1000;
  
  if (current_time != last_update) {
    last_update = current_time;
    char time_buf[32];
    sprintf(time_buf, "Time: %ds", (int)current_time);
    lv_label_set_text(time_label, time_buf);
    
    // 更新计数器
    counter++;
    char counter_buf[32];
    sprintf(counter_buf, "Counter: %d", (int)counter);
    lv_label_set_text(counter_label, counter_buf);
    
    // 更新弧形进度条
    lv_arc_set_value(arc, counter % 101);
  }
  
  lv_timer_handler(); // 处理LVGL任务
  delay(5); // 短暂延时
}

触摸屏驱动解决方案 (ILI9488 + MSP3520)

有问题

#include <Arduino_GFX_Library.h>
#include <XPT2046_Touchscreen.h> // MSP3520兼容XPT2046库

// 显示屏引脚配置
#define TFT_CS   15   // GPIO15
#define TFT_DC   4    // GPIO4
#define TFT_RST  2    // GPIO2
#define TFT_BL   5    // GPIO5

// 触摸屏引脚配置
#define TOUCH_CS 16   // GPIO16 (触摸片选)
#define TOUCH_IRQ -1  // 不使用中断

// 使用硬件SPI
Arduino_DataBus *bus = new Arduino_ESP8266SPI(TFT_DC, TFT_CS);
Arduino_GFX *gfx = new Arduino_ILI9488_18bit(bus, TFT_RST);

// 触摸屏对象
XPT2046_Touchscreen touch(TOUCH_CS, TOUCH_IRQ);

// 触摸校准参数 (根据实际调整)
const int TS_MINX = 200;
const int TS_MINY = 200;
const int TS_MAXX = 3800;
const int TS_MAXY = 3800;

void setup() {
  Serial.begin(115200);
  Serial.println("\nILI9488 + MSP3520 Test");
  
  // 显示屏复位
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, LOW);
  delay(50);
  digitalWrite(TFT_RST, HIGH);
  delay(150);
  
  // 背光初始化(固定高电平)
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);  // 保持常亮

  // 降低SPI速度确保稳定性
  if (!gfx->begin(15000000)) { // 15MHz
    Serial.println("Display init failed!");
    while(1); // 卡死检测
  }
  Serial.println("Display ready");
  
  // 触摸屏初始化
  touch.begin();
  touch.setRotation(1); // 根据屏幕方向调整
  Serial.println("Touch ready");

  // 显示初始界面
  gfx->fillScreen(BLACK);
  gfx->setTextSize(2, 2);
  gfx->setTextColor(WHITE);
  gfx->setCursor(60, 140);
  gfx->print("TOUCH TEST");
}

void loop() {
  // 触摸检测
  if (touch.touched()) {
    TS_Point p = touch.getPoint();
    
    // 坐标转换 (480x320)
    int x = map(p.y, TS_MINY, TS_MAXY, 0, 479);
    int y = map(p.x, TS_MINX, TS_MAXX, 319, 0);
    
    Serial.printf("Touch: X=%d, Y=%d, Pressure=%d\n", x, y, p.z);
    
    // 视觉反馈:触摸点
    gfx->fillCircle(x, y, 5, RED);
    delay(50);
    gfx->fillCircle(x, y, 5, BLACK);
  }
  
  // 显示帧率计数器
  static uint32_t lastUpdate = 0;
  static int counter = 0;
  
  if (millis() - lastUpdate > 1000) {
    gfx->fillRect(0, 0, 100, 30, BLACK);
    gfx->setCursor(10, 10);
    gfx->setTextColor(GREEN);
    gfx->printf("FPS:%2d", counter);
    
    counter = 0;
    lastUpdate = millis();
  }
  counter++;
}

使用TFT_eSPI库驱动

需要配置TFT_eSPI

  1. 打开Arduino库文件夹中的TFT_eSPI目录
  2. 编辑User_Setup.h文件
  3. 确保有以下配置:


#define USER_SETUP_INFO "User_Setup"

#define TFT_DRIVER      ILI9488

// ESP8266引脚配置
#define TFT_CS   15   // GPIO15
#define TFT_DC   4    // GPIO4
#define TFT_RST  2    // GPIO2

// 使用SPI
#define TFT_SPI_FREQUENCY  27000000

// 屏幕尺寸
#define TFT_WIDTH  480
#define TFT_HEIGHT 320

// 颜色格式
#define TFT_RGB_ORDER TFT_BGR

// 字体设置
#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF
#include <TFT_eSPI.h>      // 包含TFT_eSPI库
#include <SPI.h>           // SPI通信库
#include <XPT2046_Touchscreen.h> // MSP3520触摸屏驱动

// 屏幕尺寸定义
#define SCREEN_WIDTH  480
#define SCREEN_HEIGHT 320

// 触摸屏引脚定义
#define TOUCH_CS  16  // GPIO16 (触摸片选)
#define TOUCH_IRQ -1  // 不使用中断

// 创建TFT和触摸对象
TFT_eSPI tft = TFT_eSPI();  // 创建TFT对象
XPT2046_Touchscreen touch(TOUCH_CS, TOUCH_IRQ);  // 创建触摸对象

// 触摸校准参数 (根据实际情况调整)
const int TS_MINX = 250;
const int TS_MINY = 280;
const int TS_MAXX = 3750;
const int TS_MAXY = 3780;

// 颜色定义
#define BACKGROUND_COLOR 0x18E3  // 深蓝色背景
#define UI_COLOR         0x07FF  // 青色UI元素
#define TEXT_COLOR       0xFFFF  // 白色文本
#define BUTTON_COLOR     0xF800  // 红色按钮
#define BUTTON_TEXT      0xFFFF  // 白色按钮文本

// 按钮结构
struct Button {
  int x, y, width, height;
  String label;
};

// 创建按钮数组
Button buttons[] = {
  {50, 120, 120, 50, "Button 1"},
  {190, 120, 120, 50, "Button 2"},
  {330, 120, 120, 50, "Button 3"}
};

const int buttonCount = sizeof(buttons) / sizeof(Button);

void setup() {
  Serial.begin(115200);
  Serial.println("\nILI9488 + MSP3520 with TFT_eSPI");
  
  // 初始化显示屏
  tft.init();
  tft.setRotation(1);  // 设置屏幕方向 (0-3)
  tft.fillScreen(TFT_BLACK);
  
  // 初始化背光 (如果连接了背光引脚)
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH);  // 开启背光
  
  // 初始化触摸屏
  touch.begin();
  touch.setRotation(1);  // 设置触摸方向与屏幕一致
  
  // 创建UI界面
  createUI();
  
  Serial.println("Setup complete");
}

void createUI() {
  // 绘制背景
  tft.fillScreen(BACKGROUND_COLOR);
  
  // 绘制标题
  tft.setTextColor(TEXT_COLOR, BACKGROUND_COLOR);
  tft.setTextSize(3);
  tft.setTextDatum(TC_DATUM);  // 顶部居中
  tft.drawString("TFT_eSPI Demo", SCREEN_WIDTH / 2, 20);
  
  // 绘制子标题
  tft.setTextSize(2);
  tft.drawString("ILI9488 + MSP3520", SCREEN_WIDTH / 2, 60);
  
  // 绘制按钮
  for (int i = 0; i < buttonCount; i++) {
    drawButton(buttons[i]);
  }
  
  // 绘制触摸状态区域
  tft.fillRoundRect(50, 200, SCREEN_WIDTH - 100, 80, 10, TFT_DARKGREY);
  tft.setTextColor(TEXT_COLOR, TFT_DARKGREY);
  tft.setTextSize(2);
  tft.drawString("Touch Status", SCREEN_WIDTH / 2, 210);
  tft.setTextSize(1);
  tft.drawString("Touch screen to see coordinates", SCREEN_WIDTH / 2, 240);
}

void drawButton(Button btn) {
  // 绘制按钮背景
  tft.fillRoundRect(btn.x, btn.y, btn.width, btn.height, 10, BUTTON_COLOR);
  
  // 绘制按钮边框
  tft.drawRoundRect(btn.x, btn.y, btn.width, btn.height, 10, TFT_WHITE);
  
  // 绘制按钮文本
  tft.setTextColor(BUTTON_TEXT, BUTTON_COLOR);
  tft.setTextSize(2);
  tft.setTextDatum(MC_DATUM);  // 居中
  tft.drawString(btn.label, btn.x + btn.width / 2, btn.y + btn.height / 2);
}

void processTouch() {
  static int lastX = -1, lastY = -1;
  
  if (touch.touched()) {
    TS_Point p = touch.getPoint();
    
    // 映射触摸坐标到屏幕坐标
    int x = map(p.y, TS_MINY, TS_MAXY, 0, SCREEN_WIDTH - 1);
    int y = map(p.x, TS_MINX, TS_MAXX, SCREEN_HEIGHT - 1, 0);
    
    // 限制坐标在屏幕范围内
    x = constrain(x, 0, SCREEN_WIDTH - 1);
    y = constrain(y, 0, SCREEN_HEIGHT - 1);
    
    // 显示触摸坐标
    tft.fillRect(60, 250, 360, 20, TFT_DARKGREY);
    tft.setTextColor(TFT_YELLOW, TFT_DARKGREY);
    tft.setTextSize(2);
    tft.drawString("X: " + String(x) + " Y: " + String(y), SCREEN_WIDTH / 2, 250);
    
    // 检查按钮点击
    for (int i = 0; i < buttonCount; i++) {
      if (isPointInButton(x, y, buttons[i])) {
        buttonPressed(i);
        break;
      }
    }
    
    // 绘制触摸点
    if (lastX != -1 && lastY != -1) {
      tft.fillCircle(lastX, lastY, 4, BACKGROUND_COLOR);
    }
    tft.fillCircle(x, y, 4, TFT_YELLOW);
    
    lastX = x;
    lastY = y;
  } 
  else if (lastX != -1) {
    // 清除触摸点
    tft.fillCircle(lastX, lastY, 4, BACKGROUND_COLOR);
    lastX = lastY = -1;
  }
}

bool isPointInButton(int x, int y, Button btn) {
  return (x >= btn.x && x < (btn.x + btn.width) &&
          y >= btn.y && y < (btn.y + btn.height));
}

void buttonPressed(int index) {
  // 视觉反馈:按钮按下效果
  Button btn = buttons[index];
  
  // 绘制按下的按钮
  tft.fillRoundRect(btn.x, btn.y, btn.width, btn.height, 10, TFT_DARKGREEN);
  tft.drawRoundRect(btn.x, btn.y, btn.width, btn.height, 10, TFT_WHITE);
  tft.setTextColor(TFT_WHITE, TFT_DARKGREEN);
  tft.setTextSize(2);
  tft.drawString(btn.label, btn.x + btn.width / 2, btn.y + btn.height / 2);
  
  // 在串口显示按下的按钮
  Serial.println("Button pressed: " + btn.label);
  
  delay(100); // 短暂显示按下的状态
  
  // 恢复按钮原始状态
  drawButton(btn);
}

void updateCounter() {
  static uint32_t lastUpdate = 0;
  static int counter = 0;
  
  if (millis() - lastUpdate > 1000) {
    // 更新计数器显示
    tft.fillRect(SCREEN_WIDTH - 100, 10, 90, 25, BACKGROUND_COLOR);
    tft.setTextColor(TEXT_COLOR, BACKGROUND_COLOR);
    tft.setTextSize(2);
    tft.setTextDatum(TR_DATUM); // 右上角对齐
    tft.drawString("Time: " + String(counter) + "s", SCREEN_WIDTH - 10, 10);
    
    counter++;
    lastUpdate = millis();
  }
}

void loop() {
  processTouch();  // 处理触摸事件
  updateCounter(); // 更新计数器
  delay(10);       // 短暂延迟
}