【LTDC】RGB LCD 电容触摸屏的配置和程序
引言
配置好 RGB LCD 的显示之后,就可以配置其触摸的功能了。电容触摸屏的驱动方式格外的简单,下面由我一一道来(触摸检测的本质上就是电容交互式的感应,然后通过 IC 的通讯协议来传输寄存器上的数据。
主控板
STM32H743开发板 核心板 小系统板 反客 STM32H743IIT6

屏幕
正点原子 4.3寸 RGB LCD 交互电容式接触显示屏 ST7262E43
正点原子的屏幕要接上反客的 RGB 接口则需要一个转接板,可以自己花,当然反客家也有,需要单独购买。

触摸屏 IC:GT1151Q
数据手册:
编程指南:
触控引脚
主控引脚
不同主控板的引脚位置会有所不同,我使用的是反客家的 STM32H743IIT6,这里使用的引脚是:
TOUCH_RST ---- PH4(复位引脚)
TOUCH_INT ---- PG3(中断引脚)
TOUCH_SCLK ---- PI11(IIC 时钟线)
TOUCH_SDA ---- PI8(IIC 数据线)
下图是反客所提供的接口原理图:

CubeMX 配置
查看了一下触控对应引脚的功能,发现并没有复用做 IIC 功能的,说明我们需要使用软件 IIC 去读取触摸的数据。

SDA ---- 开漏输出 低速 上拉
SCL ---- 开漏输出 低速 上拉
RST ---- 推挽输出 超高速 上拉
INT ---- 输入模式 浮空
- 由于在配置中 SDA 对应引脚只有低速模式,为了匹配 SDA 的速度保证通讯的稳定性,SCL 也选择了低速,而且也只是读取触摸数据,50MHz 也足够用了。
- 复位引脚初始化为上拉,方便后续拉低来复位。
- INT 为中断引脚,给主控芯片发送中断读取信号,如果要使用的话,这个引脚则要开启 EXTI,否则就是单纯的阻塞式读取。
程序编写
这个 IC 厂家提供了一份编程指南(在上面),我们可以跟着写就好,假如对于商家提供的已经写好的驱动程序,我们配合着这个指南,也更好理解。下面是我修改好的程序,想要读懂程序则需要配合着此 IC 手册和指南,要熟悉 IC 中的某些寄存器,程序大体上无非就是:读取 IC 寄存器、写入 IC 寄存器、初始化接口程序,以及扫描读取程序。仔细阅读下来半个小时就明白了!
touch_800x480.c
点击查看代码
#include "touch_800x480.h"
GTXXXX_TouchTypeDef gtxxxx_dev; /* 触摸屏设备结构体 */
/* 注意: 除了GT9271支持10点触摸之外, 其他触摸芯片只支持 5点触摸 */
volatile uint8_t g_gt_tnum = 5; /* 默认支持的触摸屏点数(5点触摸) */
/* GTXXXX 10个触摸点(最多) 对应的寄存器表 */
const uint16_t GTXXXX_TPX_TBL[10] =
{
GTXXXX_TP1_REG,
GTXXXX_TP2_REG,
GTXXXX_TP3_REG,
GTXXXX_TP4_REG,
GTXXXX_TP5_REG,
GTXXXX_TP6_REG,
GTXXXX_TP7_REG,
GTXXXX_TP8_REG,
GTXXXX_TP9_REG,
GTXXXX_TP10_REG,
};
/**
* @brief 向GTXXXX写入一次数据
* @param reg : 起始寄存器地址
* @param buf : 数据缓缓存区
* @param len : 写数据长度
* @retval 0, 成功; 1, 失败;
*/
uint8_t gtxxxx_wr_reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
uint8_t i;
uint8_t ret = 0;
bsp_iic_start();
bsp_iic_send_byte(GTXXXX_CMD_WR); /* 发送写命令 */
bsp_iic_wait_ack();
bsp_iic_send_byte(reg >> 8); /* 发送高8位地址 */
bsp_iic_wait_ack();
bsp_iic_send_byte(reg & 0XFF); /* 发送低8位地址 */
bsp_iic_wait_ack();
for (i = 0; i < len; i++)
{
bsp_iic_send_byte(buf[i]); /* 发数据 */
ret = bsp_iic_wait_ack();
if (ret)
break;
}
bsp_iic_stop(); /* 产生一个停止条件 */
return ret;
}
/**
* @brief 从GTXXXX读出一次数据
* @param reg : 起始寄存器地址
* @param buf : 数据缓缓存区
* @param len : 读数据长度
* @retval 无
*/
void gtxxxx_rd_reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
uint8_t i;
bsp_iic_start();
bsp_iic_send_byte(GTXXXX_CMD_WR); /* 发送写命令 */
bsp_iic_wait_ack();
bsp_iic_send_byte(reg >> 8); /* 发送高8位地址 */
bsp_iic_wait_ack();
bsp_iic_send_byte(reg & 0XFF); /* 发送低8位地址 */
bsp_iic_wait_ack();
bsp_iic_start();
bsp_iic_send_byte(GTXXXX_CMD_RD); /* 发送读命令 */
bsp_iic_wait_ack();
for (i = 0; i < len; i++)
{
buf[i] = bsp_iic_read_byte(i == (len - 1) ? 0 : 1); /* 读取数据 */
}
bsp_iic_stop(); /* 产生一个停止条件 */
}
/**
* @brief 初始化GTXXXX触摸屏
* @param 无
* @retval 0, 初始化成功; 1, 初始化失败;
*/
uint8_t gtxxxx_init(void)
{
///////////////// 复位操作 /////////////////
bsp_iic_init(); /* 初始化电容屏的I2C总线 */
GTXXXX_RST(0); /* 复位 */
delay_ms(10); /* 复位保持10ms以上 */
GTXXXX_RST(1); /* 释放复位 */
delay_ms(40); /* 最低40ms,否则以上操作不成功,后续无法读取 */
///////////////// 读取id /////////////////
gtxxxx_rd_reg(GTXXXX_PID_REG, gtxxxx_dev.id, ID_LENGTH); /* 读取产品ID */
/* 判断一下是否是特定的触摸屏 */
if (strcmp((char *)gtxxxx_dev.id, "911") && strcmp((char *)gtxxxx_dev.id, "9147") && strcmp((char *)gtxxxx_dev.id, "1158") && strcmp((char *)gtxxxx_dev.id, "9271"))
{
return 1; /* 若不是触摸屏用到的GT911/9147/1158/9271,则初始化失败,需硬件查看触摸IC型号以及查看时序函数是否正确 */
}
printf("CTP ID:%s\r\n", gtxxxx_dev.id); /* 打印ID */
if (strcmp((char *)gtxxxx_dev.id, "9271") == 0) /* 假如ID==9271, 支持10点触摸 */
g_gt_tnum = 10; /* 支持10点触摸屏 */
gtxxxx_dev.id[0] = 0X02; /* 差值原始值(校准) */
gtxxxx_wr_reg(GTXXXX_CTRL_REG, gtxxxx_dev.id, 1); /* 软复位GTXXXX */
delay_ms(10); /* 复位后延时 */
gtxxxx_dev.id[0] = 0X00; /* 读坐标状态 */
gtxxxx_wr_reg(GTXXXX_CTRL_REG, gtxxxx_dev.id, 1); /* 结束复位, 进入读坐标状态 */
return 0;
}
/**
* @brief 扫描触摸屏(采用查询方式)
* @param 无
*/
uint8_t gtxxxx_scan(void)
{
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++;
if ((t % 10) == 0 || t < 10) /* 空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率 */
{
gtxxxx_rd_reg(GTXXXX_GSTID_REG, &mode, 1); /* 读取触摸点的状态 */
if ((mode & 0X80) && ((mode & 0XF) <= g_gt_tnum)) /* 触点数量小于g_gt_tnum == 5 */
{
i = 0;
gtxxxx_wr_reg(GTXXXX_GSTID_REG, &i, 1); /* 清标志 */
}
if ((mode & 0XF) && ((mode & 0XF) <= g_gt_tnum)) /* 触点数量小于g_gt_tnum == 5 */
{
temp = 0XFFFF << (mode & 0XF); /* 将点的个数转换为1的位数,匹配tp_dev.sta定义 */
printf("temp = %X\r\n", temp); /* 调试:temp*/
tempsta = gtxxxx_dev.sta; /* 保存当前的tp_dev.sta值 */
gtxxxx_dev.sta = (~temp) | TP_PRES_DOWN | TP_CATH_PRES;
gtxxxx_dev.x[g_gt_tnum - 1] = gtxxxx_dev.x[0]; /* 保存触点0的数据,保存在最后一个上 */
gtxxxx_dev.y[g_gt_tnum - 1] = gtxxxx_dev.y[0];
for (i = 0; i < g_gt_tnum; i++)
{
if (gtxxxx_dev.sta & (1 << i)) /* 触摸有效? */
{
/* 读取XY坐标值 */
gtxxxx_rd_reg(GTXXXX_TPX_TBL[i], buf, 4);
gtxxxx_dev.x[i] = ((uint16_t)buf[1] << 8) + buf[0];
gtxxxx_dev.y[i] = ((uint16_t)buf[3] << 8) + buf[2];
printf("x[%d]:%d,y[%d]:%d\r\n", i, gtxxxx_dev.x[i], i, gtxxxx_dev.y[i]);
}
}
printf("被按下后状态变化\r\n");
printf("sta & (TP_PRES_DOWN >> 15) = %X\r\n", gtxxxx_dev.sta & (TP_PRES_DOWN >> 15));
res = 1;
if (gtxxxx_dev.x[0] > PWIDTH || gtxxxx_dev.y[0] > PHEIGHT) /* 非法数据(坐标超出了) */
{
if ((mode & 0XF) > 1) /* 有其他点有数据,则复第二个触点的数据到第一个触点. */
{
gtxxxx_dev.x[0] = gtxxxx_dev.x[1];
gtxxxx_dev.y[0] = gtxxxx_dev.y[1];
t = 0; /* 触发一次,则会最少连续监测10次,从而提高命中率 */
}
else /* 非法数据,则忽略此次数据(还原原来的) */
{
gtxxxx_dev.x[0] = gtxxxx_dev.x[g_gt_tnum - 1];
gtxxxx_dev.y[0] = gtxxxx_dev.y[g_gt_tnum - 1];
mode = 0X80;
gtxxxx_dev.sta = tempsta; /* 还原sta状态 */
}
}
else
{
t = 0; /* 触发一次,则会最少连续监测10次,从而提高命中率 */
}
}
}
if ((mode & 0X8F) == 0X80) /* 无触摸点按下 */
{
if (gtxxxx_dev.sta & (TP_PRES_DOWN >> 15)) /* 之前是被按下的 */
{
gtxxxx_dev.sta &= ~(TP_PRES_DOWN >> 15); /* 标记按键松开 */
printf("被按下后再标记按键松开状态\r\n");
printf("sta & (TP_PRES_DOWN >> 15) = %X\r\n", gtxxxx_dev.sta & (TP_PRES_DOWN >> 15));
}
else /* 之前就没有被按下 */
{
gtxxxx_dev.x[0] = 0xffff;
gtxxxx_dev.y[0] = 0xffff;
gtxxxx_dev.sta &= 0XE000; /* 清除点有效标记 */
}
}
if (t > 240)
t = 10; /* 重新从10开始计数 */
return res;
}
touch_800x480.h
点击查看代码
#ifndef __TOUCH_800X480_H__
#define __TOUCH_800X480_H__
#include "headers.h"
#define TP_PRES_DOWN 0x8000 /* 触屏被按下 */
#define TP_CATH_PRES 0x4000 /* 有按键按下了 */
#define CT_MAX_TOUCH 10 /* 电容屏支持的点数,固定为5点 */
#define ID_LENGTH 4 /* 4字节ID */
/* GTXXXX INT 和 RST 引脚 定义 */
#define GTXXXX_RST_GPIO_PORT GPIOH
#define GTXXXX_RST_GPIO_PIN GPIO_PIN_4
#define GTXXXX_RST_GPIO_CLK_ENABLE() \
do \
{ \
__HAL_RCC_GPIOI_CLK_ENABLE(); \
} while (0) /* PI口时钟使能 */
#define GTXXXX_INT_GPIO_PORT GPIOG
#define GTXXXX_INT_GPIO_PIN GPIO_PIN_3
#define GTXXXX_INT_GPIO_CLK_ENABLE() \
do \
{ \
__HAL_RCC_GPIOH_CLK_ENABLE(); \
} while (0) /* PH口时钟使能 */
/* 与电容触摸屏连接的芯片引脚(未包含IIC引脚)
* IO操作函数
*/
#define GTXXXX_RST(x) \
do \
{ \
x ? HAL_GPIO_WritePin(TOUCH_RST_GPIO_Port, TOUCH_RST_Pin, GPIO_PIN_SET) : HAL_GPIO_WritePin(TOUCH_RST_GPIO_Port, TOUCH_RST_Pin, GPIO_PIN_RESET); \
} while (0) /* 复位引脚 */
#define GTXSXXX_INT HAL_GPIO_ReadPin(TOUCH_INT_GPIO_Port, TOUCH_INT_Pin) /* 读取中断引脚 */
/* IIC读写命令 */
#define GTXXXX_CMD_WR 0X28 /* 写命令 */
#define GTXXXX_CMD_RD 0X29 /* 读命令 */
/* GT9XXX 部分寄存器定义 */
#define GTXXXX_CTRL_REG 0X8040 /* GTXXXX控制寄存器 */
#define GTXXXX_CFGS_REG 0X8047 /* GTXXXX配置起始地址寄存器 */
#define GTXXXX_CHECK_REG 0X80FF /* GTXXXX校验和寄存器 */
#define GTXXXX_PID_REG 0X8140 /* GTXXXX产品ID寄存器 */
#define GTXXXX_GSTID_REG 0X814E /* GTXXXX当前检测到的触摸情况 */
#define GTXXXX_TP1_REG 0X8150 /* 第一个触摸点数据地址 */
#define GTXXXX_TP2_REG 0X8158 /* 第二个触摸点数据地址 */
#define GTXXXX_TP3_REG 0X8160 /* 第三个触摸点数据地址 */
#define GTXXXX_TP4_REG 0X8168 /* 第四个触摸点数据地址 */
#define GTXXXX_TP5_REG 0X8170 /* 第五个触摸点数据地址 */
/* 仅仅9271支持十个触点 */
#define GTXXXX_TP6_REG 0X8178 /* 第六个触摸点数据地址 */
#define GTXXXX_TP7_REG 0X8180 /* 第七个触摸点数据地址 */
#define GTXXXX_TP8_REG 0X8188 /* 第八个触摸点数据地址 */
#define GTXXXX_TP9_REG 0X8190 /* 第九个触摸点数据地址 */
#define GTXXXX_TP10_REG 0X8198 /* 第十个触摸点数据地址 */
typedef struct
{
uint16_t x[CT_MAX_TOUCH]; /* 触摸点X坐标 */
uint16_t y[CT_MAX_TOUCH]; /* 触摸点Y坐标 */
uint16_t last_x[CT_MAX_TOUCH]; /* 上一次触摸点X坐标 */
uint16_t last_y[CT_MAX_TOUCH]; /* 上一次触摸点Y坐标 */
uint8_t sta; /* 触摸状态 */
uint8_t id[ID_LENGTH]; /* 触摸屏id */
} GTXXXX_TouchTypeDef;
extern GTXXXX_TouchTypeDef gtxxxx_dev; /* 触摸屏设备结构体 */
uint8_t gtxxxx_wr_reg(uint16_t reg, uint8_t *buf, uint8_t len);
void gtxxxx_rd_reg(uint16_t reg, uint8_t *buf, uint8_t len);
uint8_t gtxxxx_init(void);
uint8_t gtxxxx_scan(void);
#endif //__TOUCH_800X480_H__
博客导航
本文来自博客园,作者:膝盖中箭卫兵,转载请注明原文链接:https://www.cnblogs.com/Skyrim-sssuuu/p/19187288

浙公网安备 33010602011771号
https://orcid.org/0000-0001-5102-772X