【LTDC】RGB LCD 电容触摸屏的配置和程序

引言

配置好 RGB LCD 的显示之后,就可以配置其触摸的功能了。电容触摸屏的驱动方式格外的简单,下面由我一一道来(触摸检测的本质上就是电容交互式的感应,然后通过 IC 的通讯协议来传输寄存器上的数据。

主控板

STM32H743开发板 核心板 小系统板 反客 STM32H743IIT6

image

屏幕

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

image

触摸屏 IC:GT1151Q

数据手册:

GT1151Q 带自定义手势唤醒功能的电容触控芯片

编程指南:

GT1151Q 编程指南

触控引脚

主控引脚

不同主控板的引脚位置会有所不同,我使用的是反客家的 STM32H743IIT6,这里使用的引脚是:

TOUCH_RST ---- PH4(复位引脚)
TOUCH_INT ---- PG3(中断引脚)
TOUCH_SCLK ---- PI11(IIC 时钟线)
TOUCH_SDA ---- PI8(IIC 数据线)

下图是反客所提供的接口原理图:

image

CubeMX 配置

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

image

SDA ---- 开漏输出 低速 上拉
SCL ---- 开漏输出 低速 上拉
RST ---- 推挽输出 超高速 上拉
INT ---- 输入模式 浮空

  1. 由于在配置中 SDA 对应引脚只有低速模式,为了匹配 SDA 的速度保证通讯的稳定性,SCL 也选择了低速,而且也只是读取触摸数据,50MHz 也足够用了。
  2. 复位引脚初始化为上拉,方便后续拉低来复位。
  3. 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__

博客导航

博客导航

posted @ 2025-11-04 10:27  膝盖中箭卫兵  阅读(11)  评论(0)    收藏  举报
ORCID iD icon https://orcid.org/0000-0001-5102-772X