你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7驱动GT9147电容触摸屏控制芯片,并移植到STemWin

[复制链接]
STMCU小助手 发布时间:2021-12-17 12:05
一  电阻驱动与电容驱动原理

1. 电阻屏等效电路如下所示, 当产生按压时:

X-接地,X+接电源,Y+接ADC输入.通过读取Y+的电压以及电阻分压原理,可以得出触点的x坐标
Y-接地,Y+接电源,X+接ADC输入.通过读取X+的电压以及电阻分压原理,可以得出触点的y坐标

2019061911075212.png


2. 电容屏等效图如下所示, 检测原理类似矩阵按键, 当产生按压时:

X轴产生从上至下依次产生激励信号(AC交流信号), Y轴电极同时接受信号 (该激励信号是交流电,可以通过电容穿到Y轴).

假设有如下两个按压点(分别位于(1,1)与(2,2)的位置),检测过程如下:
当X1产生激励信号时,Y1接受到的交流信号产生了变化, 所以可以确认(1,1)处有触摸.
接着当当X2产生激励信号时,Y2接受到的交流信号产生了变化, 所以可以确认(2,2)处也有有触摸.

20190619115448553.png


二 软件模拟IIC
由于stm32的硬件iic有各种各样的问题,所以采用软件模拟IIC的方式,主要实现IIC起始信号函数、IIC停止信号函数、等待ACK函数、产生ACK应答函数、不产生ACK应答函数、发送字节函数、读字节函数

1. 起始信号与停止信号

下图是IIC起始信号与停止信号时序图,通过观察该图编写起始信号与停止信号函数。

aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNDcwOTA5LzIwMTMwNS8yODE2MzczMy01MjE5.png


起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
  1. /***************************************************************************************
  2.   * @brief  产生IIC起始信号,当SCL为高期间,SDA由高到低的跳变
  3. ***************************************************************************************/
  4. void CT_IIC_Start(void)
  5. {
  6.         CT_SDA_OUT();     //sda线输出
  7.     CT_IIC_SCL(1);
  8.         CT_IIC_SDA(1);                    
  9.         CT_Delay();
  10.          CT_IIC_SDA(0);
  11. }
复制代码

停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
  1. /***************************************************************************************
  2.   * @brief  产生IIC停止信号,当SCL为高期间,SDA由低到高的跳变
  3. ***************************************************************************************/
  4. void CT_IIC_Stop(void)
  5. {
  6.         CT_SDA_OUT();//sda线输出
  7.         CT_IIC_SCL(1);
  8.         CT_IIC_SDA(0);//STOP:when CLK is high DATA change form low to high
  9.         CT_Delay();
  10.         CT_IIC_SDA(1);
  11. }
复制代码

在GT9147数据手册中可以发现如下截图所示内容,SCL在低电平期间至少保持1.3us,其他电平最小保持0.6

20190622160910729.png


所以将IIC延时函数定时为2us可以满足所有时序。(一般支持最高速度400k的IIC设备,基本都可以使用2us延时。)

  1. //控制I2C速度的延时
  2. void CT_Delay(void)
  3. {
  4.         delay_us(2);
  5. }
复制代码

2. 数据传输 与 ACK时序

下图是ACK时序与 传输数据0的时序图,这两种时序图是一样的,区别在于ACK是在8个数据时序后产生,且SDA电平是由接受数据端拉低的。

20190622161607756.png


产生ACK时序:在SCL高电平期间,SDA为低电平状态。
  1. /***************************************************************************************
  2.   * @brief  产生ACK应答,
  3. ***************************************************************************************/
  4. void CT_IIC_Ack(void)
  5. {
  6.         CT_IIC_SCL(0);
  7.         CT_Delay();
  8.         CT_SDA_OUT();
  9.         CT_IIC_SDA(0);
  10.         CT_IIC_SCL(1);
  11.         CT_Delay();
  12.         CT_IIC_SCL(0);
  13. }
复制代码

等待ACK时序:拉高SCL与SDA后, 然后设置SDA为输入检测状态,等待接受数据端拉低SDA
  1. /***************************************************************************************
  2.   * @brief   等待应答信号到来,等待接受数据端拉低SDA
  3.   * @input   
  4.   * @return  1,接收应答失败 ; 0,接收应答成功
  5. ***************************************************************************************/
  6. uint8_t CT_IIC_Wait_Ack(void)
  7. {
  8.         uint8_t ucErrTime=0;
  9.         CT_IIC_SDA(1);           
  10.         CT_IIC_SCL(1);
  11.         CT_SDA_IN();      //SDA设置为输入  
  12.         while(CT_READ_SDA)
  13.         {
  14.                 ucErrTime++;
  15.                 if(ucErrTime>250){
  16.                         CT_IIC_Stop();
  17.                         return 1;
  18.                 }
  19.                 CT_Delay();
  20.         }
  21.         CT_IIC_SCL(0);
  22.         return 0;  
  23. }
复制代码

下图是nACK时序与 传输数据1的时序图,这两种时序图是一样的,区别在于ACK是在8个数据时序后产生,且SDA电平是由接受数据端拉低的。

20190622164227486.png


产生ACK时序:在SCL高电平期间,SDA为高电平状态。
  1. /***************************************************************************************
  2.   * @brief  不产生ACK应答        
  3. ***************************************************************************************/
  4. void CT_IIC_NAck(void)
  5. {
  6.         CT_IIC_SCL(0);
  7.         CT_Delay();
  8.         CT_SDA_OUT();
  9.         CT_IIC_SDA(1);
  10.         CT_IIC_SCL(1);
  11.         CT_Delay();
  12.         CT_IIC_SCL(0);
  13. }
复制代码

发送一个字节函数,优先发送高位,即从bit7开始发送。
  1. /***************************************************************************************
  2.   * @brief   IIC发送一个字节,
  3.   * @input   
  4.   * @return  
  5. ***************************************************************************************/
  6. void CT_IIC_Send_Byte(uint8_t txd)
  7. {
  8.     uint8_t t;   
  9.     CT_SDA_OUT();            
  10.     CT_IIC_SCL(0);//拉低时钟开始数据传输
  11.     CT_Delay();
  12.     for(t=0;t<8;t++)
  13.     {
  14.         CT_IIC_SDA((txd&0x80)>>7);//发送bit7位
  15.         txd<<=1; //将txd的次高位左移到最高位              
  16.         CT_IIC_SCL(1);
  17.         CT_Delay();
  18.         CT_IIC_SCL(0);        
  19.         CT_Delay();
  20.     }
  21. }
复制代码

读字一个字节函数,接受到1bit数据后,将该bit放在bit0位置(通过receive++实现),如果还要继续接受数据,则将之前接受到的数据左移一位(通过receive<<=1实现),留出bit0位置接受新的数据。
  1. /***************************************************************************************
  2.   * @brief   读1个字节
  3.   * @input   ack=1时,发送ACK,ack=0,发送nACK
  4.   * @return  
  5. ***************************************************************************************/
  6. uint8_t CT_IIC_Read_Byte(unsigned char ack)
  7. {
  8.         uint8_t i,receive=0;
  9.          CT_SDA_IN();//SDA设置为输入
  10.         CT_Delay();
  11.         for(i=0;i<8;i++ )
  12.         {
  13.                 CT_IIC_SCL(0);                        
  14.                 CT_Delay();
  15.                 CT_IIC_SCL(1);         
  16.                 receive<<=1;
  17.                 if(CT_READ_SDA)receive++;   
  18.         }                                          
  19.         if (!ack)
  20.         CT_IIC_NAck();//发送nACK
  21.         else
  22.         CT_IIC_Ack(); //发送ACK   
  23.          return receive;
  24. }
复制代码

三 GT9147电容触摸屏控制芯片驱动
1. GT914内部结构框图如下图所示

2019061913180610.png


5L5)3BWQK[DM1E_`8%S}J0F.png


2. 上电流程

GT9147上电初始化流程如下所示:

配置RST输出低电平,INT输出低(或者高)电平后,位置100us以上,此阶段配置IIC地址为 0xBA/0xBB(或者0x28/0x29)
接着配置RST输出高电平并维持5ms以上后,可以配置INT引脚为悬浮输入模式。
等待50ms以上后,可以发送配置信息。

2019062113491579.png


代码参考原子例程编写,贴上代码:

  1. uint8_t GT9147_Init(void)
  2. {
  3.     uint8_t temp[5];

  4.     GPIO_InitTypeDef GPIO_Initure;

  5.     GPIO_Initure.Pin = GPIO_PIN_7;          //PH7
  6.     GPIO_Initure.Mode = GPIO_MODE_INPUT;    //输出
  7.     GPIO_Initure.Pull = GPIO_PULLUP;        //上拉
  8.     GPIO_Initure.Speed = GPIO_SPEED_HIGH;   //高速
  9.     HAL_GPIO_Init(GPIOH, &GPIO_Initure);    //初始化

  10.     GPIO_Initure.Pin = GPIO_PIN_8;           //PI8
  11.     GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
  12.     HAL_GPIO_Init(GPIOI, &GPIO_Initure);     //初始化

  13.     CT_IIC_Init();              //初始化电容屏的I2C总线

  14.     GT_RST(0);                                //复位
  15.     delay_ms(1);            //INT引脚电平维持100us以上
  16.     GT_RST(1);                                //释放复位
  17.     delay_ms(10);           //释放复位后维持5ms以上,设置INT为悬浮输入
  18.     GPIO_Initure.Pin = GPIO_PIN_7;
  19.     GPIO_Initure.Mode = GPIO_MODE_IT_RISING;
  20.     GPIO_Initure.Pull = GPIO_NOPULL;
  21.     HAL_GPIO_Init(GPIOH, &GPIO_Initure);    //初始化
  22.     delay_ms(60);

  23.     GT9147_RD_Reg(GT_PID_REG, temp, 4); //读取产品ID
  24.     temp[4] = 0;
  25.     printf("CTP ID:0x%s\r\n", temp);        //打印ID

  26.     GT9147_Send_Cfg(1);//更新并保存配置

  27.     return 1;
  28. }
复制代码

3. 读取坐标流程

使用中断方式读取坐标,需要注意的是,如果不及时读取坐标信息会一直产生中断。GT9147的中断脚与STM32的LINE7中断线相连,中断回调函数如下所示。当按下触摸屏时,touch_x与touch_y分别保存触摸时的xy坐标;当松开触摸屏时,touch_x,touch_y赋值0xffff

  1. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  2. {
  3.     uint8_t buf[4];
  4.     uint8_t i = 0, mode = 0, temp = 0;
  5.     uint16_t x[5], y[5];
  6.     if(GPIO_Pin == GPIO_PIN_7) { //读取坐标, 否则会一直有INT脉冲
  7.         GT9147_RD_Reg(GT_GSTID_REG, &mode, 1);        //读取触摸点的状态
  8.         if(mode & 0X80 && ((mode & 0XF) < 6)) //有坐标可读取
  9.         {
  10.             temp = 0;
  11.             GT9147_WR_Reg(GT_GSTID_REG, &temp, 1);//清标志
  12.         }
  13.         if( (mode & 0xF) && ((mode & 0xF) < 6)) //判断触摸点个数
  14.         {
  15.             for(i = 0; i < (mode & 0xF); i++)
  16.             {
  17.                 GT9147_RD_Reg(GT9147_TPX_TBL<i>, buf, 4);        //读取XY坐标值
  18.                 </i>x = (((uint16_t)buf[1] << 8) + buf[0]);
  19.                 y = (((uint16_t)buf[3] << 8) + buf[2]);
  20.             }
  21.             touch_x = x[0];
  22.             touch_y = y[0];
  23.         }

  24.         if((mode&0x8F)==0x80)//无触摸点按下,xy赋值为0xffff
  25.         {
  26.           touch_x = 0xffff;
  27.           touch_y = 0xffff;
  28.         }
  29.     }
  30. }
复制代码
4.主机 对 GT9147 进行读操作时序

20190621161601926.png


根据该时序图编写读寄存器函数如下:

  1. /***************************************************************************************
  2.   * @brief   从GT9147读出一次数据
  3.   * @input   reg:起始寄存器地址
  4.              buf:数据缓缓存区
  5.              len:读数据长度        
  6.   * @return  
  7. ***************************************************************************************/
  8. void GT9147_RD_Reg(uint16_t reg,uint8_t *buf,uint8_t len)
  9. {
  10.         uint8_t i;
  11.          CT_IIC_Start();        
  12.          CT_IIC_Send_Byte(GT_CMD_WR);   //发送写命令         
  13.         CT_IIC_Wait_Ack();
  14.          CT_IIC_Send_Byte(reg>>8);           //发送高8位地址
  15.         CT_IIC_Wait_Ack();                                                                                                               
  16.          CT_IIC_Send_Byte(reg&0XFF);           //发送低8位地址
  17.         CT_IIC_Wait_Ack();  
  18.          CT_IIC_Start();                     
  19.         CT_IIC_Send_Byte(GT_CMD_RD);   //发送读命令                  
  20.         CT_IIC_Wait_Ack();           
  21.         for(i=0;i<len;i++)
  22.         {
  23.             buf<span style="font-style: italic;"><span style="font-style: normal;">=CT_IIC_Read_Byte(i==(len-1)?0:1); //发数据         
  24.         }
  25.         CT_IIC_Stop();//产生一个停止条件   
  26. }</span></span>
复制代码

5.主机对 GT9147 进行写操作时序

20190621161509843.png


通过该时序图,编写写寄存器函数如下

  1. /***************************************************************************************
  2.   * @brief   向GT9147写入一次数据
  3.   * @input   reg:起始寄存器地址;
  4.              buf:数据缓缓存区
  5.              len:写数据长度
  6.   * @return  0,成功; 1,失败.
  7. ***************************************************************************************/
  8. uint8_t GT9147_WR_Reg(uint16_t reg,uint8_t *buf,uint8_t len)
  9. {
  10.         uint8_t i;
  11.         uint8_t ret=0;
  12.         CT_IIC_Start();        
  13.          CT_IIC_Send_Byte(GT_CMD_WR);           //发送写命令         
  14.         CT_IIC_Wait_Ack();
  15.         CT_IIC_Send_Byte(reg>>8);           //发送高8位地址
  16.         CT_IIC_Wait_Ack();                                                                                                               
  17.         CT_IIC_Send_Byte(reg&0XFF);           //发送低8位地址
  18.         CT_IIC_Wait_Ack();  
  19.         for(i=0;i<len;i++)
  20.         {
  21.             CT_IIC_Send_Byte(buf<span style="font-style: italic;"><span style="font-style: normal;">);          //发数据
  22.                 ret = CT_IIC_Wait_Ack();
  23.                 if(ret)break;  
  24.         }
  25.     CT_IIC_Stop();                                        //产生一个停止条件            
  26.         return ret;
  27. }</span></span>
复制代码

6. GT9147配置函数如下,GT9147_CFG_TBL针对分辨率480×272的触摸屏。

配置寄存器时是要注意以下几点:

新的版本号大于等于GT9147内部flash原有版本号,才会更新配置.
写完GT9147_CFG_TBL中的配置后,还需要往0x80FF寄存器中写入校验,0x8100寄存器中写1。
关于配置更详细的信息可以参考GT9147编程参考手册
  1. const uint8_t GT9147_CFG_TBL[]=
  2. {
  3.     0x60,0xe0,0x01,0x10,0x01,0x05,0x0C,0x00,0x01,0x08,
  4.     0x28,0x05,0x50,0x32,0x03,0x05,0x00,0x00,0xff,0xff,
  5.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89,0x28,0x0a,
  6.     0x17,0x15,0x31,0x0d,0x00,0x00,0x02,0x9b,0x03,0x25,
  7.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,
  8.     0x00,0x0f,0x94,0x94,0xc5,0x02,0x07,0x00,0x00,0x04,
  9.     0x8d,0x13,0x00,0x5c,0x1e,0x00,0x3c,0x30,0x00,0x29,
  10.     0x4c,0x00,0x1e,0x78,0x00,0x1e,0x00,0x00,0x00,0x00,
  11.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  12.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  13.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  14.     0x00,0x00,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,
  15.     0x18,0x1a,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,
  16.     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  17.     0xff,0xff,0x00,0x02,0x04,0x05,0x06,0x08,0x0a,0x0c,
  18.     0x0e,0x1d,0x1e,0x1f,0x20,0x22,0x24,0x28,0x29,0xff,
  19.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
  20.     0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  21.     0xff,0xff,0xff,0xff,
  22. };

  23. uint8_t GT9147_Send_Cfg(uint8_t mode)
  24. {
  25.         uint8_t buf[2];
  26.         uint8_t i=0;
  27.         buf[0]=0;
  28.         buf[1]=mode;        //是否写入到GT9147 FLASH?  即是否掉电保存
  29.         for(i=0;i<sizeof(GT9147_CFG_TBL);i++)
  30.             buf[0]+=GT9147_CFG_TBL<span style="font-style: italic;"><span style="font-style: normal;">;//计算校验和
  31.         buf[0]=(~buf[0])+1;
  32.         GT9147_WR_Reg(GT_CFGS_REG,(uint8_t*)GT9147_CFG_TBL,sizeof(GT9147_CFG_TBL));//发送寄存器配置
  33.         GT9147_WR_Reg(GT_CHECK_REG,buf,2);//写入校验和,和配置更新标记
  34.         return 0;
  35. }</span></span>
复制代码

四 移植触摸屏驱动到STemWin
这里假设已经成功移植了STemWin到STM32F7工程。

1. 在GUIConf打开STemWin触摸屏驱动宏

  1. #define GUI_SUPPORT_TOUCH       (1)  // Support touchscreen
复制代码

2. 新建GUI_X_Touch_Analog.c文件实现以下四个函数,在第三章第3小节我们知道touch_x,touch_y表示当前触摸的xy坐标。整个文件的内容如下所示。

  1. void GUI_TOUCH_X_ActivateX(void)
  2. {

  3. }

  4. void GUI_TOUCH_X_ActivateY(void)
  5. {

  6. }

  7. /*获取x坐标*/
  8. int  GUI_TOUCH_X_MeasureX (void)
  9. {
  10.   return touch_x;
  11. }

  12. /*获取y坐标*/
  13. int  GUI_TOUCH_X_MeasureY (void)
  14. {
  15.   return touch_y;
  16. }
复制代码

3. 使用GUI_TOUCH_Calibrate函数校准x与y值,然后才能调用GUI_TOUCH_Exec()函数处理触摸事件。

  1. void StartTouchTask(void const * argument)
  2. {
  3.   /* USER CODE BEGIN StartTouchTask */
  4.   GUI_CURSOR_Show();//显示鼠标指针
  5.   GUI_TOUCH_Calibrate(GUI_COORD_X,0,LCD_WIDTH,0,LCD_WIDTH);   
  6.   GUI_TOUCH_Calibrate(GUI_COORD_Y,0,LCD_HEIGHT,0,LCD_HEIGHT);
  7.   /* Infinite loop */
  8.   for(;;)
  9.   {
  10.     GUI_TOUCH_Exec();
  11.     osDelay(5);
  12.   }
  13.   /* USER CODE END StartTouchTask */
  14. }
复制代码




收藏 评论0 发布时间:2021-12-17 12:05

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版