【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__
博客導航
本文來自博客園,作者:膝蓋中箭衛兵,轉載請注明原文鏈接:http://www.rzrgm.cn/Skyrim-sssuuu/p/19187288

浙公網安備 33010602011771號
https://orcid.org/0000-0001-5102-772X