图40.3.3.2 正点原子 LCD上的GT9XX触摸芯片通讯接口
gt9xxx_init的实现也比较简单,实现CT_INT引脚初始化,调用其IIC初始化接口即可。
同样地,我们需要通过IIC来读取触摸点的物理坐标,由于电容屏在设计时是根据屏幕进行参数设计的,参数已经保存在gt9xxx芯片的内部了,我们只需要按手册推荐的IIC时序把对应的XY坐标读出来,转换成LCD的像素坐标即可。gt9xx系列可以通过中断或轮询方式读限,我们使用的是轮询方式:
1,按第二节时序,先读取寄存器0x814E,若当前buffer(buffer status为1)数据准备好,则依据手指个数读、按键状态取相应个数的坐标、按键信息。
2,若在1中发现buffer数据(buffer status为0)未准备好,则等待1ms再进行读取。这样,gt9xxx_scan()函数的实现如下:
/* GT9XXX 10个触摸点(最多) 对应的寄存器表 */
const uint16_t GT9XXX_TPX_TBL[10] =
{
GT9XXX_TP1_REG,
GT9XXX_TP2_REG,
GT9XXX_TP3_REG,
GT9XXX_TP4_REG,
GT9XXX_TP5_REG,
GT9XXX_TP6_REG,
GT9XXX_TP7_REG,
GT9XXX_TP8_REG,
GT9XXX_TP9_REG,
GT9XXX_TP10_REG,
};
/**
* @param mode : 电容屏未用到次参数, 为了兼容电阻屏 * @retval 当前触屏状态
* @arg 1, 触屏有触摸;
*/
uint8_t gt9xxx_scan(uint8_t mode)
{
uint8_t buf[4];
uint8_t i = 0;
uint8_t res = 0;
uint16_t temp;
uint16_t tempsta;
static uint8_t t = 0; /* 控制查询间隔,从而降低CPU占用率 */
t++;
/* 空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率 */
if ((t % 10) == 0 || t < 10)
{
gt9xxx_rd_reg(GT9XXX_GSTID_REG, &mode, 1); /* 读取触摸点的状态 */
if ((mode & 0X80) && ((mode & 0XF) <= g_gt_tnum))
{
i = 0;
gt9xxx_wr_reg(GT9XXX_GSTID_REG, &i, 1);/* 清标志 */
}
if ((mode & 0XF) && ((mode & 0XF) <= g_gt_tnum))
{
/* 将点的个数转换为1的位数,匹配tp_dev.sta定义 */
temp = 0XFFFF << (mode & 0XF);
tempsta = tp_dev.sta; /* 保存当前的tp_dev.sta值 */
tp_dev.sta = (~temp) | TP_PRES_DOWN | TP_CATH_PRES;
/* 保存触点0的数据,保存在最后一个上 */
tp_dev.x[g_gt_tnum - 1] = tp_dev.x[0];
tp_dev.y[g_gt_tnum - 1] = tp_dev.y[0];
for (i = 0; i < g_gt_tnum; i++)
{
if (tp_dev.sta & (1 << i)) /* 触摸有效? */
{
gt9xxx_rd_reg(GT9XXX_TPX_TBL, buf, 4);/* 读取XY坐标值 */
if (tp_dev.touchtype & 0X01) /* 横屏 */
{
tp_dev.x = ((uint16_t)buf[1] << 8) + buf[0];
tp_dev.y = ((uint16_t)buf[3] << 8) + buf[2];
}
else /* 竖屏 */
{
tp_dev.x = ltdcdev.width –
(((uint16_t)buf[3] << 8) + buf[2]);
tp_dev.y = ((uint16_t)buf[1] << 8) + buf[0];
}
}
}
res = 1;
/* 非法数据(坐标超出了) */
if (tp_dev.x[0] > ltdcdev.width || tp_dev.y[0] > ltdcdev.height)
{
/* 有其他点有数据,则复第二个触点的数据到第一个触点. */
if ((mode & 0XF) > 1)
{
tp_dev.x[0] = tp_dev.x[1];
tp_dev.y[0] = tp_dev.y[1];
t = 0;/* 触发一次,则会最少连续监测10次,从而提高命中率 */
}
else /* 非法数据,则忽略此次数据(还原原来的) */
{
tp_dev.x[0] = tp_dev.x[g_gt_tnum - 1];
tp_dev.y[0] = tp_dev.y[g_gt_tnum - 1];
mode = 0X80;
tp_dev.sta = tempsta; /* 恢复tp_dev.sta */
}
}
else
{
t = 0;/* 触发一次,则会最少连续监测10次,从而提高命中率 */
}
}
}
if ((mode & 0X8F) == 0X80) /* 无触摸点按下 */
{
if (tp_dev.sta & TP_PRES_DOWN) /* 之前是被按下的 */
{
tp_dev.sta &= ~TP_PRES_DOWN; /* 标记按键松开 */
}
else /* 之前就没有被按下 */
{
tp_dev.x[0] = 0xffff;
tp_dev.y[0] = 0xffff;
tp_dev.sta &= 0XE000; /* 清除点有效标记 */
}
if (t > 240)
{
t = 10; /* 重新从10开始计数 */
}
return res;
}
接下来是触摸初始化的核心程序,我们根据前面介绍的知识点,可以知道触摸的参数与屏幕大小和使用的触摸芯片有关,我们的4.3寸屏使用的是汇顶科技的GT9xxx系列触摸屏驱动IC,这是一个IIC接口的驱动芯片,我们要编写gt9xxx系列芯片的初始化程序,并编写一个坐标扫描程序,这里我们先预留这两个接口分别为gt9xxx_init()和gt9xxx_scan(),在gt9xxx.c文件中再专门实现这两个驱动,标记使用的为电容屏。
/**
* @brief 触摸屏初始化
* @param 无
* @retval 0,触摸屏初始化成功
* 1,触摸屏有问题
*/
uint8_t tp_init(void)
{
tp_dev.touchtype = 0; /* 默认设置(电阻屏 & 竖屏) */
tp_dev.touchtype |= ltdcdev.dir & 0X01; /* 根据LCD判定是横屏还是竖屏 */
if (ltdcdev.id == 0X4342 || ltdcdev.id == 0X4384)/* 电容触摸屏,4.3寸屏 */
{
gt9xxx_init();
tp_dev.scan = gt9xxx_scan; /* 扫描函数指向GT触摸屏扫描 */
tp_dev.touchtype |= 0X80; /* 电容屏 */
return 0;
}
return 1;
}
正点原子的电容屏在出厂时已经由厂家较对好参数了,通过上面的触摸初始化后,我们就可以读取相关的触点信息用于显示编程了。
34.3.4 CMakeLists.txt文件
打开本实验BSP下的CMakeLists.txt文件,其内容如下所示:
set(src_dirs
IIC
LED
RGBLCD
TOUCH
XL9555)
set(include_dirs
IIC
LED
RGBLCD
TOUCH
XL9555)
set(requires
driver
esp_lcd
esp_common
log)
idf_component_register(SRC_DIRS ${src_dirs}
INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
上述的红色TOUCH驱动需要由开发者自行添加,以确保TOUCH驱动能够顺利集成到构建系统中。这一步骤是必不可少的,它确保了TOUCH驱动的正确性和可用性,为后续的开发工作提供了坚实的基础。
34.3.5 实验应用代码
打开main/main.c文件,该文件定义了工程入口函数,名为app_main。该函数代码如下。
i2c_obj_t i2c0_master;
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t ret;
ret = nvs_flash_init(); s/* 初始化NVS */
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
i2c0_master = iic_init(I2C_NUM_0); /* 初始化IIC0 */
xl9555_init(i2c0_master); /* 初始化XL9555 */
ltdc_init(); /* 初始化ltdc */
tp_dev.init(); /* 初始化触摸屏 */
load_draw_dialog();
ctp_test();
}
以上就是main函数的主要组成部分。
34.4 下载验证
在代码编译成功之后,我们通过下载代码到开发板上,触摸屏测试如下图所示界面:
图34.4.1 触摸屏测试界面
图中,作者在触摸板绘画“ALIENTEK”字符串。按右上角的RST标志,可以清屏。