Hal编程驱动GT911触摸芯片:枚举、结构体及其应用——安富莱F429 4.3寸电容屏

使用板子类型以及屏幕类型

本文使用的是安富莱的板子stm32f429,
屏幕是TR433C1的4.3寸TFT显示屏, 480*272 RGB接口, 电容触摸 .

I2C

I2C简介、原理、时序请看这篇文章

使用cubemx工具的stm32用AT24C02实现简单密码(一点点面向对象的思想编程)

gt911

gt911简介

gt911是深圳市汇鼎科技开发

  • 专为7英寸到8英寸MID设计的新一代5点电容式触摸,由多达26个发射器电极和14个接收器电极组成,以提供更高的触摸精度。
  • gt911可同时识别 5 个触摸点位的实时准确位置,移动轨迹及触摸面积。并可根据主控需要,读取相应点数的触摸信息。
  • gt911的地址(8位地址情况)

    gt911和其他基于i2c的芯片略有不同,它可以通过,外部引脚INT和RST引脚改变他的地址,一般地址默认是0xBA,通过用INT和RESET引脚可以输入特定的时序,改变他的地址,变为0x28,或者变回0xBA,时序如下:

    地址变成0x28

  • INT和RESET都为输出模式
  • 地址变成0xBA

  • INT和RESET都为输出模式
  • 地址配置完成后

    配置之后,RST保持拉高输出,INT配置成输入(变成中断线,当有中断来临时,有触摸发生),或者失能(直接通过寄存器来判断是否有触摸)。

    gt911配置说明

    基本写芯片和读芯片代码

    
    void GT911_WriteReg(uint16_t _usRegAddr, uint8_t *_pRegBuf, uint8_t _ucLen)
    {
    	HAL_I2C_Mem_Write(&hi2c1, GT911_DIV_W, _usRegAddr, I2C_MEMADD_SIZE_16BIT, _pRegBuf, _ucLen, 0xff);
    }
    
    void GT911_ReadReg(uint16_t _usRegAddr, uint8_t *_pRegBuf, uint8_t _ucLen)
    {
    	HAL_I2C_Mem_Read(&hi2c1, GT911_DIV_R, _usRegAddr, I2C_MEMADD_SIZE_16BIT, _pRegBuf, _ucLen, 0xff);
    }
    
    

    对于hal函数说明:

  • HAL_I2C_Mem_Write
    参数1 : hal生成的i2c句柄
    参数2 : gt911的写地址,0xBA(0x28)
    参数3 : 寄存器地址
    参数4 : 寄存器大小,有8位模式,16位模式,这里选择16位模式
    参数5 : 写入寄存器的数据
    参数6 : 写入的数据长度
    参数7 : 等待超时时间,超出此时间未发出去,则发送失败
  • HAL_I2C_Mem_Read(未写的参数和上面的一样)
    参数2 : gt911的读地址,0xBB(0x29)
    参数5 : 要读出的寄存器的数据缓冲区
    参数6 : 读出数据缓冲区大小
  • 第一步:软件复位

    通过给寄存器0x8040地址的寄存器写入2,复位gt911芯片.,代码如下所示

    /*
    	功能:软件复位gt911
    */
    void Software_Reset(void)
    {
    	uint8_t _temp=2;	//中间变量
    	//往gt911中寄存器0x8040中写入2,使之复位
    	GT911_WriteReg(GT_CTRL_REG, &_temp, 1);	
    }
    

    第二步:往配置寄存器中写入数据(一般可以跳过)

    代码如下:

    //GT911(原GT9147)配置参数表
    //第一个字节为版本号(0X60),必须保证新的版本号大于等于GT911内部
    //flash原有版本号,才会更新配置.
    const uint8_t GT9147_CFG_TBL[]=
    { 
    	0X60,0XE0,0X01,0X20,0X03,0X05,0X35,0X00,0X02,0X08,
    	0X1E,0X08,0X50,0X3C,0X0F,0X05,0X00,0X00,0XFF,0X67,
    	0X50,0X00,0X00,0X18,0X1A,0X1E,0X14,0X89,0X28,0X0A,
    	0X30,0X2E,0XBB,0X0A,0X03,0X00,0X00,0X02,0X33,0X1D,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X32,0X00,0X00,
    	0X2A,0X1C,0X5A,0X94,0XC5,0X02,0X07,0X00,0X00,0X00,
    	0XB5,0X1F,0X00,0X90,0X28,0X00,0X77,0X32,0X00,0X62,
    	0X3F,0X00,0X52,0X50,0X00,0X52,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,
    	0X0F,0X03,0X06,0X10,0X42,0XF8,0X0F,0X14,0X00,0X00,
    	0X00,0X00,0X1A,0X18,0X16,0X14,0X12,0X10,0X0E,0X0C,
    	0X0A,0X08,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X29,0X28,0X24,0X22,0X20,0X1F,0X1E,0X1D,
    	0X0E,0X0C,0X0A,0X08,0X06,0X05,0X04,0X02,0X00,0XFF,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
    	0XFF,0XFF,0XFF,0XFF
    };
    
    /*
    	配置gt911,发送gt911配置参数
    	参数1:mode(0,参数不保存到flash1,参数保存到flash)
    */
    void GT911_Send_Config(uint8_t mode)
    {
    	uint8_t buf[2];
    	
    	buf[0] = 0;
    	buf[1] = mode;	//是否写入到GT9147 FLASH?  即是否掉电保存
    	for(uint8_t i=0; i<sizeof(GT9147_CFG_TBL); i++)
    	{
    		buf[0] += GT9147_CFG_TBL[i];//计算校验和
    	}
      	buf[0]=(~buf[0])+1;
    	
    	GT911_WriteReg(GT_CFGS_REG, (uint8_t *)GT9147_CFG_TBL, sizeof(GT9147_CFG_TBL));//发送寄存器配置
    	
    	GT911_WriteReg(GT_CHECK_REG, buf, 2);//写入校验和,和配置更新标记
    }
    

    第三步:结束软件复位

    通过给寄存器0x8040地址的寄存器写入0,结束复位gt911芯片,代码如下所示

    /*
    	功能:软件复位gt911
    */
    void Software_Reset(void)
    {
    	uint8_t _temp=0;	//中间变量
    	//往gt911中寄存器0x8040中写入0,使之结束复位
    	GT911_WriteReg(GT_CTRL_REG, &_temp, 1);	
    }
    

    gt911使用说明

    判断是否被触摸

    当我们触摸屏幕时,

    1. 寄存器0x814E的最高位(bit7)位会被置位为1, 低4位为触摸的点的数量, 最多支持5个点。我们只要在while中不断轮询判断, 寄存器最高位是否置位,就可以知道, 屏幕是否被触摸(轮询时间长一点要不然会读不出来的, 可以在函数中设置一个计数阀门,当进入一定次数读取一次寄存器,再判断。)

    2. INT引脚会输出一个边沿信号, 我们只要在单片机中, 设置对应的连接引脚为中断引脚, 就可以实时知道屏幕是否被触摸 ,这里我不用这个判断方法。

    注意事项:当我们读完寄存器0x814E后, 要清0该寄存器, 表示已读, 要不然他会不断输出中断信号。

    触摸后读出数据

    这里表示的是所有的5个位置的信息数据, 我们就拿第一个来举例:

    每个位置信息都由16+16+16位数据表示, 第一个16位是x的位置数据, 第二个16位是y的位置数据, 第三个是位置上的触摸面积。

    每个16位又由两个寄存器的8位数据构成,先是低8位,后是高8位。

    我们只要在
    寄存器0x8150中读出x的低8位数据,
    然后读出寄存器0x8151读出x的高8位数据,
    把数据组合成x的16位的数据,

    y的数据, 触摸面积数据读出方式一样。

    触摸轮询代码

    代码如下所示:

    /*
    	功能:gt911触摸扫描,判断当前是否被触摸
    	参数1:
    */
    void gt911_Scanf(void)
    {
    	static uint8_t timer_=0;
    	timer_++;
    	if(timer_<10)
    	{
    		return;
    	}
    	timer_=0;
    	
    	uint8_t _temp;	//中间变量
    	
    	GT911_ReadReg(GT_GSTID_REG, &_temp, 1);
    	
    	User_Touch.Touch_State = (_temp & 0x80);	//触摸状态
    	User_Touch.Touch_Number = (_temp & 0x0f);	//获取触摸点数
    	
    	switch(User_Touch.Touch_State)	//判断是否有触摸数据
    	{
    		case TOUCH__NO:		//没有数据
    			
    		break;
    		case TOUCH_ING:		//触摸中~后,有数据,并读出数据
    			
    			for(uint8_t i=0; i<User_Touch.Touch_Number; i++)
    			//读出触摸点数的所有数据
    			{
    				GT911_ReadReg((GT_TPD_Sta + i*8 + X_L), &_temp, 1);	//读出触摸x坐标的低8位
    				User_Touch.Touch_XY[i].X_Point  = _temp;
    				GT911_ReadReg((GT_TPD_Sta + i*8 + X_H), &_temp, 1);	//读出触摸x坐标的高8位
    				User_Touch.Touch_XY[i].X_Point |= (_temp<<8);
    				
    				GT911_ReadReg((GT_TPD_Sta + i*8 + Y_L), &_temp, 1);	//读出触摸y坐标的低8位
    				User_Touch.Touch_XY[i].Y_Point  = _temp;
    				GT911_ReadReg((GT_TPD_Sta + i*8 + Y_H), &_temp, 1);	//读出触摸y坐标的高8位
    				User_Touch.Touch_XY[i].Y_Point |= (_temp<<8);
    				
    				GT911_ReadReg((GT_TPD_Sta + i*8 + S_L), &_temp, 1);	//读出触摸大小数据的低8位
    				User_Touch.Touch_XY[i].S_Point  = _temp;
    				GT911_ReadReg((GT_TPD_Sta + i*8 + S_H), &_temp, 1);	//读出触摸大小数据的高8位
    				User_Touch.Touch_XY[i].S_Point |= (_temp<<8);
    			}
    			
    			_temp=0;
    			GT911_WriteReg(GT_GSTID_REG, &_temp, 1);	//清除数据标志位
    		break;
    	}
    }
    

    代码完整版本

    gt911.c

    #include "gt911.h"
    #include "O_redirect.h"
    
    //GT911(原GT9147)配置参数表
    //第一个字节为版本号(0X60),必须保证新的版本号大于等于GT911内部
    //flash原有版本号,才会更新配置.
    const uint8_t GT9147_CFG_TBL[]=
    { 
    	0X60,0XE0,0X01,0X20,0X03,0X05,0X35,0X00,0X02,0X08,
    	0X1E,0X08,0X50,0X3C,0X0F,0X05,0X00,0X00,0XFF,0X67,
    	0X50,0X00,0X00,0X18,0X1A,0X1E,0X14,0X89,0X28,0X0A,
    	0X30,0X2E,0XBB,0X0A,0X03,0X00,0X00,0X02,0X33,0X1D,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X32,0X00,0X00,
    	0X2A,0X1C,0X5A,0X94,0XC5,0X02,0X07,0X00,0X00,0X00,
    	0XB5,0X1F,0X00,0X90,0X28,0X00,0X77,0X32,0X00,0X62,
    	0X3F,0X00,0X52,0X50,0X00,0X52,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,
    	0X0F,0X03,0X06,0X10,0X42,0XF8,0X0F,0X14,0X00,0X00,
    	0X00,0X00,0X1A,0X18,0X16,0X14,0X12,0X10,0X0E,0X0C,
    	0X0A,0X08,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0X00,0X29,0X28,0X24,0X22,0X20,0X1F,0X1E,0X1D,
    	0X0E,0X0C,0X0A,0X08,0X06,0X05,0X04,0X02,0X00,0XFF,
    	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    	0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
    	0XFF,0XFF,0XFF,0XFF
    };  
    
    /*创建触摸结构体*/
    Touch_Struct	User_Touch;
    
    
    void GT911_WriteReg(uint16_t _usRegAddr, uint8_t *_pRegBuf, uint8_t _ucLen)
    {
    	HAL_I2C_Mem_Write(&GT911_I2C, GT911_DIV_W, _usRegAddr, I2C_MEMADD_SIZE_16BIT, _pRegBuf, _ucLen, 0xff);
    }
    void GT911_ReadReg(uint16_t _usRegAddr, uint8_t *_pRegBuf, uint8_t _ucLen)
    {
    	HAL_I2C_Mem_Read(&GT911_I2C, GT911_DIV_R, _usRegAddr, I2C_MEMADD_SIZE_16BIT, _pRegBuf, _ucLen, 0xff);
    }
    
    
    /*
    	配置gt911,发送gt911配置参数
    	参数1:mode(0,参数不保存到flash1,参数保存到flash)
    */
    void GT911_Send_Config(uint8_t mode)
    {
    	uint8_t buf[2];
    	
    	buf[0] = 0;
    	buf[1] = mode;	//是否写入到GT9147 FLASH?  即是否掉电保存
    	for(uint8_t i=0; i<sizeof(GT9147_CFG_TBL); i++)
    	{
    		buf[0] += GT9147_CFG_TBL[i];//计算校验和
    	}
      buf[0]=(~buf[0])+1;
    	
    	GT911_WriteReg(GT_CFGS_REG, (uint8_t *)GT9147_CFG_TBL, sizeof(GT9147_CFG_TBL));//发送寄存器配置
    	
    	GT911_WriteReg(GT_CHECK_REG, buf, 2);//写入校验和,和配置更新标记
    }
    
    
    /*
    	功能:软件复位gt911
    	参数1:gt_SR_type(为1时开始软件复位,为0时结束软件复位)
    */
    void Software_Reset(uint8_t gt_SR_type)
    {
    	uint8_t _temp=0;	//中间变量
    	if(gt_SR_type)
    	{
    		_temp=2;
    		GT911_WriteReg(GT_CTRL_REG, &_temp, 1);
    	}
    	else
    	{
    		_temp=0;
    		GT911_WriteReg(GT_CTRL_REG, &_temp, 1);
    	}
    }
    
    /*
    	功能:gt911触摸扫描,判断当前是否被触摸
    	参数1:
    */
    void gt911_Scanf(void)
    {
    	static uint8_t timer_=0;
    	timer_++;
    	if(timer_<10)		//防止短时间多次进入判断
    	{
    		return;
    	}
    	timer_=0;
    	
    	uint8_t _temp;	//中间变量
    	
    	GT911_ReadReg(GT_GSTID_REG, &_temp, 1);//读0x814E寄存器
    	
    	User_Touch.Touch_State = _temp;
    	
    	User_Touch.Touch_Number = (User_Touch.Touch_State & 0x0f);	//获取触摸点数
    	User_Touch.Touch_State = (User_Touch.Touch_State & 0x80);	//触摸状态
    	
    	switch(User_Touch.Touch_State)	//判断是否有触摸数据
    	{
    		case TOUCH__NO:		//没有数据
    			
    		break;
    		case TOUCH_ING:		//触摸中~后,有数据,并读出数据
    			
    			for(uint8_t i=0; i<User_Touch.Touch_Number; i++)
    			{
    				GT911_ReadReg((GT_TPD_Sta + i*8 + X_L), &_temp, 1);	//读出触摸x坐标的低8位
    				User_Touch.Touch_XY[i].X_Point  = _temp;
    				GT911_ReadReg((GT_TPD_Sta + i*8 + X_H), &_temp, 1);	//读出触摸x坐标的高8位
    				User_Touch.Touch_XY[i].X_Point |= (_temp<<8);
    				
    				GT911_ReadReg((GT_TPD_Sta + i*8 + Y_L), &_temp, 1);	//读出触摸y坐标的低8位
    				User_Touch.Touch_XY[i].Y_Point  = _temp;
    				GT911_ReadReg((GT_TPD_Sta + i*8 + Y_H), &_temp, 1);	//读出触摸y坐标的高8位
    				User_Touch.Touch_XY[i].Y_Point |= (_temp<<8);
    				
    				GT911_ReadReg((GT_TPD_Sta + i*8 + S_L), &_temp, 1);	//读出触摸大小数据的低8位
    				User_Touch.Touch_XY[i].S_Point  = _temp;
    				GT911_ReadReg((GT_TPD_Sta + i*8 + S_H), &_temp, 1);	//读出触摸大小数据的高8位
    				User_Touch.Touch_XY[i].S_Point |= (_temp<<8);
    			}
    			
    			_temp=0;
    			GT911_WriteReg(GT_GSTID_REG, &_temp, 1);	//清除数据标志位
    		break;
    	}
    }
    
    

    gt911.h

    #ifndef __GT911_H_
    #define __GT911_H_
    
    #include "i2c.h"
    
    /*I2C句柄*/
    #define		GT911_I2C			hi2c1
    
    #define		GT911_DIV_ID	0XBA	//设备地址 //0X28 //0XBA
    
    #define 	GT911_DIV_W		(GT911_DIV_ID | 0)	//写地址
    #define 	GT911_DIV_R		(GT911_DIV_ID | 1)	//读地址
    
    
    
    //GT911 部分寄存器定义 
    #define GT_CTRL_REG 	0X8040   	//GT911控制寄存器
    #define GT_CFGS_REG 	0X8047   	//GT911配置起始地址寄存器
    #define GT_CHECK_REG 	0X80FF   	//GT911校验和寄存器
    #define GT_PID_REG 		0X8140   	//GT911产品ID寄存器
     
    #define GT_GSTID_REG 	0X814E   	//GT911当前检测到的触摸情况,第7位是触摸标志位,低4位是触摸点数个数
    
    #define GT_TPD_Sta		0X8150		//触摸点起始数据地址
    #define GT_TP1_REG 		0X8150  	//第一个触摸点数据地址
    #define GT_TP2_REG 		0X8158		//第二个触摸点数据地址
    #define GT_TP3_REG 		0X8160		//第三个触摸点数据地址
    #define GT_TP4_REG 		0X8168		//第四个触摸点数据地址
    #define GT_TP5_REG 		0X8170		//第五个触摸点数据地址
    
    
    #define GT_TOUCH_MAX			5			//对于gt911,最多同时获取5个触摸点的数据
    
    typedef enum
    {
    	X_L = 0,
    	X_H = 1,
    	Y_L = 2,
    	Y_H = 3,
    	S_L	= 4,
    	S_H = 5
    }Data_XYS_P;	//数据X、Y、触摸大小数据偏移量
    
    typedef enum
    {
    	TOUCH__NO		= 0x00,	//没有触摸
    	TOUCH_ING		= 0x80	//被触摸	
    }TOUCH_STATE_enum;	//触摸状态
    
    typedef struct
    {
    	uint16_t	X_Point;	//X坐标
    	uint16_t	Y_Point;	//Y坐标
    	uint16_t	S_Point;	//触摸点大小
    }XY_Coordinate;	//触摸点坐标
    
    
    /*触摸结构体*/
    typedef struct 
    {
    	uint8_t Touch_State				;	//触摸状态
    	uint8_t Touch_Number			;	//触摸数量
    	XY_Coordinate Touch_XY[GT_TOUCH_MAX]	;	//触摸的x坐标,对于gt911最多5个点的坐标
    }Touch_Struct;	//触摸信息结构体
    
    
    /*外部变量区*/
    extern Touch_Struct	User_Touch;
    
    
    
    /*外部函数区*/
    void GT911_WriteReg(uint16_t _usRegAddr, uint8_t *_pRegBuf, uint8_t _ucLen);
    void GT911_ReadReg(uint16_t _usRegAddr, uint8_t *_pRegBuf, uint8_t _ucLen);
    
    void GT911_Send_Config(uint8_t mode);		//配置初始化ft911
    void Software_Reset(uint8_t gt_SR_type);//复位或者不复位gt911
    void gt911_Scanf(void);									//扫描触摸模块
    
    
    
    
    
    
    
    #endif /*__GT911_H_*/
    
    

    main.c

    头文件引用

    #include "gt911.h"
    

    my_gt911函数

    	gt911_Scanf();		//不断扫描
    	
    	if(User_Touch.Touch_State == 0x80)
    	{
    		for(uint8_t i=0; i<User_Touch.Touch_Number; i++)
    		{
    			PrintfDebug("X : %d  ", User_Touch.Touch_XY[i].X_Point);
    			PrintfDebug("Y : %d  ", User_Touch.Touch_XY[i].Y_Point);
    			PrintfDebug("S : %d\r\n\r\n", User_Touch.Touch_XY[i].S_Point);
    		}
    		User_Touch.Touch_State  = 0;
    		User_Touch.Touch_Number = 0;
    	}
    	
    

    主函数部分

    效果

    参考资料

    一、数据手册

    二、电容触摸屏GT911、GT928、GT9147的使用

    物联沃分享整理
    物联沃-IOTWORD物联网 » Hal编程驱动GT911触摸芯片:枚举、结构体及其应用——安富莱F429 4.3寸电容屏

    发表评论