嵌入式软件LCDLCD触摸屏开发
THEDI触摸屏介绍
什么是触摸屏?
触摸屏(Touch Panel)是一种能够感知用户手指或触控笔在屏幕表面的操作位置,并将这些触摸信息以坐标数据的形式反馈给主控设备(如MCU、单板计算机等)的输入设备。触摸屏广泛应用于手机、平板、工业控制、人机交互界面等场合。
触摸屏的基本结构
触摸屏通常由以下几部分组成:
触摸感应层
:通过电容、电阻、红外等方式感应位置变化。
基板(玻璃/塑料)
:为感应层提供机械支撑。
FPC柔性排线
:连接触摸层与主板,传输信号。
触摸控制芯片
:如CST816T、GT911等,负责扫描感应层、处理触摸信号、输出触摸坐标。
触摸屏本身只负责采集触摸信息,不负责显示内容。显示内容由LCD
、OLED
等显示屏负责。
触摸屏类型
电阻式触摸屏
- 通过两层导电薄膜压接判断坐标,受力即可响应。
- 优点:支持手指、手套、触控笔,成本低。
- 缺点:精度有限,寿命短,透光率低。
- 常见型号:XPT2046、ADS7846、TP4056(控制IC);用于1602、12864等老式LCD的电阻触摸层
电容式触摸屏(主流)
- 依靠人体导电特性,检测电极阵列的电容变化推算位置。
- 优点:高透光率,灵敏度高,支持多点触控,寿命长。
- 缺点:需手指或专用导电笔,湿手或带手套效果差。
- 常见型号:CST816T、GT911、FT5206、FT6236、ILI2130、Goodix GT5688
- 应用于2.4”~10.1”各类TFT/IPS彩屏模组
其它类型
对比:
类型 |
响应方式 |
支持多点 |
透光率 |
抗干扰 |
寿命 |
典型应用 |
常见型号及IC |
电阻式 |
受压变形 |
一般单点 |
一般 |
一般 |
较低 |
老式工控、POS机 |
XPT2046、ADS7846 |
电容式 |
电容变化 |
支持 |
很高 |
较好 |
很高 |
手机、平板、终端 |
CST816T、GT911、FT5206 |
红外/声波式 |
光/声波遮挡 |
支持 |
极高 |
强 |
很高 |
大尺寸查询一体机等 |
红外触摸框、ELO等 |
触摸屏工作原理
电容触摸屏原理(以CST816T等为例)
- 屏幕表面布有X、Y方向的透明电极阵列。
- 触摸控制芯片定期扫描所有电极点,监测电容变化。
- 用户手指接触屏幕时,会导致某些交点电容变化。
- 芯片通过算法计算出触摸点的X、Y坐标。
- 坐标信息通过I2C、SPI等总线传出。
触摸屏与显示屏的区别与关系
实际产品中常见“触控显示一体屏”,即显示屏和触摸屏通过光学贴合、电气连接集成在一起
,模组内部包含了显示层+触摸感应层+触摸芯片。
触摸屏典型接口与开发说明
- I2C接口:主流方案,硬件连接简单,适合中小尺寸触摸屏。
- SPI接口:部分芯片支持,速度快,抗干扰性好。
- 中断引脚:用于触摸事件通知(如CST816T的INT脚)。
- 初始化与驱动:需在MCU侧编写驱动程序,读取触摸芯片数据寄存器,解析出坐标。
- 与GUI库集成:如LVGL等,需提供触摸输入回调,反馈实时触摸状态。
厂家代码
厂家一般会给出触摸屏对应的驱动代码,我们实际开发一般进行移植
即可,主要包括驱动的源文件和头文件定义,还有底层通讯协议,一般我们使用我们的底层协议对接,然后进行移植即可
从零开始触摸驱动开发
基于厂家给的驱动代码的解读!
如何入手开发触摸驱动
在LCD开发的过程中,如果是带有触摸功能的显示屏,通常显示驱动开发完成后,需要对我们的触摸功能进行一个开发,如何与MCU正常通信并实现坐标识别,整个流程是怎样的?如何驱动触摸芯片?
我这里总结一下触摸芯片驱动开发的全流程,流程类似于上方的LCD显示驱动开发
第一步
:阅读手册
- 确认触摸芯片型号
比如 P169H002-CTP 屏幕配套触摸芯片是 CST816T
。
- 查阅芯片手册
详细了解 CTP(电容触摸芯片)的通信协议(常见为 I2C),寄存器定义,数据格式(如坐标/手势/点数等)。
- 关注通信模式
CST816T 使用 I2C 通信,需关注 I2C 地址、时序、触摸数据寄存器、初始化流程。
第二步
:触摸芯片的开发
开发初始化、读写、配置等
CST816T触摸芯片介绍
CST816T 是上海海栎创微电子有限公司推出的一款自电容
触控芯片,内置高速MCU和DSP,支持多种自电容感应图案,适合小尺寸可穿戴设备(如手环、手表)的单点手势和两点操作。 它具有高灵敏度、低功耗、支持I2C
通信,易于集成。
对于具体的I2C通讯有哪些常用操作
、工作模式
、如何使用
等,请观看手册上的详细描述
CST816T触摸检测方式
读寄存器检测
我们可以直接读取手指检测的寄存器,只要读取的手指数>0,就判断为有触摸点

中断引脚检测
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"
#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
#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)
#define CST816T_I2C_ADDRESS 0x15 #define CST816T_I2C_WRITE_ADDRESS 0x2A #define CST816T_I2C_READ_ADDRESS 0X2B
#define GestureID 0x01 #define FingerNum 0x02 #define XposH 0x03 #define XposL 0x04 #define YposH 0x05 #define YposL 0x06 #define ChipID 0xA7 #define ProjID 0xA8 #define FwVersion 0xA9 #define FactoryID 0xAA #define BPC0H 0xB0 #define BPC0L 0xB1 #define BPC1H 0xB2 #define BPC1L 0xB3 #define CDCRes 0xC0 #define CDCFreq 0xC1 #define CDCIdac 0xC2 #define SleepMode 0xE5 #define ErrResetCtl 0xEA #define LongPressTick 0xEB #define MotionMask 0xEC #define IrqPluseWidth 0xED #define NorScanPer 0xEE #define MotionSlAngle 0xEF #define LpScanRaw1H 0xF0 #define LpScanRaw1L 0xF1 #define LpScanRaw2H 0xF2 #define LpScanRaw2L 0xF3 #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 #define DisAutoSleep 0xFE
typedef struct { unsigned int x_pos; unsigned int y_pos; }CST816T_Info;
extern CST816T_Info CST816T_Position;
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
|
#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
| #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地址、寄存器地址的定义,这部分看芯片手册移植过来即可


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
| #define CST816T_I2C_ADDRESS 0x15 #define CST816T_I2C_WRITE_ADDRESS 0x2A #define CST816T_I2C_READ_ADDRESS 0X2B
#define GestureID 0x01 #define FingerNum 0x02 #define XposH 0x03 #define XposL 0x04 #define YposH 0x05 #define YposL 0x06 #define ChipID 0xA7 #define ProjID 0xA8 #define FwVersion 0xA9 #define FactoryID 0xAA #define BPC0H 0xB0 #define BPC0L 0xB1 #define BPC1H 0xB2 #define BPC1L 0xB3 #define CDCRes 0xC0 #define CDCFreq 0xC1 #define CDCIdac 0xC2 #define SleepMode 0xE5 #define ErrResetCtl 0xEA #define LongPressTick 0xEB #define MotionMask 0xEC #define IrqPluseWidth 0xED #define NorScanPer 0xEE #define MotionSlAngle 0xEF #define LpScanRaw1H 0xF0 #define LpScanRaw1L 0xF1 #define LpScanRaw2H 0xF2 #define LpScanRaw2L 0xF3 #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 #define DisAutoSleep 0xFE
|
相关类型定义:
包括坐标
、手势
、连续动作
、中断脉冲发射
等的枚举类型定义,这些根据手册上来编写,厂家估计也是如此
- 坐标:用于存放触摸点的X、Y坐标。当读取到触摸数据时,可以把坐标填入这个结构体,然后传递给上层应用(比如GUI显示、手势识别等)。

1 2 3 4 5 6
| typedef struct { unsigned int x_pos; unsigned int y_pos; }CST816T_Info;
|

1 2 3 4 5 6 7 8 9 10 11 12 13
| typedef enum { NOGESTURE = 0x00, DOWNGLIDE = 0x01, UPGLIDE = 0x02, LEFTGLIDE = 0x03, RIGHTGLIDE = 0x04, CLICK = 0x05, DOUBLECLICK = 0x0B, LONGPRESS = 0x0C, } GestureID_TypeDef;
|

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
为默认的单次低电平脉冲。

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; HAL_GPIO_Init(TP_RST_PORT,&GPIO_InitStruct);
HAL_GPIO_WritePin(TP_RST_PORT,TP_RST_PIN,GPIO_PIN_SET);
i2c_init(&CST816T_bus); }
|
复位
一般初始化涉及到复位操作,触摸芯片低功耗也与复位操作有关,所以按照手册编写复位函数

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
void CST816T_Reset(void) { TP_RST_LOW(); delay_ms(10); TP_RST_HIGH(); delay_ms(100); }
|
读写寄存器
因为触摸芯片需要进行一些配置等,所以需要读写寄存器,这里我是软件模拟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
|
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); }
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); }
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; }
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
|
uint8_t CST816T_Get_FingerNum(void) { return CST816T_ReadReg(FingerNum); }
uint8_t CST816T_Get_ChipID(void) { return CST816T_ReadReg(ChipID); }
void CST816T_Config_MotionMask(uint8_t mode) { CST816T_WriteReg(MotionMask,mode); }
void CST816T_Config_AutoSleepTime(uint8_t time) { CST816T_WriteReg(AutoSleepTime,time); }
void CST816T_Sleep(void) { CST816T_WriteReg(SleepMode,0x03); }
void CST816T_Wakeup(void) { CST816T_Reset(); }
void CST816T_Config_MotionSlAngle(uint8_t x_right_y_up_angle) { CST816T_WriteReg(MotionSlAngle,x_right_y_up_angle); }
void CST816T_Config_NorScanPer(uint8_t Period) { if(Period >= 30) Period = 30; CST816T_WriteReg(NorScanPer,Period); }
void CST816T_Config_IrqPluseWidth(uint8_t Width) { if(Width >= 200) Width = 200; CST816T_WriteReg(IrqPluseWidth,Width); }
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
|
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 #define OFFSET_X 0
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;
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; HAL_GPIO_Init(TP_RST_PORT,&GPIO_InitStruct);
HAL_GPIO_WritePin(TP_RST_PORT,TP_RST_PIN,GPIO_PIN_SET);
i2c_init(&CST816T_bus); }
void CST816T_Init(void) { CST816T_GPIO_Init(); CST816T_Config_AutoSleepTime(5); }
void CST816T_Reset(void) { TP_RST_LOW(); delay_ms(10); TP_RST_HIGH(); delay_ms(100); }
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); }
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); }
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; }
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); }
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]; }
uint8_t CST816T_Get_FingerNum(void) { return CST816T_ReadReg(FingerNum); }
uint8_t CST816T_Get_ChipID(void) { return CST816T_ReadReg(ChipID); }
void CST816T_Config_MotionMask(uint8_t mode) { CST816T_WriteReg(MotionMask,mode); }
void CST816T_Config_AutoSleepTime(uint8_t time) { CST816T_WriteReg(AutoSleepTime,time); }
void CST816T_Sleep(void) { CST816T_WriteReg(SleepMode,0x03); }
void CST816T_Wakeup(void) { CST816T_Reset(); }
void CST816T_Config_MotionSlAngle(uint8_t x_right_y_up_angle) { CST816T_WriteReg(MotionSlAngle,x_right_y_up_angle); }
void CST816T_Config_NorScanPer(uint8_t Period) { if(Period >= 30) Period = 30; CST816T_WriteReg(NorScanPer,Period); }
void CST816T_Config_IrqPluseWidth(uint8_t Width) { if(Width >= 200) Width = 200; CST816T_WriteReg(IrqPluseWidth,Width); }
void CST816T_Config_LpScanTH(uint8_t TH) { CST816T_WriteReg(LpScanTH,TH); }
|
测试代码编写
编写完驱动之后,我们通常会写一些参考示例测试我们的驱动,同时后续以供别人使用
比如:
1.读取芯片ID,看看返回值是否正确
2.检测到手指数后获取触摸点坐标,有调试器使用断点查看,或者使用串口查看数据输出

可能遇到的问题
触摸没反应
这个大概率是底层通讯有问题,比如我遇到的一种情况:
读取触摸芯片ID(读取一个字节)返回值正常,
但是读取触摸坐标xy(读取多个字节),无论点击屏幕的哪个位置,返回坐标都是x:255 y:4095
最终发现:是i2c读取多个byte的时候,接收1byte后,回复ACK,写成等待ACK了