使用STM32硬件IIC DMA驱动GT911触摸屏详细教程

使用STM32+硬件IIC+DMA驱动GT系列触摸屏(GT911)

初始化代码

/*
  * @brief  GT911 初始化程序
  * @param  None
  * @retval None
 */
void GT911_init()
{
	Dev_Now.GT911_RST=0;
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = GT911_RST_PIN | GT911_INT_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
	HAL_GPIO_Init(GT911_RST_PORT, &GPIO_InitStruct);
	
	HAL_GPIO_WritePin(GT911_RST_PORT,GT911_RST_PIN,GPIO_PIN_RESET);    
	HAL_Delay(1000);
	HAL_GPIO_WritePin(GT911_INT_PORT,GT911_INT_PIN,GPIO_PIN_RESET);    
	HAL_Delay(1000);
	HAL_GPIO_WritePin(GT911_RST_PORT,GT911_RST_PIN,GPIO_PIN_SET);    
	HAL_Delay(2000);
	
	GPIO_InitStruct.Pin = GT911_INT_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(GT911_INT_PORT, &GPIO_InitStruct);
	
	HAL_Delay(100);
	Dev_Now.GT911_RST=1;
}

主要数据读取代码:

regNum为读取的数据个数,如果只是读取1个点的触摸,改成9就可以。

#define regNum	41	//读取寄存器字节数
void GT911_Scan(void)
{
	uint8_t Clearbuf = 0;
	uint8_t i = 0;

	if (Dev_Now.Touch == 1)
	{
		Dev_Now.Touch = 0;
		if(GTDMASendOK_F)	//判断DMA是否发送完成
		{
			GTDMASendOK_F = 0;
			if(HAL_I2C_Mem_Read_DMA(&hi2c1, CT_CMD_WR, GT911_READ_XY_REG, I2C_MEMADD_SIZE_16BIT, DMAbuf, regNum)) //IIC读取regNum个字节数据
			{
				IICReset();	//异常则重启IIC总线
				return;
			}
		}
		else
		{
			if(HAL_I2C_Mem_Write_DMA(&hi2c1, CT_CMD_WR, GT911_READ_XY_REG, I2C_MEMADD_SIZE_16BIT, &Clearbuf, 1))	//写入读取完成通知从设备
			{
				IICReset();	//异常则重启IIC总线
				return;
			}
		}
	}

	if(GTDMAReadOK_F)	//判断DMA是否接收完成
	{
		GTDMAReadOK_F = 0;
		if ((GT911buf[0]&0x80) == 0x00)	//坐标是否(或按键)已经准备好
		{
			if(HAL_I2C_Mem_Write_DMA(&hi2c1, CT_CMD_WR, GT911_READ_XY_REG, I2C_MEMADD_SIZE_16BIT, &Clearbuf, 1))//写入读取完成通知从设备
			{
				IICReset();	//异常则重启IIC总线
				return;
			}
		}
		else
		{
			Dev_Now.TouchpointFlag = GT911buf[0];
			Dev_Now.TouchCount = GT911buf[0]&0x0f;

			if(HAL_I2C_Mem_Write_DMA(&hi2c1, CT_CMD_WR, GT911_READ_XY_REG, I2C_MEMADD_SIZE_16BIT, &Clearbuf, 1))//写入读取完成通知从设备
			{
				IICReset();	//异常则重启IIC总线
				return;
			}
			Dev_Now.Touchkeytrackid[0] = GT911buf[1];		//第一个触摸点的坐标
			Dev_Now.X[0] = ((uint16_t)GT911buf[3] << 8) + GT911buf[2];
			Dev_Now.Y[0] = ((uint16_t)GT911buf[5] << 8) + GT911buf[4];
			Dev_Now.S[0] = ((uint16_t)GT911buf[7] << 8) + GT911buf[6];

			Dev_Now.Touchkeytrackid[1] = GT911buf[9];		//第二个触摸点的坐标
			Dev_Now.X[1] = ((uint16_t)GT911buf[11] << 8) + GT911buf[10];
			Dev_Now.Y[1] = ((uint16_t)GT911buf[13] << 8) + GT911buf[12];
			Dev_Now.S[1] = ((uint16_t)GT911buf[15] << 8) + GT911buf[14];

			Dev_Now.Touchkeytrackid[2] = GT911buf[17];		//第三个触摸点的坐标
			Dev_Now.X[2] = ((uint16_t)GT911buf[19] << 8) + GT911buf[18];
			Dev_Now.Y[2] = ((uint16_t)GT911buf[21] << 8) + GT911buf[20];
			Dev_Now.S[2] = ((uint16_t)GT911buf[23] << 8) + GT911buf[22];

			Dev_Now.Touchkeytrackid[3] = GT911buf[25];		//第四个触摸点的坐标
			Dev_Now.X[3] = ((uint16_t)GT911buf[27] << 8) + GT911buf[26];
			Dev_Now.Y[3] = ((uint16_t)GT911buf[29] << 8) + GT911buf[28];
			Dev_Now.S[3] = ((uint16_t)GT911buf[31] << 8) + GT911buf[30];

			Dev_Now.Touchkeytrackid[4] = GT911buf[33];		//第五个触摸点的坐标
			Dev_Now.X[4] = ((uint16_t)GT911buf[35] << 8) + GT911buf[34];
			Dev_Now.Y[4] = ((uint16_t)GT911buf[37] << 8) + GT911buf[36];
			Dev_Now.S[4] = ((uint16_t)GT911buf[39] << 8) + GT911buf[38];

			for (i = 0; i< Dev_Backup.TouchCount;i++)	//检查触摸点的坐标边界
			{
				if(Dev_Now.Y[i]<20)Dev_Now.Y[i]=20;
				if(Dev_Now.Y[i]>GT911_MAX_HEIGHT-20)Dev_Now.Y[i]=GT911_MAX_HEIGHT-20;
				if(Dev_Now.X[i]<20)Dev_Now.X[i]=20;
				if(Dev_Now.X[i]>GT911_MAX_WIDTH-20)Dev_Now.X[i]=GT911_MAX_WIDTH-20;
			}
			for (i=0;i<Dev_Now.TouchCount;i++)
			{
				if(Dev_Now.Y[i]<20)Dev_Now.Y[i]=20;
				if(Dev_Now.Y[i]>GT911_MAX_HEIGHT-20)Dev_Now.Y[i]=GT911_MAX_HEIGHT-20;
				if(Dev_Now.X[i]<20)Dev_Now.X[i]=20;
				if(Dev_Now.X[i]>GT911_MAX_WIDTH-20)Dev_Now.X[i]=GT911_MAX_WIDTH-20;

				Dev_Backup.X[i] = Dev_Now.X[i];
				Dev_Backup.Y[i] = Dev_Now.Y[i];
				Dev_Backup.TouchCount = Dev_Now.TouchCount;
			}
		}
	}
}

错误复位代码

主要解决IIC偶尔出现死锁的问题,IICError 变量记录死锁的次数,移植的时候这个变量如果一直增加,说明时序出现了问题。

/*
  * @brief  IIC引脚复位程序
  * @param  None
  * @retval None
 */
static void i2c_hw_reset(void) {

    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);

    if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_RESET ||
        HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET) {
        //HAL_Delay(10);
    }

    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    hi2c1.Instance->CR1 |= I2C_CR1_SWRST;
    hi2c1.Instance->CR1 &= ~I2C_CR1_SWRST;
	HAL_I2C_DeInit(&hi2c1);        //释放IO口为GPIO,复位句柄状态
	HAL_I2C_Init(&hi2c1);          //这句重新初始化I2C控制
}

/*
  * @brief  IIC复位程序
  * @param  None
  * @retval None
 */
void IICReset(void)
{
	SET_BIT(hi2c1.Instance->CR1, I2C_CR1_STOP);	//发送一个停止位
	hi2c1.State = HAL_I2C_STATE_READY;			//改变IIC状态为准备状态
	hi2c1.Mode = HAL_I2C_MODE_NONE;				//标准模式
	i2c_hw_reset();								//复位IIC总线
	IICError ++;								//错误次数计数
}

DMA中断代码

DMA数据发送/接收中断处理

/**
  * @brief This function handles DMA1 stream0 global interrupt.
  */
void DMA1_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream0_IRQn 0 */
	if(__HAL_DMA_GET_TC_FLAG_INDEX(&hdma_i2c1_rx))	//DMA传输完成判断
	{
		GTDMAReadOK_F = 1;
		memcpy(GT911buf, DMAbuf, sizeof(DMAbuf));
	}
  /* USER CODE END DMA1_Stream0_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_i2c1_rx);
  /* USER CODE BEGIN DMA1_Stream0_IRQn 1 */

  /* USER CODE END DMA1_Stream0_IRQn 1 */
}

/**
  * @brief This function handles DMA1 stream6 global interrupt.
  */
void DMA1_Stream6_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream6_IRQn 0 */
	if(__HAL_DMA_GET_TC_FLAG_INDEX(&hdma_i2c1_tx))	//DMA传输完成判断
	{
		GTDMASendOK_F = 1;
	}
  /* USER CODE END DMA1_Stream6_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_i2c1_tx);
  /* USER CODE BEGIN DMA1_Stream6_IRQn 1 */

  /* USER CODE END DMA1_Stream6_IRQn 1 */
}

GT911数据准备完成中断

GT911数据准备完成后,会产生一个外部中断

/**
  * @brief This function handles EXTI line[9:5] interrupts.
  */
void EXTI9_5_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI9_5_IRQn 0 */
	  if(Dev_Now.GT911_RST)
	  {
		  	  Dev_Now.Touch =1;
	  }
  /* USER CODE END EXTI9_5_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
  /* USER CODE BEGIN EXTI9_5_IRQn 1 */

  /* USER CODE END EXTI9_5_IRQn 1 */
}

基于系统时钟1ms扫描一次

/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  GT911_Scan();	//1ms扫描一次
  /* USER CODE END SysTick_IRQn 1 */
}

结果

单点触摸的数据如下:

多点触摸的数据如下:

最后附上Github地址

github地址:https://github.com/oy2n/stm32cube-gt911-dma.git

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32硬件IIC DMA驱动GT911触摸屏详细教程

发表评论