LCD触摸屏开发

触摸屏介绍

什么是触摸屏?

触摸屏(Touch Panel)是一种能够感知用户手指或触控笔在屏幕表面的操作位置,并将这些触摸信息以坐标数据的形式反馈给主控设备(如MCU、单板计算机等)的输入设备。触摸屏广泛应用于手机、平板、工业控制、人机交互界面等场合。

触摸屏的基本结构

触摸屏通常由以下几部分组成:

  • 触摸感应层:通过电容、电阻、红外等方式感应位置变化。
  • 基板(玻璃/塑料):为感应层提供机械支撑。
  • FPC柔性排线:连接触摸层与主板,传输信号。
  • 触摸控制芯片:如CST816T、GT911等,负责扫描感应层、处理触摸信号、输出触摸坐标。

触摸屏本身只负责采集触摸信息,不负责显示内容。显示内容由LCDOLED等显示屏负责。

触摸屏类型

  1. 电阻式触摸屏

    • 通过两层导电薄膜压接判断坐标,受力即可响应。
    • 优点:支持手指、手套、触控笔,成本低。
    • 缺点:精度有限,寿命短,透光率低。
    • 常见型号:XPT2046、ADS7846、TP4056(控制IC);用于1602、12864等老式LCD的电阻触摸层
  2. 电容式触摸屏(主流)

    • 依靠人体导电特性,检测电极阵列的电容变化推算位置。
    • 优点:高透光率,灵敏度高,支持多点触控,寿命长。
    • 缺点:需手指或专用导电笔,湿手或带手套效果差。
    • 常见型号:CST816T、GT911、FT5206、FT6236、ILI2130、Goodix GT5688
      • 应用于2.4”~10.1”各类TFT/IPS彩屏模组
  3. 其它类型

    • 红外式、表面声波式、光学式等,主要用于特定大尺寸或特殊环境。

    • 常见型号

      • 红外式:HMI大屏常用红外触摸框(型号多为尺寸+点数描述,如“32寸10点红外触摸框”)
      • 表面声波式:ELO(伊洛)等品牌的工业大尺寸触摸屏
      • 光学式:PQ Labs、NextWindow 等方案

对比:

类型 响应方式 支持多点 透光率 抗干扰 寿命 典型应用 常见型号及IC
电阻式 受压变形 一般单点 一般 一般 较低 老式工控、POS机 XPT2046、ADS7846
电容式 电容变化 支持 很高 较好 很高 手机、平板、终端 CST816T、GT911、FT5206
红外/声波式 光/声波遮挡 支持 极高 很高 大尺寸查询一体机等 红外触摸框、ELO等

触摸屏工作原理

电容触摸屏原理(以CST816T等为例)

  • 屏幕表面布有X、Y方向的透明电极阵列。
  • 触摸控制芯片定期扫描所有电极点,监测电容变化。
  • 用户手指接触屏幕时,会导致某些交点电容变化。
  • 芯片通过算法计算出触摸点的X、Y坐标。
  • 坐标信息通过I2C、SPI等总线传出。

触摸屏与显示屏的区别与关系

  • 显示屏(如LCD、OLED):只负责显示图像、文字等信息,无法感知触摸

  • 触摸屏:只负责检测并输出触摸点的坐标,无法显示内容

实际产品中常见“触控显示一体屏”,即显示屏和触摸屏通过光学贴合、电气连接集成在一起,模组内部包含了显示层+触摸感应层+触摸芯片

触摸屏典型接口与开发说明

  • I2C接口:主流方案,硬件连接简单,适合中小尺寸触摸屏。
  • SPI接口:部分芯片支持,速度快,抗干扰性好。
  • 中断引脚:用于触摸事件通知(如CST816T的INT脚)。
  • 初始化与驱动:需在MCU侧编写驱动程序,读取触摸芯片数据寄存器,解析出坐标。
  • 与GUI库集成:如LVGL等,需提供触摸输入回调,反馈实时触摸状态。

厂家代码

厂家一般会给出触摸屏对应的驱动代码,我们实际开发一般进行移植即可,主要包括驱动的源文件和头文件定义,还有底层通讯协议,一般我们使用我们的底层协议对接,然后进行移植即可

从零开始触摸驱动开发

基于厂家给的驱动代码的解读!

如何入手开发触摸驱动

在LCD开发的过程中,如果是带有触摸功能的显示屏,通常显示驱动开发完成后,需要对我们的触摸功能进行一个开发,如何与MCU正常通信并实现坐标识别,整个流程是怎样的?如何驱动触摸芯片?

我这里总结一下触摸芯片驱动开发的全流程,流程类似于上方的LCD显示驱动开发

第一步:阅读手册

  1. 确认触摸芯片型号
    比如 P169H002-CTP 屏幕配套触摸芯片是 CST816T
  2. 查阅芯片手册
    详细了解 CTP(电容触摸芯片)的通信协议(常见为 I2C),寄存器定义,数据格式(如坐标/手势/点数等)。
  3. 关注通信模式
    CST816T 使用 I2C 通信,需关注 I2C 地址、时序、触摸数据寄存器、初始化流程。

第二步:触摸芯片的开发

开发初始化、读写、配置等

CST816T触摸芯片介绍

CST816T 是上海海栎创微电子有限公司推出的一款电容触控芯片,内置高速MCU和DSP,支持多种自电容感应图案,适合小尺寸可穿戴设备(如手环、手表)的单点手势和两点操作。 它具有高灵敏度、低功耗、支持I2C通信,易于集成。

对于具体的I2C通讯有哪些常用操作工作模式如何使用等,请观看手册上的详细描述

CST816T触摸检测方式

读寄存器检测

我们可以直接读取手指检测的寄存器,只要读取的手指数>0,就判断为有触摸点

image-20250808195612851

中断引脚检测

CST816T芯片有一个INT(中断)引脚,当检测到触摸时,该引脚会被拉低,我们可以通过以下方式判断检测:

1.读取INT电平,检测到低就代表触摸了,读取相关触摸数据后,INI引脚自动拉高(类似于读寄存器)

2.配置INI为主控芯片某个引脚的外部中断,设置为下降沿触发

总结

方式 说明 优点 缺点
轮询读取 MCU主动查询INT引脚状态/手指数寄存器 实现简单,调试方便 需要频繁轮询,功耗高,响应慢
中断读取 INT引脚作为外部中断输入MCU,事件发生时自动触发中断回调 响应快,低功耗,效率高 需配置中断,部分芯片有数量限制

触摸开发

建议先大体浏览一下对应的手册内容!!!

头文件

这部分代码厂商通常会提供,我们基于厂商代码分析:

对于触摸芯片驱动我们一般会先从头文件写起,主要包括:引脚宏定义通讯函数宏定义函数声明

这些与LCD显示类似,除此之外我们还需要对应的触摸屏的I2C地址寄存器宏定义宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#ifndef __CST816T_H
#define __CST816T_H

#include "i2c_hal.h"
#include "delay.h"

/* CST816T触摸芯片引脚宏定义 */

#define TP_RST_PORT GPIOA
#define TP_RST_PIN GPIO_PIN_15

#define TP_INT_PORT GPIOB
#define TP_INT_PIN GPIO_PIN_1

#define TP_SCL_PORT GPIOB
#define TP_SCL_PIN GPIO_PIN_6

#define TP_SDA_PORT GPIOB
#define TP_SDA_PIN GPIO_PIN_4

/* CST816T触摸芯片相关宏函数定义*/

#define TP_RST_LOW() HAL_GPIO_WritePin(TP_RST_PORT, TP_RST_PIN, GPIO_PIN_RESET)
#define TP_RST_HIGH() HAL_GPIO_WritePin(TP_RST_PORT, TP_RST_PIN, GPIO_PIN_SET)

/* CST816T触摸芯片I2C地址定义 */
#define CST816T_I2C_ADDRESS 0x15 // 7位I2C地址
#define CST816T_I2C_WRITE_ADDRESS 0x2A // 8位写地址
#define CST816T_I2C_READ_ADDRESS 0X2B // 8位读地址


/* CST816T触摸芯片寄存器地址 */

#define GestureID 0x01 // 手势ID寄存器,记录当前检测到的手势类型
#define FingerNum 0x02 // 触摸点数寄存器,当前触摸点的数量
#define XposH 0x03 // 第一个触摸点X坐标高8位
#define XposL 0x04 // 第一个触摸点X坐标低8位
#define YposH 0x05 // 第一个触摸点Y坐标高8位
#define YposL 0x06 // 第一个触摸点Y坐标低8位
#define ChipID 0xA7 // 芯片ID寄存器,用于芯片识别,固定值
#define ProjID 0xA8 // 项目ID寄存器,区分不同项目
#define FwVersion 0xA9 // 固件版本号寄存器
#define FactoryID 0xAA // 工厂ID寄存器
#define BPC0H 0xB0 // 备份坐标0高8位
#define BPC0L 0xB1 // 备份坐标0低8位
#define BPC1H 0xB2 // 备份坐标1高8位
#define BPC1L 0xB3 // 备份坐标1低8位
#define CDCRes 0xC0 // CDC电阻
#define CDCFreq 0xC1 // CDC频率
#define CDCIdac 0xC2 // CDC电流
#define SleepMode 0xE5 // 进入低功耗模式控制
#define ErrResetCtl 0xEA // 错误复位控制
#define LongPressTick 0xEB // 长按定时时间
#define MotionMask 0xEC // 对某些运动相关操作的屏蔽或启用设置
#define IrqPluseWidth 0xED // 中断脉冲宽度
#define NorScanPer 0xEE // 正常扫描周期参数
#define MotionSlAngle 0xEF // 运动滑动角度
#define LpScanRaw1H 0xF0 // 低功耗扫描原始数据1高字节
#define LpScanRaw1L 0xF1 // 低功耗扫描原始数据1低字节
#define LpScanRaw2H 0xF2 // 低功耗扫描原始数据2高字节
#define LpScanRaw2L 0xF3 // 低功耗扫描原始数据2低字节
#define LpAutoWakeTime 0xF4 // 低功耗自动唤醒时间
#define LpScanTH 0xF5 // 低功耗扫描阈值
#define LpScanWin 0xF6 // 低功耗扫描窗口
#define LpScanFreq 0xF7 // 低功耗扫描频率
#define LpScanIdac 0xF8 // 低功耗扫描电流
#define AutoSleepTime 0xF9 // 自动休眠时间
#define IrqCtl 0xFA // 中断控制
#define AutoReset 0xFB // 自动复位控制
#define LongPressTime 0xFC // 长按判定时间
#define IOCtl 0xFD // IO控制
#define DisAutoSleep 0xFE // 禁止自动休眠


/* 触摸屏坐标结构体 */
typedef struct
{
unsigned int x_pos;
unsigned int y_pos;
}CST816T_Info;

/* 用于上层使用 */
extern CST816T_Info CST816T_Position;


/* 手势ID识别选项*/
typedef enum
{
NOGESTURE = 0x00,//无操作
DOWNGLIDE = 0x01,//下滑
UPGLIDE = 0x02,//上滑
LEFTGLIDE = 0x03,//左滑
RIGHTGLIDE = 0x04,//右滑
CLICK = 0x05, //点击
DOUBLECLICK = 0x0B, //双击
LONGPRESS = 0x0C, //长按
} GestureID_TypeDef;



/* 连续动作配置选项 */
typedef enum
{
M_DISABLE = 0x00,// 不需要任何连续动作
EnConLR = 0x01,// 左右滑动
EnConUD = 0x02,//上下滑动
EnDClick = 0x03, //双击
M_ALLENABLE = 0x07, //启用所有连续动作配置
} MotionMask_TypeDef;

/* 中断低脉冲发射方式选项 */
typedef enum
{
OnceWLP = 0x00,//单词脉冲发射
EnMotion = 0x10,//运动变化
EnChange = 0x20,//检测某些特定变化
EnTouch = 0x40,//触摸事件
EnTest = 0x80,//检测中断是否正常
} IrqCtl_TypeDef;

/* 屏幕初始化相关函数 */
void CST816T_GPIO_Init(void);
void CST816T_Reset(void);
void CST816T_Init(void);

/* 触摸屏读写相关函数*/
void CST816T_WriteReg(uint8_t reg_addr,uint8_t data);
uint8_t CST816T_ReadReg(uint8_t reg_addr);
void CST816T_WriteBytes(uint8_t reg_addr,uint8_t data[],int size);
void CST816T_ReadBytes(uint8_t reg_addr,uint8_t data[],int size);

/* 触摸屏操作相关函数*/
void CST816T_Get_Postiton(void);
uint8_t CST816T_Get_FingerNum(void);
uint8_t CST816T_Get_ChipID(void);

/* 触摸屏参数配置相关函数*/
void CST816T_Sleep(void);
void CST816T_Wakeup(void);
void CST816T_Config_MotionMask(uint8_t mode);
void CST816T_Config_AutoSleepTime(uint8_t time);
void CST816T_Config_MotionSlAngle(uint8_t x_right_y_up_angle);
void CST816T_Config_NorScanPer(uint8_t Period);
void CST816T_Config_IrqPluseWidth(uint8_t Width);
void CST816T_Config_LpScanTH(uint8_t TH);

#endif

下面我们就来详细拆解一下内容:

引脚宏定义: 主要是SCL、SDA、RST、INT引脚,根据手册、原理图定义即可

1
2
3
4
5
6
7
8
9
10
11
12
13
/* CST816T触摸芯片引脚宏定义 */

#define TP_RST_PORT GPIOA
#define TP_RST_PIN GPIO_PIN_15

#define TP_INT_PORT GPIOB
#define TP_INT_PIN GPIO_PIN_1

#define TP_SCL_PORT GPIOB
#define TP_SCL_PIN GPIO_PIN_6

#define TP_SDA_PORT GPIOB
#define TP_SDA_PIN GPIO_PIN_4

通讯函数宏定义: 涉及到的就是对应引脚的拉高拉低,由于I2C是软件模拟,单独有驱动,所以这里不定义

1
2
3
/* CST816T触摸芯片相关宏函数定义*/
#define TP_RST_LOW() HAL_GPIO_WritePin(TP_RST_PORT, TP_RST_PIN, GPIO_PIN_RESET)
#define TP_RST_HIGH() HAL_GPIO_WritePin(TP_RST_PORT, TP_RST_PIN, GPIO_PIN_SET)

触摸芯片相关宏定义: 包括I2C地址、寄存器地址的定义,这部分看芯片手册移植过来即可

image-20250806151130205

image-20250806151119991

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* CST816T触摸芯片I2C地址定义 */
#define CST816T_I2C_ADDRESS 0x15 // 7位I2C地址
#define CST816T_I2C_WRITE_ADDRESS 0x2A // 8位写地址
#define CST816T_I2C_READ_ADDRESS 0X2B // 8位读地址

/* CST816T触摸芯片寄存器地址 */

#define GestureID 0x01 // 手势ID寄存器,记录当前检测到的手势类型
#define FingerNum 0x02 // 触摸点数寄存器,当前触摸点的数量
#define XposH 0x03 // 第一个触摸点X坐标高8位
#define XposL 0x04 // 第一个触摸点X坐标低8位
#define YposH 0x05 // 第一个触摸点Y坐标高8位
#define YposL 0x06 // 第一个触摸点Y坐标低8位
#define ChipID 0xA7 // 芯片ID寄存器,用于芯片识别,固定值
#define ProjID 0xA8 // 项目ID寄存器,区分不同项目
#define FwVersion 0xA9 // 固件版本号寄存器
#define FactoryID 0xAA // 工厂ID寄存器
#define BPC0H 0xB0 // 备份坐标0高8位
#define BPC0L 0xB1 // 备份坐标0低8位
#define BPC1H 0xB2 // 备份坐标1高8位
#define BPC1L 0xB3 // 备份坐标1低8位
#define CDCRes 0xC0 // CDC电阻
#define CDCFreq 0xC1 // CDC频率
#define CDCIdac 0xC2 // CDC电流
#define SleepMode 0xE5 // 进入低功耗模式控制
#define ErrResetCtl 0xEA // 错误复位控制
#define LongPressTick 0xEB // 长按定时时间
#define MotionMask 0xEC // 对某些运动相关操作的屏蔽或启用设置
#define IrqPluseWidth 0xED // 中断脉冲宽度
#define NorScanPer 0xEE // 正常扫描周期参数
#define MotionSlAngle 0xEF // 运动滑动角度
#define LpScanRaw1H 0xF0 // 低功耗扫描原始数据1高字节
#define LpScanRaw1L 0xF1 // 低功耗扫描原始数据1低字节
#define LpScanRaw2H 0xF2 // 低功耗扫描原始数据2高字节
#define LpScanRaw2L 0xF3 // 低功耗扫描原始数据2低字节
#define LpAutoWakeTime 0xF4 // 低功耗自动唤醒时间
#define LpScanTH 0xF5 // 低功耗扫描阈值
#define LpScanWin 0xF6 // 低功耗扫描窗口
#define LpScanFreq 0xF7 // 低功耗扫描频率
#define LpScanIdac 0xF8 // 低功耗扫描电流
#define AutoSleepTime 0xF9 // 自动休眠时间
#define IrqCtl 0xFA // 中断控制
#define AutoReset 0xFB // 自动复位控制
#define LongPressTime 0xFC // 长按判定时间
#define IOCtl 0xFD // IO控制
#define DisAutoSleep 0xFE // 禁止自动休眠

相关类型定义: 包括坐标手势连续动作中断脉冲发射等的枚举类型定义,这些根据手册上来编写,厂家估计也是如此

  • 坐标:用于存放触摸点的X、Y坐标。当读取到触摸数据时,可以把坐标填入这个结构体,然后传递给上层应用(比如GUI显示、手势识别等)。

image-20250806151907711

1
2
3
4
5
6
/* 触摸屏坐标结构体 */
typedef struct
{
unsigned int x_pos;
unsigned int y_pos;
}CST816T_Info;
  • 手势定义: 读取手势寄存器得值,用于判断用户操作

image-20250806151817695

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 手势ID识别选项*/
typedef enum
{
NOGESTURE = 0x00,//无操作
DOWNGLIDE = 0x01,//下滑
UPGLIDE = 0x02,//上滑
LEFTGLIDE = 0x03,//左滑
RIGHTGLIDE = 0x04,//右滑
CLICK = 0x05, //点击
DOUBLECLICK = 0x0B, //双击
LONGPRESS = 0x0C, //长按
} GestureID_TypeDef;

  • 连续动作: 决定哪些连续动作被允许识别。

image-20250806152151143

1
2
3
4
5
6
7
8
9
10
11
/* 连续动作配置选项 */
typedef enum
{
M_DISABLE = 0x00,// 不需要任何连续动作
EnConLR = 0x01,// 左右滑动
EnConUD = 0x02,//上下滑动
EnDClick = 0x03, //双击
M_ALLENABLE = 0x07, //启用所有连续动作配置
} MotionMask_TypeDef;


  • 中断脉冲发射: 用于配置芯片的中断控制寄存器,设置中断的触发方式。比如,EnMotion只在检测到运动时产生中断,EnTouch只在有触摸时产生中断,OnceWLP为默认的单次低电平脉冲。

image-20250806152532751

1
2
3
4
5
6
7
8
9
10
/* 中断低脉冲发射方式选项 */
typedef enum
{
OnceWLP = 0x00,//单词脉冲发射
EnMotion = 0x10,//运动变化
EnChange = 0x20,//检测某些特定变化
EnTouch = 0x40,//触摸事件
EnTest = 0x80,//检测中断是否正常
} IrqCtl_TypeDef;

  • 函数声明: 主要是四个部分初始化读写寄存器触摸屏操作触摸屏参数配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* 屏幕初始化相关函数 */
void CST816T_GPIO_Init(void);
void CST816T_Reset(void);
void CST816T_Init(void);

/* 触摸屏读写相关函数*/
void CST816T_WriteReg(uint8_t reg_addr,uint8_t data);
uint8_t CST816T_ReadReg(uint8_t reg_addr);
void CST816T_WriteBytes(uint8_t reg_addr,uint8_t data[],int size);
void CST816T_ReadBytes(uint8_t reg_addr,uint8_t data[],int size);

/* 触摸屏操作相关函数*/
void CST816T_Get_Postiton(void);
uint8_t CST816T_Get_FingerNum(void);
uint8_t CST816T_Get_ChipID(void);

/* 触摸屏参数配置相关函数*/
void CST816T_Sleep(void);
void CST816T_Wakeup(void);
void CST816T_Config_MotionMask(uint8_t mode);
void CST816T_Config_AutoSleepTime(uint8_t time);
void CST816T_Config_MotionSlAngle(uint8_t x_right_y_up_angle);
void CST816T_Config_NorScanPer(uint8_t Period);
void CST816T_Config_IrqPluseWidth(uint8_t Width);
void CST816T_Config_LpScanTH(uint8_t TH);

引脚初始化

一般有两种检测方式,中断检测和轮询检测,我们这里不使用中断引脚,所以没有配置中断引脚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
i2c_bus_t CST816T_bus = 
{
.I2C_SDA_PORT = TP_SDA_PORT,
.I2C_SCL_PORT = TP_SCL_PORT,
.I2C_SDA_PIN = TP_SDA_PIN,
.I2C_SCL_PIN = TP_SCL_PIN
};


void CST816T_GPIO_Init(void)
{
/*开启时钟*/
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/* 初始化复位引脚 */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = TP_RST_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //50Mhz左右即可
HAL_GPIO_Init(TP_RST_PORT,&GPIO_InitStruct);

HAL_GPIO_WritePin(TP_RST_PORT,TP_RST_PIN,GPIO_PIN_SET);

/* 初始化中断引脚,不用中断的话屏蔽掉 */

/* I2C引脚初始化 */
i2c_init(&CST816T_bus);
}

复位

一般初始化涉及到复位操作,触摸芯片低功耗也与复位操作有关,所以按照手册编写复位函数

image-20250808193405122

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
*********************************************************************************************************
* 函 数 名: CST816T_Reset
* 功能说明: 触摸屏复位
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Reset(void)
{
TP_RST_LOW();
delay_ms(10);
TP_RST_HIGH();
delay_ms(100); //手册上复位等待最小100ms
}

读写寄存器

因为触摸芯片需要进行一些配置等,所以需要读写寄存器,这里我是软件模拟I2C,直接对其进行编写驱动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
*********************************************************************************************************
* 函 数 名: CST816T_WriteReg
* 功能说明: 向指定寄存器写入单个字节数据
* 形 参:reg_addr:寄存器地址 data:要写入的数据
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_WriteReg(uint8_t reg_addr,uint8_t data)
{
i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,data);
i2c_soft_wait_ack(&CST816T_bus);

i2c_soft_stop(&CST816T_bus);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_WriteBytes
* 功能说明: 向指定寄存器开始地址连续写入多个字节数据
* 形 参:reg_addr:寄存器起始地址 data:数据指针 size:写入字节数
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_WriteBytes(uint8_t reg_addr,uint8_t data[],int size)
{
i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);

for(int i=0;i<size;i++)
{
i2c_soft_send_byte(&CST816T_bus,data[i]);
i2c_soft_wait_ack(&CST816T_bus);
}

i2c_soft_stop(&CST816T_bus);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_ReadReg
* 功能说明: 读取指定寄存器的单个字节数据
* 形 参:reg_addr:寄存器地址
* 返 回 值: 读取到的数据
*********************************************************************************************************
*/
uint8_t CST816T_ReadReg(uint8_t reg_addr)
{
uint8_t data;

i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);

i2c_soft_start(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_READ_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
data = i2c_soft_read_byte(&CST816T_bus);
i2c_soft_send_not_ack(&CST816T_bus);

i2c_soft_stop(&CST816T_bus);

return data;
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_ReadBytes
* 功能说明: 从指定寄存器地址开始连续读取多个字节数据
* 形 参:reg_addr:寄存器起始地址 data:数据缓存指针 size:读取字节数
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_ReadBytes(uint8_t reg_addr,uint8_t data[],int size)
{
i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);

i2c_soft_start(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_READ_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
for(int i=0;i<size;i++)
{
data[i] = i2c_soft_read_byte(&CST816T_bus);

if(i < size-1)
{
i2c_soft_send_ack(&CST816T_bus);
}
}

i2c_soft_send_not_ack(&CST816T_bus);
i2c_soft_stop(&CST816T_bus);
}

功能函数

剩下的就是一些对于触摸的功能函数,获取手指数量获取芯片ID等等,按照手册上描述进行编写即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
*********************************************************************************************************
* 函 数 名: CST816T_Get_FingerNum
* 功能说明: 获取当前检测到的手指数量
* 形 参:无
* 返 回 值: 检测到的手指数量
*********************************************************************************************************
*/
uint8_t CST816T_Get_FingerNum(void)
{
return CST816T_ReadReg(FingerNum);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Get_ChipID
* 功能说明: 获取CST816T芯片ID
* 形 参:无
* 返 回 值: 芯片ID
*********************************************************************************************************
*/
uint8_t CST816T_Get_ChipID(void)
{
return CST816T_ReadReg(ChipID);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_MotionMask
* 功能说明: 配置手势检测使能掩码(Motion Mask)
* 形 参:mode:手势使能掩码
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_MotionMask(uint8_t mode)
{
CST816T_WriteReg(MotionMask,mode);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_AutoSleepTime
* 功能说明: 配置自动进入睡眠前的等待时间
* 形 参:time:自动睡眠等待时间,单位:s
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_AutoSleepTime(uint8_t time)
{
CST816T_WriteReg(AutoSleepTime,time);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Sleep
* 功能说明: 使CST816T进入休眠模式
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Sleep(void)
{
CST816T_WriteReg(SleepMode,0x03);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Wakeup
* 功能说明: 唤醒CST816T(通过复位方式)
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Wakeup(void)
{
CST816T_Reset();
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_MotionSlAngle
* 功能说明: 配置滑动手势检测角度
* 形 参:x_right_y_up_angle:角度参数
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_MotionSlAngle(uint8_t x_right_y_up_angle)
{
CST816T_WriteReg(MotionSlAngle,x_right_y_up_angle);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_NorScanPer
* 功能说明: 配置正常扫描周期
* 形 参:Period:扫描周期,最大30
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_NorScanPer(uint8_t Period)
{
if(Period >= 30)
Period = 30;
CST816T_WriteReg(NorScanPer,Period);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_IrqPluseWidth
* 功能说明: 配置IRQ中断脉冲宽度
* 形 参:Width:中断脉宽,最大200
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_IrqPluseWidth(uint8_t Width)
{
if(Width >= 200)
Width = 200;
CST816T_WriteReg(IrqPluseWidth,Width);
}

/*
*********************************************************************************************************
* 函 数 名: CST816t_Config_LpScanTH
* 功能说明: 配置低功耗扫描阈值
* 形 参:TH:低功耗扫描阈值
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_LpScanTH(uint8_t TH)
{
CST816T_WriteReg(LpScanTH,TH);
}

触摸芯片初始化

最后我们对芯片初始化进行一个封装,供应用层调用后使用

对于其他配置,我们可以根据需求放到初始化函数中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
*********************************************************************************************************
* 函 数 名: CST816T_Init
* 功能说明: CST816初始化
* 形 参:none
* 返 回 值: none
*********************************************************************************************************
*/
void CST816T_Init(void)
{
CST816T_GPIO_Init(); //引脚初始化
CST816T_Config_AutoSleepTime(5); //睡眠时间配置
//其他的一些想要的设置.....
}

源文件

以上整理后可以得到cst816t.c文件

后续测试后可以根据读取到的坐标点,对坐标进行一个校准,添加对应的偏移量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#include "cst816t.h"

#define OFFSET_Y 0 //y轴偏移量
#define OFFSET_X 0 //x轴偏移量

i2c_bus_t CST816T_bus =
{
.I2C_SDA_PORT = TP_SDA_PORT,
.I2C_SCL_PORT = TP_SCL_PORT,
.I2C_SDA_PIN = TP_SDA_PIN,
.I2C_SCL_PIN = TP_SCL_PIN
};

CST816T_Info CST816T_Position;

/*
*********************************************************************************************************
* 函 数 名: CST816_GPIO_Init
* 功能说明: CST816 GPIO口初始化
* 形 参:none
* 返 回 值: none
*********************************************************************************************************
*/
void CST816T_GPIO_Init(void)
{
/*开启时钟*/
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/* 初始化复位引脚 */
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = TP_RST_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //50Mhz左右即可
HAL_GPIO_Init(TP_RST_PORT,&GPIO_InitStruct);

HAL_GPIO_WritePin(TP_RST_PORT,TP_RST_PIN,GPIO_PIN_SET);

/* 初始化中断引脚,不用中断的话屏蔽掉 */

/* I2C引脚初始化 */
i2c_init(&CST816T_bus);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Init
* 功能说明: CST816初始化
* 形 参:none
* 返 回 值: none
*********************************************************************************************************
*/
void CST816T_Init(void)
{
CST816T_GPIO_Init();
CST816T_Config_AutoSleepTime(5);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Reset
* 功能说明: 触摸屏复位
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Reset(void)
{
TP_RST_LOW();
delay_ms(10);
TP_RST_HIGH();
delay_ms(100); //手册上复位等待最小100ms
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_WriteReg
* 功能说明: 向指定寄存器写入单个字节数据
* 形 参:reg_addr:寄存器地址 data:要写入的数据
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_WriteReg(uint8_t reg_addr,uint8_t data)
{
i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,data);
i2c_soft_wait_ack(&CST816T_bus);

i2c_soft_stop(&CST816T_bus);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_WriteBytes
* 功能说明: 向指定寄存器开始地址连续写入多个字节数据
* 形 参:reg_addr:寄存器起始地址 data:数据指针 size:写入字节数
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_WriteBytes(uint8_t reg_addr,uint8_t data[],int size)
{
i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);

for(int i=0;i<size;i++)
{
i2c_soft_send_byte(&CST816T_bus,data[i]);
i2c_soft_wait_ack(&CST816T_bus);
}

i2c_soft_stop(&CST816T_bus);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_ReadReg
* 功能说明: 读取指定寄存器的单个字节数据
* 形 参:reg_addr:寄存器地址
* 返 回 值: 读取到的数据
*********************************************************************************************************
*/
uint8_t CST816T_ReadReg(uint8_t reg_addr)
{
uint8_t data;

i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);

i2c_soft_start(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_READ_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
data = i2c_soft_read_byte(&CST816T_bus);
i2c_soft_send_not_ack(&CST816T_bus);

i2c_soft_stop(&CST816T_bus);

return data;
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_ReadBytes
* 功能说明: 从指定寄存器地址开始连续读取多个字节数据
* 形 参:reg_addr:寄存器起始地址 data:数据缓存指针 size:读取字节数
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_ReadBytes(uint8_t reg_addr,uint8_t data[],int size)
{
i2c_soft_start(&CST816T_bus);

i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_WRITE_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,reg_addr);
i2c_soft_wait_ack(&CST816T_bus);

i2c_soft_start(&CST816T_bus);
i2c_soft_send_byte(&CST816T_bus,CST816T_I2C_READ_ADDRESS);
i2c_soft_wait_ack(&CST816T_bus);
for(int i=0;i<size;i++)
{
data[i] = i2c_soft_read_byte(&CST816T_bus);

if(i < size-1)
{
i2c_soft_send_ack(&CST816T_bus);
}
}

i2c_soft_send_not_ack(&CST816T_bus);
i2c_soft_stop(&CST816T_bus);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Get_Postiton
* 功能说明: 获取当前触摸点的X、Y坐标
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Get_Postiton(void)
{
uint8_t data[4] ;
CST816T_ReadBytes(XposH,data,4);
CST816T_Position.x_pos = ((data[0] & 0x0F) << 8) | data[1];
CST816T_Position.y_pos = ((data[2] & 0x0F) << 8) | data[3];
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Get_FingerNum
* 功能说明: 获取当前检测到的手指数量
* 形 参:无
* 返 回 值: 检测到的手指数量
*********************************************************************************************************
*/
uint8_t CST816T_Get_FingerNum(void)
{
return CST816T_ReadReg(FingerNum);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Get_ChipID
* 功能说明: 获取CST816T芯片ID
* 形 参:无
* 返 回 值: 芯片ID
*********************************************************************************************************
*/
uint8_t CST816T_Get_ChipID(void)
{
return CST816T_ReadReg(ChipID);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_MotionMask
* 功能说明: 配置手势检测使能掩码(Motion Mask)
* 形 参:mode:手势使能掩码
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_MotionMask(uint8_t mode)
{
CST816T_WriteReg(MotionMask,mode);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_AutoSleepTime
* 功能说明: 配置自动进入睡眠前的等待时间
* 形 参:time:自动睡眠等待时间,单位:s
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_AutoSleepTime(uint8_t time)
{
CST816T_WriteReg(AutoSleepTime,time);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Sleep
* 功能说明: 使CST816T进入休眠模式
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Sleep(void)
{
CST816T_WriteReg(SleepMode,0x03);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Wakeup
* 功能说明: 唤醒CST816T(通过复位方式)
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Wakeup(void)
{
CST816T_Reset();
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_MotionSlAngle
* 功能说明: 配置滑动手势检测角度
* 形 参:x_right_y_up_angle:角度参数
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_MotionSlAngle(uint8_t x_right_y_up_angle)
{
CST816T_WriteReg(MotionSlAngle,x_right_y_up_angle);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_NorScanPer
* 功能说明: 配置正常扫描周期
* 形 参:Period:扫描周期,最大30
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_NorScanPer(uint8_t Period)
{
if(Period >= 30)
Period = 30;
CST816T_WriteReg(NorScanPer,Period);
}

/*
*********************************************************************************************************
* 函 数 名: CST816T_Config_IrqPluseWidth
* 功能说明: 配置IRQ中断脉冲宽度
* 形 参:Width:中断脉宽,最大200
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_IrqPluseWidth(uint8_t Width)
{
if(Width >= 200)
Width = 200;
CST816T_WriteReg(IrqPluseWidth,Width);
}

/*
*********************************************************************************************************
* 函 数 名: CST816t_Config_LpScanTH
* 功能说明: 配置低功耗扫描阈值
* 形 参:TH:低功耗扫描阈值
* 返 回 值: 无
*********************************************************************************************************
*/
void CST816T_Config_LpScanTH(uint8_t TH)
{
CST816T_WriteReg(LpScanTH,TH);
}

测试代码编写

编写完驱动之后,我们通常会写一些参考示例测试我们的驱动,同时后续以供别人使用

比如:

1.读取芯片ID,看看返回值是否正确

2.检测到手指数后获取触摸点坐标,有调试器使用断点查看,或者使用串口查看数据输出

image-20250806224655423

可能遇到的问题

触摸没反应

这个大概率是底层通讯有问题,比如我遇到的一种情况:

读取触摸芯片ID(读取一个字节)返回值正常,

但是读取触摸坐标xy(读取多个字节),无论点击屏幕的哪个位置,返回坐标都是x:255 y:4095

最终发现:是i2c读取多个byte的时候,接收1byte后,回复ACK,写成等待ACK了