【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
实际开发的时候,我们发现节奏还是要尽量慢一点。一定要按照屏幕驱动、触摸驱动、lvgl、触摸标定、触摸进入lvgl,不能想着一步梭哈,就能得到最终的结果。不然,往往是错误套着错误,很容易把人搞得非常疲惫。有必要一点一点修改代码,稳扎稳打、步步为营,这样用ai写代码比较稳妥一点。

1、添加触摸驱动
驱动芯片还是之前说过的xpt2046。本身是电阻屏,虽然消费领域用的一般,但是工业系统用得很多。比如说,电阻屏用手套按下去的时候,也会有效果,这是电容屏不具备的。
2、总线
总线部分还是spi,用到的是miso,但一般mosi也连接上。另外除了spi四根线之外,还有一个irq连线,可以用来做中断。
3、两个spi
电阻触摸屏,一般需要两个spi,这有点吃亏。毕竟其他ic一般都是用iic来记录 ,这样至少还可以用spi来做tf卡、或者是以太网连接。使用的时候,需要注意下。
4、ai编写代码
编写代码的时候,不要从0到1编写代码,要在上一次3.5寸屏幕ok的基础之上修改,这样成功的概率高很多。这也算是一个小的trick。
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
// ================= CONFIG =================
#define LCD_W 480
#define LCD_H 320
#define PIN_MOSI 13
#define PIN_CLK 14
#define PIN_CS 15
#define PIN_DC 2
#define PIN_RST 4
#define PIN_BL 12
// ================= TOUCH (XPT2046) =================
#define TP_MOSI 23
#define TP_MISO 19
#define TP_CLK 18
#define TP_CS 5
#define TP_IRQ 27
static spi_device_handle_t spi_lcd;
static spi_device_handle_t spi_tp;
static const char *TAG = "ILI9488_AUTO";
// ================= LCD MODE =================
typedef enum {
MODE_RGB565 = 0,
MODE_RGB666 = 1,
} lcd_mode_t;
static lcd_mode_t lcd_mode = MODE_RGB565;
// ================= GPIO =================
static inline void dc_cmd(void) { gpio_set_level(PIN_DC, 0); }
static inline void dc_data(void) { gpio_set_level(PIN_DC, 1); }
static void lcd_reset(void)
{
gpio_set_level(PIN_RST, 0);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(PIN_RST, 1);
vTaskDelay(pdMS_TO_TICKS(150));
}
// ================= SPI LCD =================
static void lcd_cmd(uint8_t cmd)
{
spi_transaction_t t = {
.length = 8,
.tx_buffer = &cmd,
};
dc_cmd();
spi_device_transmit(spi_lcd, &t);
}
static void lcd_data(const void *data, int len)
{
spi_transaction_t t = {
.length = len * 8,
.tx_buffer = data,
};
dc_data();
spi_device_transmit(spi_lcd, &t);
}
// ================= INIT =================
static void ili9488_init(lcd_mode_t mode)
{
lcd_reset();
lcd_cmd(0x01);
vTaskDelay(pdMS_TO_TICKS(120));
lcd_cmd(0x11);
vTaskDelay(pdMS_TO_TICKS(150));
lcd_cmd(0x3A);
uint8_t pix = (mode == MODE_RGB565) ? 0x55 : 0x66;
lcd_data(&pix, 1);
lcd_cmd(0x36);
uint8_t mad = 0x28;
lcd_data(&mad, 1);
lcd_cmd(0x29);
vTaskDelay(pdMS_TO_TICKS(50));
lcd_mode = mode;
ESP_LOGI(TAG, "LCD init done");
}
// ================= TOUCH (XPT2046) =================
static uint16_t tp_read_axis(uint8_t cmd)
{
uint8_t tx[3] = {cmd, 0x00, 0x00};
uint8_t rx[3] = {0};
spi_transaction_t t = {
.length = 24,
.tx_buffer = tx,
.rx_buffer = rx,
};
spi_device_transmit(spi_tp, &t);
int val = ((rx[1] << 8) | rx[2]) >> 3; // 12bit
return val & 0x0FFF;
}
static void touch_task(void *arg)
{
while (1)
{
if (gpio_get_level(TP_IRQ) == 0) // pressed
{
uint16_t x = tp_read_axis(0xD0);
uint16_t y = tp_read_axis(0x90);
ESP_LOGI("TOUCH", "PRESSED -> X=%d Y=%d", x, y);
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelay(pdMS_TO_TICKS(20));
}
}
// ================= WINDOW =================
static void set_window(int x1,int y1,int x2,int y2)
{
uint8_t d[4];
lcd_cmd(0x2A); // Column address set
d[0]=x1>>8; d[1]=x1;
d[2]=x2>>8; d[3]=x2;
lcd_data(d,4);
lcd_cmd(0x2B); // Page address set
d[0]=y1>>8; d[1]=y1;
d[2]=y2>>8; d[3]=y2;
lcd_data(d,4);
lcd_cmd(0x2C); // Memory write
}
// ================= AUTO SAFE FILL =================
#define BUF_PIXELS 1024
static uint8_t buf[BUF_PIXELS * 3]; // Maximum size prepared for RGB666
static void fill_color(uint16_t color)
{
set_window(0,0,LCD_W-1,LCD_H-1);
uint8_t r = (color >> 11) & 0x1F;
uint8_t g = (color >> 5) & 0x3F;
uint8_t b = color & 0x1F;
r <<= 3;
g <<= 2;
b <<= 3;
for (int i=0;i<BUF_PIXELS;i++) {
buf[i*3+0]=r;
buf[i*3+1]=g;
buf[i*3+2]=b;
}
spi_transaction_t t = {
.length = BUF_PIXELS * 24,
.tx_buffer = buf,
};
int blocks = (LCD_W*LCD_H)/BUF_PIXELS;
for (int i=0;i<blocks;i++) {
dc_data();
spi_device_transmit(spi_lcd,&t);
}
}
// ================= BACKLIGHT =================
static void backlight_init(void)
{
gpio_config_t io={
.pin_bit_mask=1ULL<<PIN_BL,
.mode=GPIO_MODE_OUTPUT
};
gpio_config(&io);
gpio_set_level(PIN_BL,1);
}
// ================= MAIN =================
void app_main(void)
{
gpio_set_direction(PIN_DC,GPIO_MODE_OUTPUT);
gpio_set_direction(PIN_RST,GPIO_MODE_OUTPUT);
// ================= LCD SPI =================
spi_bus_config_t bus_lcd={
.mosi_io_num=PIN_MOSI,
.miso_io_num=-1,
.sclk_io_num=PIN_CLK,
.max_transfer_sz=1024*3
};
spi_bus_initialize(SPI2_HOST,&bus_lcd,SPI_DMA_CH_AUTO);
spi_device_interface_config_t dev_lcd={
.clock_speed_hz=20*1000*1000,
.mode=0,
.spics_io_num=PIN_CS,
.queue_size=7,
};
spi_bus_add_device(SPI2_HOST,&dev_lcd,&spi_lcd);
// ================= TOUCH SPI =================
spi_bus_config_t bus_tp={
.mosi_io_num=TP_MOSI,
.miso_io_num=TP_MISO,
.sclk_io_num=TP_CLK,
.max_transfer_sz=32
};
spi_bus_initialize(SPI3_HOST,&bus_tp,SPI_DMA_CH_AUTO);
spi_device_interface_config_t dev_tp={
.clock_speed_hz=2*1000*1000,
.mode=0,
.spics_io_num=TP_CS,
.queue_size=3,
};
spi_bus_add_device(SPI3_HOST,&dev_tp,&spi_tp);
gpio_set_direction(TP_IRQ, GPIO_MODE_INPUT);
// ================= INIT LCD =================
ili9488_init(MODE_RGB666);
fill_color(0x07e0); // green
backlight_init(); // backlight on
// ================= TOUCH TASK =================
xTaskCreate(touch_task, "touch_task", 4096, NULL, 5, NULL);
while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
5、测试和验证
测试的时候,主要就是看两点。第一,看看屏幕的颜色有没有发生变化,比如说变成绿色。第二,就是esp-idf切换成monitor的形式,这个时候就可以看到打印信息。手动按下去的时候,看看有没有打印信息出来,正常是没有打印的,有打印就代表触摸屏起作用了。