为LVGL添加自己的触摸屏驱动(FT6336U为例,arduino)

之前写过一篇文章“arduino下使用LVGL的一些笔记(驱动CST816触摸屏、适配FFat内部文件系统)”,链接:arduino下使用LVGL的一些笔记(驱动CST816触摸屏、适配FFat内部文件系统)_littlefs lvgl-CSDN博客

其中简单提到了如何去适配触摸屏的驱动,这篇文件我们更加深入的去了解下如何把一个自己的触摸屏驱动(FT6336U为例)适配到LVGL中去。当然这里说的是LVGL中没有被集成的驱动。

一、LVGL触摸屏驱动API部分

首先,我们要了解LVGL是如何与触摸屏驱动之间进行API接口联系的。

1.设备注册

LVGL的初始化部分有如下注册输入设备驱动的代码,这里就是注册触摸屏的驱动了。

  /*Initialize the (dummy) input device driver*/
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = my_touchpad_read;
  lv_indev_drv_register(&indev_drv);

其中:

indev_drv.type = LV_INDEV_TYPE_POINTER;

代表指针型输入设备,比如触摸屏、鼠标等,意味着传给LVGL的最重要信息是坐标信息。

  indev_drv.read_cb = my_touchpad_read;

这行是把读取坐标的函数作为回调函数注册给LVGL,my_touchpad_read是最重要的触摸屏坐标传输API接口。

驱动注册成功后,LVGL会后台不断调用回调函数my_touchpad_read(),然后根据回调函数返回结果来处理触摸事件。

2.触摸屏读取API

my_touchpad_read这个函数是LVGL提供的。注意到其有两个参数:indev_drv和data。

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{
  if (touch_6336.available())
  {
    data->state = LV_INDEV_STATE_PR;
    data->point.x = touch_6336.touchPoint.tp[0].x;
    data->point.y = touch_6336.touchPoint.tp[0].y;
  }
  else
  {
    data->state = LV_INDEV_STATE_REL;
  }
}

indev_drv实际可以不用,但是data是我们必须用的。

代码中:

data->state就是标识触摸屏状态了,LV_INDEV_STATE_PR代表有触摸动作发生,LV_INDEV_STATE_REL代表触摸屏释放。

data->point.x和data->point.y就是在有触摸动作发生的时候,把读取的坐标保存到这两个变量中。

要注意if (touch_6336.available())这行,它的返回结果代表着是否发生触摸动作,是需要触摸屏驱动在发生触摸时返回true的。同时也是说,触摸屏驱动中,必须要有available()这个方法。

此外其实我们还有些要了解:

(1)触摸屏对象的定义。FT6336U.h中是定义的类,那么定义一个对象就行了。

FT6336U touch_6336(5,4,7,&Wire);//Wire是0号总线

几个参数后面会讲到为什么这么写。

(2)触摸屏初始化。在setup部分调用一次即可。

touch_6336.begin();

函数定义后面会讲。

二、触摸屏驱动部分

了解了LVGL的触摸屏驱动API,那么我们就可以做驱动适配了。

这里我们在arduino库中找了一下FT6336U这个触摸屏的驱动,找到一个“RAK14014-FT6336U”的驱动版本,不用安装库,找到该驱动的github仓库,下载源文件即可:RAK14014_FT6336U.cpp和RAK14014_FT6336U.h。

在arduino的library中新建一个文件夹FT6336U,把这下载的两个文件拷贝到该文件夹中,重命名为FT6336U.cpp和FT6336U.h。

然后就可以开始改造了。

1.硬件底层方面

打开FT6336U.cpp,我们可以看到底层与触摸屏硬件层面交互数据的两个方法:

uint8_t FT6336U::readByte(uint8_t addr) 
{
  uint8_t rdData = 0; 
  uint8_t rdDataCount; 
  do {
    _i2cPort->beginTransmission(_deviceAddress); 
    _i2cPort->write(addr); 
    _i2cPort->endTransmission(false); // Restart
    delay(10); 
    rdDataCount = _i2cPort->requestFrom(_deviceAddress, 1); 
  } while(rdDataCount == 0); 
  if(_i2cPort->available()) 
  {
    rdData = _i2cPort->read(); 
  }
  return rdData; 
}
void FT6336U::writeByte(uint8_t addr, uint8_t data) 
{
  _i2cPort->beginTransmission(_deviceAddress); 
  _i2cPort->write(addr); 
  _i2cPort->write(data); 
  _i2cPort->endTransmission(); 
}

具体的过程我们可以不去管它,但是我们必须关注它使用的是I2C总线。

具体使用的是哪个I2C总线,引脚怎么定义的呢?这个是我们必须要弄清楚的。

看FT6336U.cpp的代码:

FT6336U::FT6336U(byte addr) 
{
  _deviceAddress = addr;
}

bool FT6336U::begin(TwoWire &wirePort, uint8_t deviceAddress)
{
  _deviceAddress = deviceAddress;
  _i2cPort = &wirePort;
  _i2cPort->begin(); 
  if(read_device_type() == 0x02)
  {
    writeByte(0x02, 0x01);
    return true;
  }
  return false;
}

第一个是构造函数,第二个是初始化函数。

(1)构造函数

为了方便我们指定触摸屏引脚和总线号,我们把构造函数改造一下,把总线号和引脚传给对象。

FT6336U::FT6336U(int SDAPin, int SCLPin, int INTPin, TwoWire * wirePort) 
  {
    _deviceAddress    = I2C_ADDR_FT6336U;
    _SDAPin           = uint8_t(SDAPin);
    _SCLPin           = uint8_t(SCLPin);
    _INTPin           = uint8_t(INTPin);
    _i2cPort          = wirePort;//Wire和wire1两个关键字是两条硬总线0/1,在wire.h中被固定定义了
  }

(2)初始化函数

看FT6336U.h中函数原型定义:

  bool begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = I2C_ADDR_FT6336U);

OK,如此的话,如果不指定参数,那么就是用的第一条(0#)I2C总线。具体见Wire.h末尾对Wire和Wire1两个符号的预定义。

等等,关于引脚的定义呢?

看bool FT6336U::begin(TwoWire &wirePort, uint8_t deviceAddress)中的一行:

  _i2cPort->begin(); 

_i2cPort是一个I2C(TwoWire)对象,那么这个begin()函数的原型定义是就在Wire.h中了。

在Wire.h中,关于begin()函数定义了多种形式:

  
    bool begin(int sda, int scl, uint32_t frequency=0); // returns true, if successful init of i2c bus
    bool begin(uint8_t slaveAddr, int sda, int scl, uint32_t frequency);
    // Explicit Overload for Arduino MainStream API compatibility
    inline bool begin()
    {
        return begin(-1, -1, static_cast<uint32_t>(0));
    }
    inline bool begin(uint8_t addr)
    {
        return begin(addr, -1, -1, 0);
    }
    inline bool begin(int addr)
    {
        return begin(static_cast<uint8_t>(addr), -1, -1, 0);
    }

OK,那么在这个begin中增加引脚即可:

  _i2cPort->begin(SDAPin,SCLPin); 

SDAPin和SCLPin是你实际的I2C总线引脚号。

2.对LVGL的接口方面

前面我们已经搞清楚了,LVGL是通过my_touchpad_read()这个函数读取触摸屏输入数据的。那触摸屏驱动就要对接这个接口,把触摸数据传给LVGL。

(1)首先,my_touchpad_read()中:

if (touch_6336.available())

这句是调用触摸屏驱动中的available()函数,让其返回是否有触摸事件发生。那么触摸屏驱动中必须要有这个available()方法才行。

然而,不幸的是,FT6336U.cpp中并没有这个函数,那么就需要我们自己添加了。

这里我们参考CST816触摸屏的驱动,采用注册中断的方式,来实现一个available()方法。

首先,FT6336U触摸屏是有INT引脚的,应该说绝大部分触摸屏都有这个引脚,作用是有触摸事件发生时通知CPU。

顺便提一句,触摸屏大都有两种工作模式:中断模式扫描模式。中断模式是在有输入时通过中断引脚通知CPU,然后CPU读取触摸数据;扫描模式是CPU一直不停的读取触摸屏数据,有触摸时CPU自然会读取到。显而易见,中断模式更加节省CPU的开销。

用中断方式实现available()方法我们添加如下代码:

void IRAM_ATTR FT6336U::handleISR(void) {
  _event_available = true;

}

bool FT6336U::available(void) {
  if (_event_available) {
    //read_touch();
    _event_available = false;
    return true;
  }
  return false;
}

并且把begin()函数给更改一下:

bool FT6336U::begin(void)
{//modifyied by fat0x
  _i2cPort->begin(_SDAPin,_SCLPin); 
  if(read_device_type() == 0x02)
  {
    writeByte(0x02, 0x01);
    attachInterrupt(_INTPin, std::bind(&FT6336U::handleISR, this), FALLING);
    return true;
  }
  return false;
}

handleISR是一个中断服务函数,发生中断时把_event_available置位。

begin()函数中,我们增加attachInterrupt(),在硬件层面注册一个中断服务函数,其中_INTPin就是触摸屏的INT引脚连接到CPU的引脚号;handleISR是中断服务函数名;FALLING是定义有引脚上电平变化的哪种类型触发该中断,FALLING是电平下降沿。

最后available()函数就是在LVGL调用时,如果有中断就返回true给LVGL了。

(2)my_touchpad_read中读取触摸坐标数据

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{
  if (touch_6336.available())
  {
    data->state = LV_INDEV_STATE_PR;
    data->point.x = touch_6336.touchPoint.tp[0].x;
    data->point.y = touch_6336.touchPoint.tp[0].y;
  }
  else
  {
    data->state = LV_INDEV_STATE_REL;
  }
}

注意到my_touchpad_read中,一旦available()返回true,LVGL就会读取触摸屏对象中保存的坐标数据。这意味着,触摸屏驱动需要在中断发生的时候,就在硬件层面去读取数据,然后把数据提前保存到对象中,LVGL才能读取到。

那么available()函数中就需要增加读取坐标的代码了(下面代码中的scan()):

bool FT6336U::available(void) {
  if (_event_available) {
    scan();
    _event_available = false;
    return true;
  }
  return false;
}

scan()函数是驱动的作者写好的,作用是读取触摸坐标,并且保存到类中定义的两个对象数据touchPoint.tp[0].x和touchPoint.tp[0].y中。所以我们在my_touchpad_read()函数中是这两行代码:

    data->point.x = touch_6336.touchPoint.tp[0].x;
    data->point.y = touch_6336.touchPoint.tp[0].y;

OK,整个驱动的改造就基本结束了。

三、修改过的完整代码

1.FT6336U.h

/**************************************************************************/
/*!
  @file     FT6336U.h
  Author: Atsushi Sasaki(https://github.com/aselectroworks)
  License: MIT (see LICENSE)
*/
/**************************************************************************/

#ifndef _FT6336U_H__
#define _FT6336U_H__

#include <Arduino.h>
#include <Wire.h>

#define LIB_DEBUG 0
#if LIB_DEBUG > 0
  #define LIB_LOG(tag, ...)              \
    do                                   \
    {                                    \
      if (tag)                           \
      Serial.printf("#Debug ");        \
      Serial.printf("<%s> ", tag);       \
      Serial.printf(__VA_ARGS__);        \
      Serial.printf("\n");               \
    } while (0)
#else
  #define LIB_LOG(...)
#endif

#define I2C_ADDR_FT6336U                    0x38

#define FT6336U_PRES_DOWN                   0x02
#define FT6336U_COORD_UD                    0x01
#define FT6336U_ADDR_DEVICE_MODE 	          0x00
typedef enum 
{
  working_mode = 0b000, 
  factory_mode = 0b100, 
} DEVICE_MODE_Enum; 
#define FT6336U_ADDR_GESTURE_ID             0x01
#define FT6336U_ADDR_TD_STATUS 		          0x02

#define FT6336U_ADDR_TOUCH1_EVENT 	        0x03
#define FT6336U_ADDR_TOUCH1_ID 		          0x05
#define FT6336U_ADDR_TOUCH1_X 		          0x03
#define FT6336U_ADDR_TOUCH1_Y 		          0x05
#define FT6336U_ADDR_TOUCH1_WEIGHT          0x07
#define FT6336U_ADDR_TOUCH1_MISC            0x08

#define FT6336U_ADDR_TOUCH2_EVENT 	        0x09
#define FT6336U_ADDR_TOUCH2_ID 		          0x0B
#define FT6336U_ADDR_TOUCH2_X 		          0x09
#define FT6336U_ADDR_TOUCH2_Y 		          0x0B
#define FT6336U_ADDR_TOUCH2_WEIGHT          0x0D
#define FT6336U_ADDR_TOUCH2_MISC            0x0E

#define FT6336U_ADDR_THRESHOLD              0x80
#define FT6336U_ADDR_FILTER_COE             0x85
#define FT6336U_ADDR_CTRL                   0x86
typedef enum 
{
  keep_active_mode = 0, 
  switch_to_monitor_mode = 1, 
} CTRL_MODE_Enum; 
#define FT6336U_ADDR_TIME_ENTER_MONITOR     0x87
#define FT6336U_ADDR_ACTIVE_MODE_RATE       0x88
#define FT6336U_ADDR_MONITOR_MODE_RATE      0x89

#define FT6336U_ADDR_RADIAN_VALUE           0x91
#define FT6336U_ADDR_OFFSET_LEFT_RIGHT      0x92
#define FT6336U_ADDR_OFFSET_UP_DOWN         0x93
#define FT6336U_ADDR_DISTANCE_LEFT_RIGHT    0x94
#define FT6336U_ADDR_DISTANCE_UP_DOWN       0x95
#define FT6336U_ADDR_DISTANCE_ZOOM          0x96

#define FT6336U_ADDR_CIPHER_LOW				      0xA0
#define FT6336U_ADDR_LIBRARY_VERSION_H      0xA1
#define FT6336U_ADDR_LIBRARY_VERSION_L      0xA2
#define FT6336U_ADDR_CHIP_ID                0xA3
#define FT6336U_ADDR_G_MODE                 0xA4
typedef enum {
    pollingMode = 0, 
    triggerMode = 1, 
} G_MODE_Enum; 
#define FT6336U_ADDR_POWER_MODE             0xA5
#define FT6336U_ADDR_FIRMARE_ID             0xA6
#define FT6336U_ADDR_FOCALTECH_ID           0xA8
#define FT6336U_ADDR_RELEASE_CODE_ID        0xAF
#define FT6336U_ADDR_STATE                  0xBC

// Function Specific Type
typedef enum 
{
    touch = 0, 
    stream, 
    release, 
} TouchStatusEnum; 
typedef struct 
{
    TouchStatusEnum status; 
    uint16_t x; 
    uint16_t y; 
} TouchPointType;
typedef struct 
{
    uint8_t touch_count; 
    TouchPointType tp[2]; 
} FT6336U_TouchPointType; 

/**************************************************************************/
/*!
    @brief  FT6336U I2C CTP controller driver
*/
/**************************************************************************/
class FT6336U 
{
public: 
  FT6336U(int SDAPin, int SCLPin, int INTPin, TwoWire * wirePort);
  //bool begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = I2C_ADDR_FT6336U);
  bool begin(void);
  bool available(void);
  void IRAM_ATTR handleISR(void);

  uint8_t read_device_type(void);
  uint8_t read_device_mode(void);
  void write_device_mode(DEVICE_MODE_Enum);
  uint8_t read_gesture_id(void); 
  uint8_t read_td_status(void);
  uint8_t read_touch_number(void); 
  uint16_t read_touch1_x(void);
  uint16_t read_touch1_y(void);
  uint8_t read_touch1_event(void);
  uint8_t read_touch1_id(void);
  uint8_t read_touch1_weight(void);
  uint8_t read_touch1_misc(void);
  uint16_t read_touch2_x(void);
  uint16_t read_touch2_y(void);
  uint8_t read_touch2_event(void);
  uint8_t read_touch2_id(void);
  uint8_t read_touch2_weight(void);
  uint8_t read_touch2_misc(void);

  // Mode Parameter Register
  void write_power_mode(uint8_t mode);
  void write_monitor_mode_period(uint8_t mode);
  void disable_face_dec_mode();
  uint8_t read_touch_threshold(void); 
  uint8_t read_filter_coefficient(void); 
  uint8_t read_ctrl_mode(void); 
  void write_ctrl_mode(CTRL_MODE_Enum mode); 
  uint8_t read_time_period_enter_monitor(void); 
  void write_time_period_enter_monitor(uint8_t time);
  uint8_t read_active_rate(void); 
  uint8_t read_monitor_rate(void); 

  // Gestrue Parameter Register
  uint8_t read_radian_value(void); 
  void write_radian_value(uint8_t val); 
  uint8_t read_offset_left_right(void); 
  void write_offset_left_right(uint8_t val); 
  uint8_t read_offset_up_down(void); 
  void write_offset_up_down(uint8_t val); 
  uint8_t read_distance_left_right(void); 
  void write_distance_left_right(uint8_t val); 
  uint8_t read_distance_up_down(void); 
  void write_distance_up_down(uint8_t val); 
  uint8_t read_distance_zoom(void); 
  void write_distance_zoom(uint8_t val); 

  // System Information
  uint16_t read_library_version(void); 
  uint8_t read_chip_id(void); 
  uint8_t read_g_mode(void); 
  void write_g_mode(G_MODE_Enum mode); 
  uint8_t read_pwrmode(void); 
  uint8_t read_firmware_id(void);
  uint8_t read_focaltech_id(void); 
  uint8_t read_release_code_id(void); 
  uint8_t read_state(void); 

  // Scan Function
  FT6336U_TouchPointType scan(void);
  FT6336U_TouchPointType touchPoint; 

private:  
  
  TwoWire *_i2cPort; // The generic connection to user's chosen I2C hardware
  uint8_t _SDAPin;
  uint8_t _SCLPin;
  uint8_t _INTPin;

  uint8_t _deviceAddress;
  bool _event_available;  //added by fat0x

  uint8_t readByte(uint8_t addr); 
  void writeByte(uint8_t addr, uint8_t data); 

  
}; 
#endif

2.FT6336U.cpp

/**************************************************************************/
/*!
  @file     FT6336U.cpp
  Author: Atsushi Sasaki (https://github.com/aselectroworks)
  License: MIT (see LICENSE)
*/
/**************************************************************************/

#include "FT6336U.h"
#include <FunctionalInterrupt.h>

FT6336U::FT6336U(int SDAPin, int SCLPin, int INTPin, TwoWire * wirePort) 
  {
    _deviceAddress    = I2C_ADDR_FT6336U;
    _SDAPin           = uint8_t(SDAPin);
    _SCLPin           = uint8_t(SCLPin);
    _INTPin           = uint8_t(INTPin);
    _i2cPort          = wirePort;//Wire和wire1两个关键字是两条硬总线0/1,在wire.h中被固定定义了
  }

bool FT6336U::begin(void)
{//modifyied by fat0x
  _i2cPort->begin(_SDAPin,_SCLPin); 
  if(read_device_type() == 0x02)
  {
    writeByte(0x02, 0x01);
    attachInterrupt(_INTPin, std::bind(&FT6336U::handleISR, this), FALLING);
    return true;
  }
  return false;
}

/*added by fat0x begin*/
void IRAM_ATTR FT6336U::handleISR(void) {
  _event_available = true;

}

bool FT6336U::available(void) {
  if (_event_available) {
    scan();
    _event_available = false;
    return true;
  }
  return false;
}

/*added by fat0x end!*/


uint8_t FT6336U::read_device_type(void) 
{
    return readByte(FT6336U_ADDR_CIPHER_LOW);
}

uint8_t FT6336U::read_device_mode(void) 
{
    return (readByte(FT6336U_ADDR_DEVICE_MODE) & 0x70) >> 4;
}
void FT6336U::write_device_mode(DEVICE_MODE_Enum mode) 
{
    writeByte(FT6336U_ADDR_DEVICE_MODE, (mode & 0x07) << 4);
}
uint8_t FT6336U::read_gesture_id(void) 
{
    return readByte(FT6336U_ADDR_GESTURE_ID);
}
uint8_t FT6336U::read_td_status(void) 
{
    return readByte(FT6336U_ADDR_TD_STATUS);
}
uint8_t FT6336U::read_touch_number(void) 
{
    return readByte(FT6336U_ADDR_TD_STATUS) & 0x0F;
}
// Touch 1 functions
uint16_t FT6336U::read_touch1_x(void) 
{
    uint8_t read_buf[2];
    read_buf[0] = readByte(FT6336U_ADDR_TOUCH1_X);
    read_buf[1] = readByte(FT6336U_ADDR_TOUCH1_X + 1);
		return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
}
uint16_t FT6336U::read_touch1_y(void) 
{
		uint8_t read_buf[2];
		read_buf[0] = readByte(FT6336U_ADDR_TOUCH1_Y);
		read_buf[1] = readByte(FT6336U_ADDR_TOUCH1_Y + 1);
		return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
}
uint8_t FT6336U::read_touch1_event(void) 
{
    return readByte(FT6336U_ADDR_TOUCH1_EVENT) >> 6;
}
uint8_t FT6336U::read_touch1_id(void) 
{
    return readByte(FT6336U_ADDR_TOUCH1_ID) >> 4;
}
uint8_t FT6336U::read_touch1_weight(void) 
{
    return readByte(FT6336U_ADDR_TOUCH1_WEIGHT);
}
uint8_t FT6336U::read_touch1_misc(void) 
{
    return readByte(FT6336U_ADDR_TOUCH1_MISC) >> 4;
}
// Touch 2 functions
uint16_t FT6336U::read_touch2_x(void) 
{
    uint8_t read_buf[2];
    read_buf[0] = readByte(FT6336U_ADDR_TOUCH2_X);
    read_buf[1] = readByte(FT6336U_ADDR_TOUCH2_X + 1);
	return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
}
uint16_t FT6336U::read_touch2_y(void) 
{
    uint8_t read_buf[2];
    read_buf[0] = readByte(FT6336U_ADDR_TOUCH2_Y);
    read_buf[1] = readByte(FT6336U_ADDR_TOUCH2_Y + 1);
	return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
}
uint8_t FT6336U::read_touch2_event(void) 
{
    return readByte(FT6336U_ADDR_TOUCH2_EVENT) >> 6;
}
uint8_t FT6336U::read_touch2_id(void) 
{
    return readByte(FT6336U_ADDR_TOUCH2_ID) >> 4;
}
uint8_t FT6336U::read_touch2_weight(void) 
{
    return readByte(FT6336U_ADDR_TOUCH2_WEIGHT);
}
uint8_t FT6336U::read_touch2_misc(void) 
{
    return readByte(FT6336U_ADDR_TOUCH2_MISC) >> 4;
}

// Mode Parameter Register
void FT6336U::write_power_mode(uint8_t mode) 
{
    writeByte(FT6336U_ADDR_POWER_MODE, mode);
}

void FT6336U::write_monitor_mode_period(uint8_t mode) 
{
    writeByte(FT6336U_ADDR_MONITOR_MODE_RATE, mode);
}

void FT6336U::disable_face_dec_mode() 
{
    writeByte(0xB0, 0x00);
}

uint8_t FT6336U::read_touch_threshold(void) 
{
    return readByte(FT6336U_ADDR_THRESHOLD);
}
uint8_t FT6336U::read_filter_coefficient(void) 
{
    return readByte(FT6336U_ADDR_FILTER_COE);
}
uint8_t FT6336U::read_ctrl_mode(void) 
{
    return readByte(FT6336U_ADDR_CTRL);
}
void FT6336U::write_ctrl_mode(CTRL_MODE_Enum mode) 
{
    writeByte(FT6336U_ADDR_CTRL, mode);
}
uint8_t FT6336U::read_time_period_enter_monitor(void) 
{
    return readByte(FT6336U_ADDR_TIME_ENTER_MONITOR);
}
void FT6336U::write_time_period_enter_monitor(uint8_t time) 
{
    writeByte(FT6336U_ADDR_TIME_ENTER_MONITOR, time);
}

uint8_t FT6336U::read_active_rate(void) 
{
    return readByte(FT6336U_ADDR_ACTIVE_MODE_RATE);
}
uint8_t FT6336U::read_monitor_rate(void) 
{
    return readByte(FT6336U_ADDR_MONITOR_MODE_RATE);
}

// Gesture Parameters
uint8_t FT6336U::read_radian_value(void) 
{
	return readByte(FT6336U_ADDR_RADIAN_VALUE);
}
void FT6336U::write_radian_value(uint8_t val) 
{
	writeByte(FT6336U_ADDR_RADIAN_VALUE, val); 
}
uint8_t FT6336U::read_offset_left_right(void) 
{
	return readByte(FT6336U_ADDR_OFFSET_LEFT_RIGHT);
}
void FT6336U::write_offset_left_right(uint8_t val) 
{
	writeByte(FT6336U_ADDR_OFFSET_LEFT_RIGHT, val); 
}
uint8_t FT6336U::read_offset_up_down(void) 
{
	return readByte(FT6336U_ADDR_OFFSET_UP_DOWN);
}
void FT6336U::write_offset_up_down(uint8_t val) 
{
	writeByte(FT6336U_ADDR_OFFSET_UP_DOWN, val); 
}
uint8_t FT6336U::read_distance_left_right(void) 
{
	return readByte(FT6336U_ADDR_DISTANCE_LEFT_RIGHT);
}
void FT6336U::write_distance_left_right(uint8_t val) 
{
	writeByte(FT6336U_ADDR_DISTANCE_LEFT_RIGHT, val); 
}
uint8_t FT6336U::read_distance_up_down(void) 
{
	return readByte(FT6336U_ADDR_DISTANCE_UP_DOWN);
}
void FT6336U::write_distance_up_down(uint8_t val) 
{
	writeByte(FT6336U_ADDR_DISTANCE_UP_DOWN, val); 
}
uint8_t FT6336U::read_distance_zoom(void) 
{
	return readByte(FT6336U_ADDR_DISTANCE_ZOOM);
}
void FT6336U::write_distance_zoom(uint8_t val) 
{
	writeByte(FT6336U_ADDR_DISTANCE_ZOOM, val); 
}


// System Information
uint16_t FT6336U::read_library_version(void) 
{
    uint8_t read_buf[2];
    read_buf[0] = readByte(FT6336U_ADDR_LIBRARY_VERSION_H);
    read_buf[1] = readByte(FT6336U_ADDR_LIBRARY_VERSION_L);
	return ((read_buf[0] & 0x0f) << 8) | read_buf[1];
}
uint8_t FT6336U::read_chip_id(void) 
{
    return readByte(FT6336U_ADDR_CHIP_ID);
}
uint8_t FT6336U::read_g_mode(void) 
{
    return readByte(FT6336U_ADDR_G_MODE);
}
void FT6336U::write_g_mode(G_MODE_Enum mode)
{
	writeByte(FT6336U_ADDR_G_MODE, mode); 
}
uint8_t FT6336U::read_pwrmode(void) 
{
    return readByte(FT6336U_ADDR_POWER_MODE);
}
uint8_t FT6336U::read_firmware_id(void) 
{
    return readByte(FT6336U_ADDR_FIRMARE_ID);
}
uint8_t FT6336U::read_focaltech_id(void) 
{
    return readByte(FT6336U_ADDR_FOCALTECH_ID);
}
uint8_t FT6336U::read_release_code_id(void) 
{
    return readByte(FT6336U_ADDR_RELEASE_CODE_ID);
}
uint8_t FT6336U::read_state(void) 
{
    return readByte(FT6336U_ADDR_STATE);
}


//coordinate diagram(FPC downwards)
y 264x176
						//
						//
						//x
						//
						//
FT6336U_TouchPointType FT6336U::scan(void){
    touchPoint.touch_count = read_td_status(); 

    if(touchPoint.touch_count == 0) {
        touchPoint.tp[0].status = release; 
        touchPoint.tp[1].status = release; 
    }
    else if(touchPoint.touch_count == 1) {
        uint8_t id1 = read_touch1_id(); // id1 = 0 or 1
        touchPoint.tp[id1].status = (touchPoint.tp[id1].status == release) ? touch : stream; 
        touchPoint.tp[id1].x = read_touch1_x(); 
        touchPoint.tp[id1].y = read_touch1_y(); 
        touchPoint.tp[~id1 & 0x01].status = release; 
    }
    else {
        uint8_t id1 = read_touch1_id(); // id1 = 0 or 1
        touchPoint.tp[id1].status = (touchPoint.tp[id1].status == release) ? touch : stream; 
        touchPoint.tp[id1].x = read_touch1_x(); 
        touchPoint.tp[id1].y = read_touch1_y(); 
        uint8_t id2 = read_touch2_id(); // id2 = 0 or 1(~id1 & 0x01)
        touchPoint.tp[id2].status = (touchPoint.tp[id2].status == release) ? touch : stream; 
        touchPoint.tp[id2].x = read_touch2_x(); 
        touchPoint.tp[id2].y = read_touch2_y(); 
    }

    return touchPoint; 

}


// Private Function
uint8_t FT6336U::readByte(uint8_t addr) 
{
  uint8_t rdData = 0; 
  uint8_t rdDataCount; 
  do {
    _i2cPort->beginTransmission(_deviceAddress); 
    _i2cPort->write(addr); 
    _i2cPort->endTransmission(false); // Restart
    delay(10); 
    rdDataCount = _i2cPort->requestFrom(_deviceAddress, 1); 
  } while(rdDataCount == 0); 
  if(_i2cPort->available()) 
  {
    rdData = _i2cPort->read(); 
  }
  return rdData; 
}
void FT6336U::writeByte(uint8_t addr, uint8_t data) 
{
  _i2cPort->beginTransmission(_deviceAddress); 
  _i2cPort->write(addr); 
  _i2cPort->write(data); 
  _i2cPort->endTransmission(); 
}

3.arduino中的调用代码

#include "FT6336U.h"

FT6336U touch_6336(5,4,7,&Wire);//Wire是0号总线,引脚号根据实际连线修改

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{
  if (touch_6336.available())
  {
    data->state = LV_INDEV_STATE_PR;
    data->point.x = touch_6336.touchPoint.tp[0].x;
    data->point.y = touch_6336.touchPoint.tp[0].y;
  }
  else
  {
    data->state = LV_INDEV_STATE_REL;
  }
}

void setup()
{
  touch_6336.begin();

  /*Initialize the (dummy) input device driver*/
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = my_touchpad_read;
  lv_indev_drv_register(&indev_drv);
}

arduino中其他LVGL代码我没有全部贴,因为和本驱动无关。

4.坐标的调整

最后,说一个点,屏幕旋转的问题。

触摸屏传回的坐标是根据屏幕的大小来的。比如240*320的屏幕,成品的触摸屏传回给你的x和y坐标一定是在0-239,0-319之间的。

但是x和y是需要根据你屏幕的旋转的改变的。比如屏幕出厂默认是竖屏,你使用时改成了横屏显示,那么你的触摸屏驱动里也要把x和y做相应的调整,LVGL中的触摸功能才能正常使用,否则触摸就是乱的。

全文完结。

  • 33
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果在Arduino ESP32上使用LVGL时,手指一直触摸屏幕时,可以通过过滤处理触摸事件来避免触摸事件的积压和重复响应。 一种处理方法是设置一个时间阈值,只有手指触摸屏幕的时间大于阈值时才响应触摸事件,否则忽略该触摸事件。可以使用lv_tick_get()函数获取当前时间,并记录手指触摸屏幕的起始时间。如果手指离开屏幕的时间减去起始时间大于阈值,则响应触摸事件,否则忽略该触摸事件。示例代码如下: ```C++ void loop() { lv_task_handler(); // 处理LVGL任务,包括触摸事件 lv_indev_t *indev = lv_indev_get_act(); // 获取当前活动的输入设备 lv_indev_data_t data; // 存储输入设备的数据 lv_indev_read(indev, &data); // 读取输入设备的数据 static uint32_t start_time = 0; // 记录手指触摸屏幕的起始时间 const uint32_t threshold = 500; // 时间阈值,单位为毫秒 if (data.state == LV_INDEV_STATE_PR) { // 手指按下屏幕 start_time = lv_tick_get(); // 记录手指触摸屏幕的起始时间 } else if (data.state == LV_INDEV_STATE_REL) { // 手指离开屏幕 uint32_t end_time = lv_tick_get(); // 获取手指离开屏幕的时间 if (end_time - start_time > threshold) { // 手指触摸屏幕的时间大于阈值 lv_indev_finish(indev); // 处理触摸事件 } } // 其他代码 } ``` 在处理完触摸事件后,程序会检查手指触摸屏幕的时间是否大于阈值,如果大于阈值,则响应触摸事件,否则忽略该触摸事件。这样就可以过滤处理触摸事件,避免触摸事件的积压和重复响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值