STM32CubeMX系列教程23:LCD触摸控制
其中 TS_I2C 为模拟 I2C 驱动程序,下面为读写寄存器操作函数。
/******************************************************************************* * Function Name : I2C_WR_Reg * Description : Writes to the selected register. * Input : - reg: address of the selected register. * - buf: Need to write the BUF pointer. * - len: The length of the array * Output : None * Return : ret -0 succeed -1 error * Attention : None *******************************************************************************/ uint8_t I2C_WriteReg(uint8_t I2c_Addr,uint16_t reg,uint8_t *buf,uint8_t len) { uint8_t i; uint8_t ret=0; I2C_Start(); I2C_Send_Byte(I2c_Addr); //Slaver Addr I2C_Wait_Ack(); #ifdef I2C_MEMADD_16BIT I2C_Send_Byte(reg>>8); //Data Addr high I2C_Wait_Ack(); #endif I2C_Send_Byte(reg&0xFF); //Data Addr low I2C_Wait_Ack(); for(i=0;i<len;i++) { I2C_Send_Byte(buf[i]); ret=I2C_Wait_Ack(); if(ret)break; } I2C_Stop(); return ret; } /******************************************************************************* * Function Name : i2C_RD_Reg * Description : Writes to the selected register. * Input : - reg: address of the selected register. * - buf: Need to read the BUF pointer. * - len: The length of the array * Output : None * Return : None * Attention : None *******************************************************************************/ void I2C_ReadReg(uint8_t I2c_Addr,uint16_t reg,uint8_t *buf,uint8_t len) { uint8_t i; I2C_Start(); I2C_Send_Byte(I2c_Addr); I2C_Wait_Ack(); #ifdef I2C_MEMADD_16BIT I2C_Send_Byte(reg>>8); //Data Addr high I2C_Wait_Ack(); #endif I2C_Send_Byte(reg&0xFF); //Data Addr low I2C_Wait_Ack(); I2C_Stop(); I2C_Start(); I2C_Send_Byte(I2c_Addr+1); I2C_Wait_Ack(); for(i=0;i<len;i++) { buf[i]=I2C_Read_Byte(i==(len-1)?0:1); } I2C_Stop(); }
GT811.c为触摸芯片的驱动文件,下面简单介绍一下初始化函数和读取触摸状态函数。程序开始先拉低复位管脚复位芯片,注意如果延时时间过短则会导致复位不成功。读取GT811的ID值判断通信是否正常。设置屏幕分辨率并将配置参数写入到配置&功能寄存器组中。
/** * @brief Initialize the GT811 communication bus * from MCU to GT811 : ie I2C channel initialization (if required). * @retval None */ uint8_t GT811_Init(void) { I2C_Init(); /* reset GT811 */ HAL_GPIO_WritePin(LCD_RST_GPIO_Port,LCD_RST_Pin, GPIO_PIN_RESET); HAL_Delay(200); HAL_GPIO_WritePin(LCD_RST_GPIO_Port,LCD_RST_Pin, GPIO_PIN_SET); HAL_Delay(200); /* if Version is correct, send the configuration parameters */ if(GT811_ReadID() == GT811_VERSION_VALUE) { /* touch screen configuration parameter (touch screen manufacturers provide) */ uint8_t GTP_CFG_DATA[]= { 0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x05,0x55,0x15,0x55,0x25,0x55,0x35,0x55,0x45,0x55, 0x55,0x55,0x65,0x55,0x75,0x55,0x85,0x55,0x95,0x55,0xA5,0x55,0xB5,0x55,0xC5,0x55,0xD5,0x55,0xE5,0x55, 0xF5,0x55,0x1B,0x03,0x00,0x00,0x00,0x13,0x13,0x13,0x0F,0x0F,0x0A,0x50,0x30,0x05,0x03,0x64,0x05,0xe0, 0x01,0x20,0x03,0x00,0x00,0x32,0x2C,0x34,0x2E,0x00,0x00,0x04,0x14,0x22,0x04,0x00,0x00,0x00,0x00,0x00, 0x20,0x14,0xEC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,0x25,0x28,0x14,0x00, 0x00,0x00,0x00,0x00,0x00,0x01, }; /* config */ GTP_CFG_DATA[62] = GT811_MAX_WIDTH >> 8; GTP_CFG_DATA[61] = GT811_MAX_WIDTH & 0xff; GTP_CFG_DATA[60] = GT811_MAX_HEIGHT >> 8; GTP_CFG_DATA[59] = GT811_MAX_HEIGHT & 0xff; I2C_WriteReg(GT811_CMD_WR,GT811_CONFIG_REG,(uint8_t *)GTP_CFG_DATA,sizeof(GTP_CFG_DATA)); } return HAL_OK; }
如下为读触摸状态函数,先通过I2C读去输出信息寄存器,判断TouchpointFlag寄存器的tp0~tp4是否置1,即是否有触摸,若有则将寄存器的值转为坐标值,存储在TS_StateTypeDef 结构体的指针内存中。
void GT811_GetState(TS_StateTypeDef *TS_State) { uint8_t RegBuf[34]; /* Read touch message */ I2C_ReadReg(GT811_CMD_WR,GT811_READ_XY_REG,RegBuf,sizeof(RegBuf)); /* get touch massage */ TS_State->SensorId = RegBuf[0x00] >> 6; TS_State->touchDetected = RegBuf[0x00] & 0x1F; if(TS_State->touchDetected != 0) { //Touch point 1 coordinates TS_State->touchY[0] = GT811_MAX_HEIGHT - (((uint16_t)RegBuf[0x02] << 8) + RegBuf[0x03]); TS_State->touchX[0] = (((uint16_t)RegBuf[0x04] << 8) + RegBuf[0x05]); TS_State->touchWeight[0] = RegBuf[0x06]; //Touch point 2 coordinates TS_State->touchY[1] = GT811_MAX_HEIGHT - (((uint16_t)RegBuf[0x07] << 8) + RegBuf[0x08]); TS_State->touchX[1] = (((uint16_t)RegBuf[0x09] << 8) + RegBuf[0x0A]); TS_State->touchWeight[1] = RegBuf[0x0B]; //Touch point 3 coordinates TS_State->touchY[2] = GT811_MAX_HEIGHT - (((uint16_t)RegBuf[0x0C] << 8) + RegBuf[0x0D]); TS_State->touchX[2] = (((uint16_t)RegBuf[0x0E] << 8) + RegBuf[0x0F]); TS_State->touchWeight[2] = RegBuf[0x10]; //Touch point 4 coordinates TS_State->touchY[3] = GT811_MAX_HEIGHT - (((uint16_t)RegBuf[0x11] << 8) + RegBuf[0x18]); TS_State->touchX[3] = (((uint16_t)RegBuf[0x19] << 8) + RegBuf[0x1A]); TS_State->touchWeight[3] = RegBuf[0x1B]; //Touch point 5 coordinates TS_State->touchY[4] = GT811_MAX_HEIGHT - (((uint16_t)RegBuf[0x1C] << 8) + RegBuf[0x1D]); TS_State->touchX[4] = (((uint16_t)RegBuf[0x1E] << 8) + RegBuf[0x1F]); TS_State->touchWeight[4] = RegBuf[0x20]; } }
TS_StateTypeDef结构体在GT811.h中定义。
typedef struct { uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ uint32_t SensorId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ } TS_StateTypeDef;
删除原来的应用代码,在main文件中添加头文件。
/* USER CODE BEGIN Includes */ #include "stm32746g_sdram.h" #include "stm32746g_LCD.h" #include "GT811.h" /* USER CODE END Includes */
声明变量,其中TS_State为当前触摸状态,TS_BKState为上一次触摸状态。TS_flag为触摸标志,TouchPoit存储触点数。PointColor存储各个触点的显示颜色。
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ TS_StateTypeDef TS_State={0}; uint8_t TS_flag ; uint8_t TouchPoit; TS_StateTypeDef TS_BKState; uint8_t value = 0; uint16_t i; uint32_t PointColor[]={LCD_COLOR_BLUE,LCD_COLOR_GREEN,LCD_COLOR_RED,LCD_COLOR_MAGENTA,LCD_COLOR_YELLOW}; /* USER CODE END PV */
在while循环中添加如下应用程序,程序首先判断触摸标志,如果有触摸,则读取触摸状态。循环中分为三分部,第一部分即清楚上次显示的内容,即将显示内容设为背景色黑色覆盖。第二部分在对应触摸的位置显示一个点和水平垂直量两条先。第三部分就这次的触摸状态存储到备份状态结构体中,以便下一次擦除。
/* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(TS_flag == 1) { GT811_GetState(&TS_State); if(TS_State.touchDetected != 0) { TouchPoit = TS_BKState.touchDetected; for(i = 0;i < 5;i++) { if(TouchPoit & 0x01) { BSP_LCD_SetTextColor(LCD_COLOR_BLACK); BSP_LCD_FillCircle(TS_BKState.touchX[i],TS_BKState.touchY[i],20); BSP_LCD_DrawVLine(TS_BKState.touchX[i], 55, 580); BSP_LCD_DrawHLine(5, TS_BKState.touchY[i], 1004); } TouchPoit >>= 1; } TouchPoit = TS_State.touchDetected; for(i = 0;i < 5;i++) { if(TouchPoit & 0x01) { if(TS_State.touchY[i] < 75)TS_State.touchY[i] = 75; if(TS_State.touchY[i] > 580)TS_State.touchY[i] = 580; if(TS_State.touchX[i] < 20)TS_State.touchX[i] = 20; if(TS_State.touchX[i] > 1004)TS_State.touchX[i] = 1004; BSP_LCD_SetTextColor(PointColor[i]); BSP_LCD_FillCircle(TS_State.touchX[i],TS_State.touchY[i],20); BSP_LCD_DrawVLine(TS_State.touchX[i], 55, 580); BSP_LCD_DrawHLine(5, TS_State.touchY[i], 1004); TS_BKState.touchX[i] = TS_State.touchX[i]; TS_BKState.touchY[i] = TS_State.touchY[i]; } TouchPoit >>= 1; } TS_BKState.touchDetected = TS_State.touchDetected; } TS_flag = 0; } } /* USER CODE END 3 */
在main文件后面添加外部中断回调函数,当屏幕有触摸是触发中断,触摸标志位置1。
/* USER CODE BEGIN 4 */ /** * @} */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if( GPIO_Pin == GPIO_PIN_7) { TS_flag = 1; } } /* USER CODE END 4 */
编译程序下载到开发板中,触摸屏幕会显示触点。(以下为五点触控效果的显示)