STM32 TFT學習筆記——觸摸屏

主機環境:Windows 7 SP1

開發環境:MDK5.14

目標板:ST NUCLEO-F303RE

TFT型號:2.4英寸,帶觸摸,SD卡,240*320分辨率,26萬色

驅動IC:ILI9325

ST庫版本:STM32Cube_FW_F3_V1.1.0

SD卡:Kingston 16GB Micro SDHC Class 10

觸摸IC:XPT2046


關於XPT2016的說明可以從網上下載很多資料,XPT2046使用SPI通信接口,接口說明如下:

多出了一個BUSY腳和一個PENIRQ腳,BUSY信號指示XPT2046工作狀態,但是在使用過程中發現其不起作用,所以就沒用了,PENIRQ爲中斷指示腳,當觸摸屏有接觸時其信號會變成低電平。對於NUCLEO-F303RE來說SPI1接口在BSP裏面用作了SD卡接口,因此這裏使用SPI3接口來跟XPT2046進行通信,接口聲明如下

/* Definition for SPI_XPT2046 clock resources */
#define SPI_XPT2046							SPI3
#define SPI_XPT2046_CLK_ENABLE()			__SPI3_CLK_ENABLE()
#define SPI_XPT2046_CLK_DISABLE()			__SPI3_CLK_DISABLE()
#define SPI_XPT2046_nCS_GPIO_CLK_ENABLE()	__GPIOA_CLK_ENABLE()
#define SPI_XPT2046_SCK_GPIO_CLK_ENABLE()	__GPIOC_CLK_ENABLE()
#define SPI_XPT2046_MISO_GPIO_CLK_ENABLE()	__GPIOC_CLK_ENABLE()
#define SPI_XPT2046_MOSI_GPIO_CLK_ENABLE()	__GPIOC_CLK_ENABLE()

#define SPI_XPT2046_FORCE_RESET()			__SPI3_FORCE_RESET()
#define SPI_XPT2046_RELEASE_RESET()			__SPI3_RELEASE_RESET()

/* Definition for SPIx Pins */
#define SPI_XPT2046_SCK_PIN                 GPIO_PIN_10
#define SPI_XPT2046_SCK_GPIO_PORT           GPIOC
#define SPI_XPT2046_SCK_AF                  GPIO_AF6_SPI3
#define SPI_XPT2046_MISO_PIN                GPIO_PIN_11
#define SPI_XPT2046_MISO_GPIO_PORT          GPIOC
#define SPI_XPT2046_MISO_AF                 GPIO_AF6_SPI3
#define SPI_XPT2046_MOSI_PIN                GPIO_PIN_12
#define SPI_XPT2046_MOSI_GPIO_PORT          GPIOC
#define SPI_XPT2046_MOSI_AF                 GPIO_AF6_SPI3

#define SPI_XPT2046_nCS_PIN					GPIO_PIN_15
#define SPI_XPT2046_nCS_GPIO_PORT			GPIOA

#define SPI_XPT2046_nCS_Set_Low()			(GPIOA->BRR = GPIO_PIN_15)
#define SPI_XPT2046_nCS_Set_High()			(GPIOA->BSRRL = GPIO_PIN_15)

#define SPI_XPT2046_TIMEOUT					1000

XPT2046通信時序如下


通信主時鐘爲2MHz據此編輯我們的spi3初始化以及讀寫代碼

SPI_HandleTypeDef spi_xpt_Handle;
/**
  * @brief SPI MSP Initialization 
  *        This function configures the hardware resources used in this example: 
  *           - Peripheral's clock enable
  *           - Peripheral's GPIO Configuration  
  * @param hspi: SPI handle pointer
  * @retval None
  */
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	if(SPI_XPT2046 != hspi->Instance)
	{
		return ;
	}
   
	/*##-1- Enable peripherals and GPIO Clocks #################################*/
	/* Enable GPIO TX/RX clock */
	SPI_XPT2046_SCK_GPIO_CLK_ENABLE();
	SPI_XPT2046_MISO_GPIO_CLK_ENABLE();
	SPI_XPT2046_MOSI_GPIO_CLK_ENABLE();
	SPI_XPT2046_nCS_GPIO_CLK_ENABLE();
	/* Enable SPI clock */
	SPI_XPT2046_CLK_ENABLE(); 

	/*##-2- Configure peripheral GPIO ##########################################*/  
	/* SPI SCK GPIO pin configuration  */
	GPIO_InitStruct.Pin       = SPI_XPT2046_SCK_PIN;
	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
	GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
	GPIO_InitStruct.Alternate = SPI_XPT2046_SCK_AF;
	HAL_GPIO_Init(SPI_XPT2046_SCK_GPIO_PORT, &GPIO_InitStruct);

	/* SPI MISO GPIO pin configuration  */
	GPIO_InitStruct.Pin = SPI_XPT2046_MISO_PIN;
	GPIO_InitStruct.Alternate = SPI_XPT2046_MISO_AF;
	HAL_GPIO_Init(SPI_XPT2046_MISO_GPIO_PORT, &GPIO_InitStruct);

	/* SPI MOSI GPIO pin configuration  */
	GPIO_InitStruct.Pin = SPI_XPT2046_MOSI_PIN;
	GPIO_InitStruct.Alternate = SPI_XPT2046_MOSI_AF;
	HAL_GPIO_Init(SPI_XPT2046_MOSI_GPIO_PORT, &GPIO_InitStruct);

	/* SPI nCS GPIO pin configuration  */
	GPIO_InitStruct.Pin = SPI_XPT2046_nCS_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(SPI_XPT2046_nCS_GPIO_PORT, &GPIO_InitStruct);

}

/**
  * @brief SPI MSP De-Initialization 
  *        This function frees the hardware resources used in this example:
  *          - Disable the Peripheral's clock
  *          - Revert GPIO configuration to its default state
  * @param hspi: SPI handle pointer
  * @retval None
  */
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
	if(SPI_XPT2046 != hspi->Instance)
	{
		return ;
	}
	
	/*##-1- Reset peripherals ##################################################*/
	SPI_XPT2046_FORCE_RESET();
	SPI_XPT2046_RELEASE_RESET();

	/*##-2- Disable peripherals and GPIO Clocks ################################*/
	/* Configure SPI SCK as alternate function  */
	HAL_GPIO_DeInit(SPI_XPT2046_SCK_GPIO_PORT, SPI_XPT2046_SCK_PIN);
	/* Configure SPI MISO as alternate function  */
	HAL_GPIO_DeInit(SPI_XPT2046_MISO_GPIO_PORT, SPI_XPT2046_MISO_PIN);
	/* Configure SPI MOSI as alternate function  */
	HAL_GPIO_DeInit(SPI_XPT2046_MOSI_GPIO_PORT, SPI_XPT2046_MOSI_PIN);
	/* Configure SPI nCS as alternate function  */
	HAL_GPIO_DeInit(SPI_XPT2046_nCS_GPIO_PORT, SPI_XPT2046_nCS_PIN);
}
/**********************************************************************
函數:SPI3_Init()
函數作用:SPI3初始化
參數:無
返回值:無
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-07-31
說明: SPI3使用的時鐘爲APB1,在時鐘初始化時該時鐘爲
		32MHz,跟xpt2046通信設置成2MHz速率,CLK空閒狀態爲低
		電平,數據在時鐘上升沿鎖存,8bit數據位,MSB,主模式
**********************************************************************/
void SPI3_Init(void)
{
	/* Set the SPI parameters */
	spi_xpt_Handle.Instance               = SPI_XPT2046;

	spi_xpt_Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
	spi_xpt_Handle.Init.Direction         = SPI_DIRECTION_2LINES;
	spi_xpt_Handle.Init.CLKPhase          = SPI_PHASE_1EDGE;
	spi_xpt_Handle.Init.CLKPolarity       = SPI_POLARITY_LOW;
	spi_xpt_Handle.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLED;
	spi_xpt_Handle.Init.CRCPolynomial     = 7;
	spi_xpt_Handle.Init.DataSize          = SPI_DATASIZE_8BIT;
	spi_xpt_Handle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
	spi_xpt_Handle.Init.NSS               = SPI_NSS_SOFT;
	spi_xpt_Handle.Init.TIMode            = SPI_TIMODE_DISABLED;
	spi_xpt_Handle.Init.NSSPMode          = SPI_NSS_PULSE_DISABLED;
	spi_xpt_Handle.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;
	spi_xpt_Handle.Init.Mode 			  = SPI_MODE_MASTER;
	
	HAL_SPI_Init(&spi_xpt_Handle);//初始化spi
	return ;
}

/**********************************************************************
函數:SPI3_Write()
函數作用:SPI3發送一個字節數據
參數:
		uint8_t value----------------------------待發送的字節數據
返回值:0:成功-1:失敗
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-07-31
說明: SPI3通信超時時間爲1S
**********************************************************************/
int8_t SPI3_Write(uint8_t value)
{
	HAL_StatusTypeDef status = HAL_OK;

	status = HAL_SPI_Transmit(&spi_xpt_Handle, &value, 1, SPI_XPT2046_TIMEOUT);

	/* Check the communication status */
	if(status != HAL_OK)
	{
		return (int8_t)-1;
	}
	
	return 0;
}
/**********************************************************************
函數:SPI3_Read()
函數作用:SPI3接收一個16bit數據
參數:
		uint8_t *value------------------------------接收數據的地址
返回值:0:成功-1:失敗
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-07-31
說明: SPI3通信超時時間爲1S
**********************************************************************/
int8_t SPI3_Read(uint8_t *readvalue)
{
	HAL_StatusTypeDef status = HAL_OK;
	uint8_t writevalue = 0x00;

	status = HAL_SPI_TransmitReceive(&spi_xpt_Handle, &writevalue, readvalue, 1, SPI_XPT2046_TIMEOUT);

	/* Check the communication status */
	if(status != HAL_OK)
	{
		return (int8_t)-1;
	}

	return 0;
}

SPI通信完成之後還有兩個引腳接口BUSY和PENIRQ,聲明如下

#define TOUCHPANEL_PEN_GPIO_CLK_ENABLE()	__GPIOC_CLK_ENABLE()
#define TOUCHPANEL_BUSY_GPIO_CLK_ENABLE()	__GPIOC_CLK_ENABLE()
#define TOUCHPANEL_PEN_PIN					GPIO_PIN_2
#define TOUCHPANEL_PEN_GPIO_PORT			GPIOC
#define TOUCHPANEL_BUSY_PIN					GPIO_PIN_3
#define TOUCHPANEL_BUSY_GPIO_PORT			GPIOC

#define TOUCHPANEL_BUSY_Read()				(GPIOC->IDR & GPIO_PIN_3)
//#define TOUCHPANEL_PEN_Read()				(GPIOC->IDR & GPIO_PIN_2)

#define TOUCHPANEL_BUSY						(GPIO_PIN_3)
#define TOUCHPANEL_IDLE						(0x00)

接口初始化如下

/**********************************************************************
函數:HAL_TouchPanel_MspInit()
函數作用:觸摸屏端口資源初始化
參數:無
返回值:無
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-07-31
說明: 這裏端口是PEN口和BUSY口其他口都是spi通訊口
**********************************************************************/
void HAL_TouchPanel_MspInit(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
   
	/*##-1- Enable peripherals and GPIO Clocks #################################*/
	/* Enable GPIO  clock */
	TOUCHPANEL_PEN_GPIO_CLK_ENABLE();
	TOUCHPANEL_BUSY_GPIO_CLK_ENABLE();

	/*##-2- Configure peripheral GPIO #######################################*/  
	/* PEN GPIO pin configuration  */
	GPIO_InitStruct.Pin       = TOUCHPANEL_BUSY_PIN;
	GPIO_InitStruct.Mode      = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull      = GPIO_PULLUP;
	GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
	GPIO_InitStruct.Pin 	  = TOUCHPANEL_BUSY_PIN;
	HAL_GPIO_Init(TOUCHPANEL_BUSY_GPIO_PORT, &GPIO_InitStruct);

	GPIO_InitStruct.Pin		  = TOUCHPANEL_PEN_PIN;
	GPIO_InitStruct.Mode	  = GPIO_MODE_IT_FALLING;
	HAL_GPIO_Init(TOUCHPANEL_PEN_GPIO_PORT, &GPIO_InitStruct);
	
	/*Enable an set EXTI line 2 Interrupt to the lowest priority*/
	HAL_NVIC_SetPriority(EXTI2_TSC_IRQn,2,0);
	HAL_NVIC_EnableIRQ(EXTI2_TSC_IRQn);
	return ;
}
/**********************************************************************
函數:TouchPanel_Init()
函數作用:觸摸屏初始化
參數:無
返回值:無
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-07-31
說明: 
**********************************************************************/
void TouchPanel_Init(void)
{
	HAL_TouchPanel_MspInit();//初始化io口資源
	SPI_XPT2046_nCS_Set_High();//片選拉高
}

這裏配置PENIQR爲中斷引腳,下降沿有效,XPT2046的命令只有一條


MSB一直爲1,MODE=012bit轉換模式,SER/DFR=0:差分模式轉換,文檔中提到在測量X、Y座標時首選差分模式,PD1,PD0=0,A2、A1、A0說明如下


001是測量X座標,101是測量Y座標

構造一個採樣點結構體,存儲測量值,如下

typedef struct
{
	uint16_t sample_x;
	uint16_t sample_y;
}Touch_Point;

讀取測量值如下

/**********************************************************************
函數:TouchPanel_GetPoint()
函數作用:獲取觸摸點
參數:無
返回值:無
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-07-31
說明: 
**********************************************************************/
int8_t TouchPanel_GetPoint(Touch_Point *touch_point)
{
	uint8_t sample_value_h=0,sample_value_l=0;
	
	SPI_XPT2046_nCS_Set_Low();

	if(SPI3_Write(0x90) != 0)//測量Y-
	{
		return (int8_t)-1;
	}

	if(0 != SPI3_Read(&sample_value_h))
	{
		printf("read err1\r\n");
	}
	if(0 != SPI3_Read(&sample_value_l))
	{
		printf("read err1\r\n");
	}
	touch_point->sample_x = ((sample_value_h&0x7F)<<5|(sample_value_l>>3));
	
	if(0 != SPI3_Write(0xD0))//測量X-
	{
		printf("write err2\r\n");
	}
	sample_value_h = 0;
	sample_value_l = 0;
	if(0 != SPI3_Read(&sample_value_h))
	{
		printf("read err2\r\n");
	}
	if(0 != SPI3_Read(&sample_value_l))
	{
		printf("read err2\r\n");
	}
	touch_point->sample_y = ((sample_value_h&0x7F)<<5|(sample_value_l>>3));
	
	SPI_XPT2046_nCS_Set_High();

	return 0;
	
}
uint8_t flag = 0;
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
{
	switch(GPIO_Pin)
	{
		case TOUCHPANEL_PEN_PIN:
			flag = 1;
			break;
		default:
			break;
	}
}

/**********************************************************************
函數:EXTI2_TSC_IRQHandler()
函數作用:EXTI2_TSC中斷響應函數
參數:無
返回值:無
上一版本:無
當前版本:1.0
作者:anobodykey
最後修改時間:2015-08-10
說明: 只處理EXTI2中斷
**********************************************************************/
void EXTI2_TSC_IRQHandler(void)
{
	HAL_GPIO_EXTI_IRQHandler (TOUCHPANEL_PEN_PIN);
}

在讀取測量值時需要注意測量的結果是12bit,在時序圖中可以看到,一共24個時鐘,前8個時鐘是發送控制命令,第9個時鐘無效,接着的12個時鐘爲有效數據,最後3個時鐘爲空閒時鐘,因此數據的高位和地位需要正確的組合。時序說明如下


在主循環中代碼如下

while(1)
{
	if(flag)
	{
		//PEN爲低電平表示有觸摸點
		printf("get the touch!\r\n");
		TouchPanel_GetPoint(&touch_point);
		printf("sample y:%04X\r\n",touch_point.sample_y);
		printf("sample x:%04X\r\n",touch_point.sample_x);
		flag = 0;
	}
}

測試結果如下:


現在只是獲取了採樣值還沒有轉換成X、Y座標,同時對於電阻屏來說第一步就是校正,關於校正流程網上有很多資源,做完這些下面就可以使用STemWin來製作圖形界面了,使用STemWin可以很方便我們做出豐富的界面。


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