使用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