STM32F7驅動GT9147電容觸摸屏控制芯片,並移植到STemWin

目錄

一  電阻驅動與電容驅動原理

二 軟件模擬IIC

三 GT9147電容觸摸屏控制芯片驅動

四 移植觸摸屏驅動到STemWin


一  電阻驅動與電容驅動原理

1. 電阻屏等效電路如下所示, 當產生按壓時:
X-接地,X+接電源,Y+接ADC輸入.通過讀取Y+的電壓以及電阻分壓原理,可以得出觸點的x座標
Y-接地,Y+接電源,X+接ADC輸入.通過讀取X+的電壓以及電阻分壓原理,可以得出觸點的y座標

2. 電容屏等效圖如下所示, 檢測原理類似矩陣按鍵, 當產生按壓時:

X軸產生從上至下依次產生激勵信號(AC交流信號), Y軸電極同時接受信號 (該激勵信號是交流電,可以通過電容穿到Y軸).

假設有如下兩個按壓點(分別位於(1,1)與(2,2)的位置),檢測過程如下:
當X1產生激勵信號時,Y1接受到的交流信號產生了變化, 所以可以確認(1,1)處有觸摸.
接着噹噹X2產生激勵信號時,Y2接受到的交流信號產生了變化, 所以可以確認(2,2)處也有有觸摸.

二 軟件模擬IIC

由於stm32的硬件iic有各種各樣的問題,所以採用軟件模擬IIC的方式,主要實現IIC起始信號函數、IIC停止信號函數、等待ACK函數、產生ACK應答函數、不產生ACK應答函數、發送字節函數、讀字節函數

1. 起始信號與停止信號

下圖是IIC起始信號與停止信號時序圖,通過觀察該圖編寫起始信號與停止信號函數。

  • 起始信號:當SCL爲高期間,SDA由高到低的跳變;啓動信號是一種電平跳變時序信號,而不是一個電平信號。
/***************************************************************************************
  * @brief  產生IIC起始信號,當SCL爲高期間,SDA由高到低的跳變
***************************************************************************************/
void CT_IIC_Start(void)
{
	CT_SDA_OUT();     //sda線輸出
    CT_IIC_SCL(1);
	CT_IIC_SDA(1);	  	  
	CT_Delay();
 	CT_IIC_SDA(0);
}
  • 停止信號:當SCL爲高期間,SDA由低到高的跳變;停止信號也是一種電平跳變時序信號,而不是一個電平信號。
/***************************************************************************************
  * @brief  產生IIC停止信號,當SCL爲高期間,SDA由低到高的跳變
***************************************************************************************/
void CT_IIC_Stop(void)
{
	CT_SDA_OUT();//sda線輸出
	CT_IIC_SCL(1);
	CT_IIC_SDA(0);//STOP:when CLK is high DATA change form low to high
	CT_Delay();
	CT_IIC_SDA(1);
}

在GT9147數據手冊中可以發現如下截圖所示內容,SCL在低電平期間至少保持1.3us,其他電平最小保持0.6

所以將IIC延時函數定時爲2us可以滿足所有時序。(一般支持最高速度400k的IIC設備,基本都可以使用2us延時。)

//控制I2C速度的延時
void CT_Delay(void)
{
	delay_us(2);
}

2. 數據傳輸 與 ACK時序

下圖是ACK時序與 傳輸數據0的時序圖,這兩種時序圖是一樣的,區別在於ACK是在8個數據時序後產生,且SDA電平是由接受數據端拉低的。

  • 產生ACK時序:在SCL高電平期間,SDA爲低電平狀態。
/***************************************************************************************
  * @brief  產生ACK應答,
***************************************************************************************/
void CT_IIC_Ack(void)
{
	CT_IIC_SCL(0);
	CT_Delay();
        CT_SDA_OUT();
	CT_IIC_SDA(0);
	CT_IIC_SCL(1);
	CT_Delay();
	CT_IIC_SCL(0);
}
  • 等待ACK時序:拉高SCL與SDA後, 然後設置SDA爲輸入檢測狀態,等待接受數據端拉低SDA
/***************************************************************************************
  * @brief   等待應答信號到來,等待接受數據端拉低SDA
  * @input   
  * @return  1,接收應答失敗 ; 0,接收應答成功
***************************************************************************************/
uint8_t CT_IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	CT_IIC_SDA(1);	   
	CT_IIC_SCL(1);
        CT_SDA_IN();      //SDA設置爲輸入  
	while(CT_READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250){
			CT_IIC_Stop();
			return 1;
		}
		CT_Delay();
	}
	CT_IIC_SCL(0);
	return 0;  
}

下圖是nACK時序與 傳輸數據1的時序圖,這兩種時序圖是一樣的,區別在於ACK是在8個數據時序後產生,且SDA電平是由接受數據端拉低的。

  • 產生ACK時序:在SCL高電平期間,SDA爲高電平狀態。
/***************************************************************************************
  * @brief  不產生ACK應答	
***************************************************************************************/
void CT_IIC_NAck(void)
{
	CT_IIC_SCL(0);
	CT_Delay();
        CT_SDA_OUT();
	CT_IIC_SDA(1);
	CT_IIC_SCL(1);
	CT_Delay();
	CT_IIC_SCL(0);
}
  • 發送一個字節函數,優先發送高位,即從bit7開始發送。
/***************************************************************************************
  * @brief   IIC發送一個字節,
  * @input   
  * @return  
***************************************************************************************/
void CT_IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;   
    CT_SDA_OUT(); 	    
    CT_IIC_SCL(0);//拉低時鐘開始數據傳輸
    CT_Delay();
    for(t=0;t<8;t++)
    {
        CT_IIC_SDA((txd&0x80)>>7);//發送bit7位
        txd<<=1; //將txd的次高位左移到最高位	      
        CT_IIC_SCL(1); 
        CT_Delay();
        CT_IIC_SCL(0);	
        CT_Delay();
    }
}
  • 讀字一個字節函數,接受到1bit數據後,將該bit放在bit0位置(通過receive++實現),如果還要繼續接受數據,則將之前接受到的數據左移一位(通過receive<<=1實現),留出bit0位置接受新的數據。
/***************************************************************************************
  * @brief   讀1個字節
  * @input   ack=1時,發送ACK,ack=0,發送nACK
  * @return  
***************************************************************************************/
uint8_t CT_IIC_Read_Byte(unsigned char ack)
{
	uint8_t i,receive=0;
 	CT_SDA_IN();//SDA設置爲輸入
	CT_Delay();
	for(i=0;i<8;i++ )
	{ 
		CT_IIC_SCL(0); 	    	   
		CT_Delay();
		CT_IIC_SCL(1);	 
		receive<<=1;
		if(CT_READ_SDA)receive++;   
	}	  				 
	if (!ack)
        CT_IIC_NAck();//發送nACK
	else 
        CT_IIC_Ack(); //發送ACK   
 	return receive;
}

三 GT9147電容觸摸屏控制芯片驅動

1. GT914內部結構框圖如下圖所示

引腳 說明
AVDD、AVDD18、DVDD12、VDDDIO、GND 電源和地
Driving channels 激勵信號輸出的引腳,一共有 0-17 個引腳,它連接到電容屏引出的各個激勵信號軸
Sensing channels 信號檢測引腳,一共有 0-9 個引腳,它連接到電容屏 引出的各個電容量檢測信號軸
I2C I2C 通信信號線,包含 SCL與 SDA,外部控制器通過它與 GT9147 芯片通訊
INT 中斷信號,GB9147 芯片通過它告訴外部控制器有新的觸摸事件
/RSTB 復位引腳,用於復位 GT9157 芯片;在上電時還與 INT 引腳配合設置 IIC 通訊的設備地址

2. 上電流程

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

  • 配置RST輸出低電平,INT輸出低(或者高)電平後,位置100us以上,此階段配置IIC地址爲 0xBA/0xBB(或者0x28/0x29)
  • 接着配置RST輸出高電平並維持5ms以上後,可以配置INT引腳爲懸浮輸入模式。
  • 等待50ms以上後,可以發送配置信息。

代碼參考原子例程編寫,貼上代碼:

uint8_t GT9147_Init(void)
{
    uint8_t temp[5];
    
    GPIO_InitTypeDef GPIO_Initure;
    
    GPIO_Initure.Pin = GPIO_PIN_7;          //PH7
    GPIO_Initure.Mode = GPIO_MODE_INPUT;    //輸出
    GPIO_Initure.Pull = GPIO_PULLUP;        //上拉
    GPIO_Initure.Speed = GPIO_SPEED_HIGH;   //高速
    HAL_GPIO_Init(GPIOH, &GPIO_Initure);    //初始化
    
    GPIO_Initure.Pin = GPIO_PIN_8;           //PI8
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推輓輸出
    HAL_GPIO_Init(GPIOI, &GPIO_Initure);     //初始化
    
    CT_IIC_Init();      	//初始化電容屏的I2C總線

    GT_RST(0);				//復位
    delay_ms(1);            //INT引腳電平維持100us以上
    GT_RST(1);				//釋放復位
    delay_ms(10);           //釋放復位後維持5ms以上,設置INT爲懸浮輸入
    GPIO_Initure.Pin = GPIO_PIN_7;
    GPIO_Initure.Mode = GPIO_MODE_IT_RISING;
    GPIO_Initure.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOH, &GPIO_Initure);    //初始化
    delay_ms(60);

    GT9147_RD_Reg(GT_PID_REG, temp, 4); //讀取產品ID
    temp[4] = 0;
    printf("CTP ID:0x%s\r\n", temp);	//打印ID

    GT9147_Send_Cfg(1);//更新並保存配置

    return 1;
}

3. 讀取座標流程

使用中斷方式讀取座標,需要注意的是,如果不及時讀取座標信息會一直產生中斷。GT9147的中斷腳與STM32的LINE7中斷線相連,中斷回調函數如下所示。當按下觸摸屏時,touch_x與touch_y分別保存觸摸時的xy座標;當鬆開觸摸屏時,touch_x,touch_y賦值0xffff

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    uint8_t buf[4];
    uint8_t i = 0, mode = 0, temp = 0;
    uint16_t x[5], y[5];
    if(GPIO_Pin == GPIO_PIN_7) { //讀取座標, 否則會一直有INT脈衝
        GT9147_RD_Reg(GT_GSTID_REG, &mode, 1);	//讀取觸摸點的狀態
        if(mode & 0X80 && ((mode & 0XF) < 6)) //有座標可讀取
        {
            temp = 0;
            GT9147_WR_Reg(GT_GSTID_REG, &temp, 1);//清標誌
        }
        if( (mode & 0xF) && ((mode & 0xF) < 6)) //判斷觸摸點個數
        {
            for(i = 0; i < (mode & 0xF); i++)
            {
                GT9147_RD_Reg(GT9147_TPX_TBL[i], buf, 4);	//讀取XY座標值
                x[i] = (((uint16_t)buf[1] << 8) + buf[0]);
                y[i] = (((uint16_t)buf[3] << 8) + buf[2]);
            }
            touch_x = x[0];
            touch_y = y[0];
        }
        
        if((mode&0x8F)==0x80)//無觸摸點按下,xy賦值爲0xffff
        {
          touch_x = 0xffff;
          touch_y = 0xffff;
        }
    }
}

4.主機 對 GT9147 進行讀操作時序

根據該時序圖編寫讀寄存器函數如下:

/***************************************************************************************
  * @brief   從GT9147讀出一次數據
  * @input   reg:起始寄存器地址
             buf:數據緩緩存區
             len:讀數據長度	
  * @return  
***************************************************************************************/
void GT9147_RD_Reg(uint16_t reg,uint8_t *buf,uint8_t len)
{
	uint8_t i; 
 	CT_IIC_Start();	
 	CT_IIC_Send_Byte(GT_CMD_WR);   //發送寫命令 	 
	CT_IIC_Wait_Ack();
 	CT_IIC_Send_Byte(reg>>8);   	//發送高8位地址
	CT_IIC_Wait_Ack(); 	 										  		   
 	CT_IIC_Send_Byte(reg&0XFF);   	//發送低8位地址
	CT_IIC_Wait_Ack();  
 	CT_IIC_Start();  	 	   
	CT_IIC_Send_Byte(GT_CMD_RD);   //發送讀命令		   
	CT_IIC_Wait_Ack();	   
	for(i=0;i<len;i++)
	{
    	buf[i]=CT_IIC_Read_Byte(i==(len-1)?0:1); //發數據	  
	}
        CT_IIC_Stop();//產生一個停止條件    
}

5.主機對 GT9147 進行寫操作時序

通過該時序圖,編寫寫寄存器函數如下

/***************************************************************************************
  * @brief   向GT9147寫入一次數據
  * @input   reg:起始寄存器地址; 
             buf:數據緩緩存區
             len:寫數據長度
  * @return  0,成功; 1,失敗.
***************************************************************************************/
uint8_t GT9147_WR_Reg(uint16_t reg,uint8_t *buf,uint8_t len)
{
	uint8_t i;
	uint8_t ret=0;
	CT_IIC_Start();	
 	CT_IIC_Send_Byte(GT_CMD_WR);   	//發送寫命令 	 
	CT_IIC_Wait_Ack();
	CT_IIC_Send_Byte(reg>>8);   	//發送高8位地址
	CT_IIC_Wait_Ack(); 	 										  		   
	CT_IIC_Send_Byte(reg&0XFF);   	//發送低8位地址
	CT_IIC_Wait_Ack();  
	for(i=0;i<len;i++)
	{
    	CT_IIC_Send_Byte(buf[i]);  	//發數據
		ret = CT_IIC_Wait_Ack();
		if(ret)break;  
	}
    CT_IIC_Stop();					//產生一個停止條件	    
	return ret; 
}

6. GT9147配置函數如下,GT9147_CFG_TBL針對分辨率480×272的觸摸屏。

配置寄存器時是要注意以下幾點:

  • 新的版本號大於等於GT9147內部flash原有版本號,纔會更新配置.
  • 寫完GT9147_CFG_TBL中的配置後,還需要往0x80FF寄存器中寫入校驗,0x8100寄存器中寫1。
  • 關於配置更詳細的信息可以參考GT9147編程參考手冊
const uint8_t GT9147_CFG_TBL[]=
{
    0x60,0xe0,0x01,0x10,0x01,0x05,0x0C,0x00,0x01,0x08,
    0x28,0x05,0x50,0x32,0x03,0x05,0x00,0x00,0xff,0xff,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89,0x28,0x0a,
    0x17,0x15,0x31,0x0d,0x00,0x00,0x02,0x9b,0x03,0x25,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,
    0x00,0x0f,0x94,0x94,0xc5,0x02,0x07,0x00,0x00,0x04,
    0x8d,0x13,0x00,0x5c,0x1e,0x00,0x3c,0x30,0x00,0x29,
    0x4c,0x00,0x1e,0x78,0x00,0x1e,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,
    0x18,0x1a,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0x00,0x02,0x04,0x05,0x06,0x08,0x0a,0x0c,
    0x0e,0x1d,0x1e,0x1f,0x20,0x22,0x24,0x28,0x29,0xff,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,
};

uint8_t GT9147_Send_Cfg(uint8_t mode)
{
	uint8_t buf[2];
	uint8_t i=0;
	buf[0]=0;
	buf[1]=mode;	//是否寫入到GT9147 FLASH?  即是否掉電保存
	for(i=0;i<sizeof(GT9147_CFG_TBL);i++)
            buf[0]+=GT9147_CFG_TBL[i];//計算校驗和
        buf[0]=(~buf[0])+1;
	GT9147_WR_Reg(GT_CFGS_REG,(uint8_t*)GT9147_CFG_TBL,sizeof(GT9147_CFG_TBL));//發送寄存器配置
	GT9147_WR_Reg(GT_CHECK_REG,buf,2);//寫入校驗和,和配置更新標記
	return 0;
}

四 移植觸摸屏驅動到STemWin

這裏假設已經成功移植了STemWin到STM32F7工程。

1. 在GUIConf打開STemWin觸摸屏驅動宏

#define GUI_SUPPORT_TOUCH       (1)  // Support touchscreen

2. 新建GUI_X_Touch_Analog.c文件實現以下四個函數,在第三章第3小節我們知道touch_x,touch_y表示當前觸摸的xy座標。整個文件的內容如下所示。

void GUI_TOUCH_X_ActivateX(void) 
{

}

void GUI_TOUCH_X_ActivateY(void)
{

}

/*獲取x座標*/
int  GUI_TOUCH_X_MeasureX (void)
{
  return touch_x;
}

/*獲取y座標*/
int  GUI_TOUCH_X_MeasureY (void)
{
  return touch_y;
}

3. 使用GUI_TOUCH_Calibrate函數校準x與y值,然後才能調用GUI_TOUCH_Exec()函數處理觸摸事件。

void StartTouchTask(void const * argument)
{
  /* USER CODE BEGIN StartTouchTask */
  GUI_CURSOR_Show();//顯示鼠標指針
  GUI_TOUCH_Calibrate(GUI_COORD_X,0,LCD_WIDTH,0,LCD_WIDTH);   
  GUI_TOUCH_Calibrate(GUI_COORD_Y,0,LCD_HEIGHT,0,LCD_HEIGHT);
  /* Infinite loop */
  for(;;)
  {
    GUI_TOUCH_Exec();
    osDelay(5);
  }
  /* USER CODE END StartTouchTask */
}

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章