驱动使用GT911,能够正常读取ID的值,触摸屏幕时INT电压也下降了。初始化的时候给GT911配置寄存器写入新的配置参数,读取该寄存器的值也与写入的值相同,但是读取状态寄存器的数据始终为0,直接读取坐标的数据也为0,这是为什么?
#ifndef __GT911_H
#define __GT911_H
#include "stm32f4xx.h" // Device header
#include "MyI2C.h"
#include "Delay.h"
#include "usart1.h"
// GT911 寄存器地址定义
#define GT911_ADDR1_WR 0xBA // 0x5D << 1
#define GT911_ADDR1_RD 0xBB
#define GT911_ADDR2 0x28
#define GT911_ADDR2_WR 0x28 // 0x14 << 1
#define GT911_ADDR2_RD 0x29 // 0x14 << 1
#define GT911_STATUS_REG 0x814E //状态寄存器
#define GT911_CONFIG_VERSION 0x8047 //配置寄存器
#define GT911_PRODUCT_ID 0x8140 //坐标寄存器 ID
#define GT911_TOUCH_DATA_START 0x8150 //坐标寄存器1
#define GT911_CONTROL_REGISTER 0x8040 //控制寄存器
#define GT911_MAX_TOUCH 5
// 触摸点数据结构
typedef struct {
uint8_t trackId;
uint16_t x;
uint16_t y;
uint8_t size;
uint8_t flag;
} GT911_TouchPoint;
// 触摸状态结构
typedef struct {
uint8_t touchNum;
uint8_t touchStatus;
GT911_TouchPoint points[GT911_MAX_TOUCH];
} GT911_TouchData;
// 函数声明
uint8_t GT911_Init(uint16_t devAddr);
uint8_t GT911_CheckTouchStatus(void);
uint8_t GT911_ReadTouchData(GT911_TouchData *touchData);
uint8_t GT911_ClearStatus(void);
void GT911_Reset(void);
uint8_t GT911_ReadProductID(uint8_t *productID);
// I2C 读写函数
uint8_t GT911_I2C_Write(uint16_t regAddr, uint8_t *data, uint16_t len);
uint8_t GT911_I2C_Read(uint16_t regAddr, uint8_t *data, uint16_t len);
// 外部变量
extern uint16_t gt911_devAddr;
uint8_t GT911_ReadAndPrintConfig(uint8_t *store_config);
void GT911_Send_Cfg(uint8_t mode);
#endif
#include "GT911.h"
#include <string.h>
uint16_t gt911_devAddr = 0;
const uint8_t GT911_CFG_TBL[]=
{
0x5A,0x20,0x03,0xE0,0x01,0x05,0x0C,0x00,0x01,0x08,0x28,0x0F,0x5A,0x46,0x03,0x0F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x28,0x0A,0x96,0x98,
0xB2,0x04,0x00,0x00,0x00,0x00,0x02,0x1D,0x19,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x78,0xA0,0x94,0xD5,0x02,0x08,0x00,0x00,0x04,0x93,0x7B,0x00,0x8D,
0x82,0x00,0x87,0x8A,0x00,0x82,0x92,0x00,0x7D,0x9B,0x00,0x7D,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,
0x14,0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x24,
0x22,0x21,0x20,0x1F,0x1E,0x1D,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
/**
* @brief I2C写数据
*/
uint8_t GT911_I2C_Write(uint16_t regAddr, uint8_t *data, uint16_t len)
{
uint16_t i;
MyI2C_Start();
// 发送设备地址 + 写标志
MyI2C_SendByte(0x28);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 1;
}
// 发送寄存器地址高字节
MyI2C_SendByte((regAddr >> 8) & 0xFF);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 2;
}
// 发送寄存器地址低字节
MyI2C_SendByte(regAddr & 0xFF);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 3;
}
// 发送数据
for(i = 0; i < len; i++)
{
MyI2C_SendByte(data[i]);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 4;
}
}
MyI2C_Stop();
return 0;
}
/**
* @brief I2C读数据
*/
uint8_t GT911_I2C_Read(uint16_t regAddr, uint8_t *data, uint16_t len)
{
uint16_t i;
MyI2C_Start();
// 发送设备地址 + 写标志
MyI2C_SendByte(0x28);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 1;
}
// 发送寄存器地址高字节
MyI2C_SendByte((regAddr >> 8)& 0xFF);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 2;
}
// 发送寄存器地址低字节
MyI2C_SendByte(regAddr & 0xFF);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 3;
}
// 重新发送起始条件
MyI2C_Start();
// 发送设备地址 + 读标志
MyI2C_SendByte(0x29);
if(MyI2C_ReceiveAck())
{
MyI2C_Stop();
return 4;
}
// 读取数据
for(i = 0; i < len; i++)
{
if(i == len - 1)
{
data[i] = MyI2C_ReceiveByte();
MyI2C_SendAck(1); // 最后一个字节发送NACK
}
else
{
data[i] = MyI2C_ReceiveByte();
MyI2C_SendAck(0); // 发送ACK
}
}
MyI2C_Stop();
return 0;
}
/**
* @brief 初始化GT911
*/
uint8_t GT911_Init(uint16_t devAddr)
{
uint8_t temp[2] = {0};
uint8_t productID[4] = {0};
uint8_t ret = 0;
gt911_devAddr = devAddr;
// 初始化I2C(包含GPIO初始化)
MyI2C_Init();
A:
// 执行复位序列
//// //0xBA
// GPIO_ResetBits(GT911_RST_PORT, GT911_RST_PIN);
// GPIO_ResetBits(GT911_INT_PORT, GT911_INT_PIN);
// Delay_ms(10); // 10ms
// GPIO_SetBits(GT911_RST_PORT, GT911_RST_PIN);
//// //0x28 八位写地址
GPIO_ResetBits(GT911_RST_PORT, GT911_RST_PIN); // 拉低RST
GPIO_ResetBits(GT911_INT_PORT, GT911_INT_PIN); // INT保持低
Delay_ms(10); // 保持10ms
GPIO_SetBits(GT911_RST_PORT, GT911_RST_PIN); // 释放RST
Delay_ms(10); // 等待芯片稳定
// 重新配置INT为浮空输入
GPIO_InitTypeDef GPIO_InitStructure;
//GPIO_InitStructure.GPIO_OType = GPIO_OTYPE_PP;
GPIO_InitStructure.GPIO_Pin = GT911_INT_PIN;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_NOPULL;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GT911_INT_PORT, &GPIO_InitStructure);
Delay_ms(100); // 等待芯片完全初始化
ret = GT911_I2C_Read(0x8140, productID, 4);
if(ret != 0)
{
printf(" id read error ");
printf("ret = %d\r\n",ret);
Delay_ms(500);
goto A;
}
printf("productID = %d %d %d %d \r\n",productID[0],productID[1],productID[2],productID[3]);
//printf("productID = %s \r\n",productID);
if(strcmp((char*)productID,"911")==0)//ID==9147
{
temp[0]=0X02;
GT911_I2C_Write(GT911_CONTROL_REGISTER,temp,1);//软复位GT911
GT911_I2C_Read(GT911_STATUS_REG,temp,1);//读取GT_CFGS_REG寄存器
//printf("Default Ver:%x\r\n",temp[0]);
// if(temp[0]!=0x60)
// {
GT911_Send_Cfg(1);
// }
Delay_ms(10);
temp[0]=0X00;
GT911_I2C_Write(GT911_CONTROL_REGISTER,temp,1);//结束复位
}
return 0;
}
/**
* @brief 检查触摸状态(轮询状态寄存器最高位)
*/
uint8_t GT911_CheckTouchStatus(void)
{
uint8_t status = 0;
uint8_t ret = 0;
ret = GT911_I2C_Read(GT911_STATUS_REG, &status, 1);
if(ret != 0)
{
return ret; // 通信错误
}
// 检查最高位(bit7)是否为1,表示有触摸数据
if(status & 0x80)
{
return status; // 有触摸
}
return 0; // 无触摸
}
/**
* @brief 读取触摸数据(修正坐标解析)
* @param touchData: 存储触摸数据的结构体指针
* @retval 0-成功, 1-通信错误, 2-无触摸数据, 3-参数错误
*/
uint8_t GT911_ReadTouchData(GT911_TouchData *touchData)
{
uint8_t buf[40] = {0}; // 足够存放5个触摸点(5*8=40字节)
uint8_t status = 0;
uint8_t ret = 0;
uint8_t i;
if(touchData == NULL) {
return 3; // 参数错误
}
memset(touchData, 0, sizeof(GT911_TouchData));
// 1. 读取状态寄存器(0x814E)
ret = GT911_I2C_Read(GT911_STATUS_REG, &status, 1);
if(ret != 0) {
printf("读取状态寄存器失败,错误码: %d\r\n", ret);
return 1; // 通信错误
}
// 调试信息:打印原始状态字节
//printf("[DEBUG] 状态寄存器原始值: 0x%02X\r\n", status);
// 2. 检查最高位(bit7)是否为1,表示有新的触摸数据
if((status & 0x80) == 0) {
// 注意:无触摸时返回2,这是正常情况,不是错误
return 2; // 无新触摸数据
}
// 3. 获取触摸点数量(低4位,最多5点)
touchData->touchNum = status & 0x0F;
if(touchData->touchNum > GT911_MAX_TOUCH) {
printf("警告:报告的触摸点数(%d)超过最大值,已截断\r\n", touchData->touchNum);
touchData->touchNum = GT911_MAX_TOUCH;
}
printf("检测到触摸点数: %d\r\n", touchData->touchNum);
// 4. 如果有点,则读取触摸点数据(每个点8字节)
if(touchData->touchNum > 0) {
// 计算需要读取的字节数
uint8_t bytesToRead = touchData->touchNum * 8;
// 从0x8150开始读取触摸数据
ret = GT911_I2C_Read(GT911_TOUCH_DATA_START, buf, bytesToRead);
if(ret != 0) {
printf("读取触摸数据失败,错误码: %d\r\n", ret);
return 1; // 通信错误
}
// 5. 解析每个触摸点数据(关键修正部分)
for(i = 0; i < touchData->touchNum; i++) {
uint8_t *p = &buf[i * 8]; // 每个点8字节
// 解析触摸点数据(根据GT911数据手册)
touchData->points[i].trackId = p[7] & 0x0F; // 跟踪ID(低4位)
touchData->points[i].x = ((uint16_t)(p[1] & 0x0F) << 8) | p[0]; // X坐标
touchData->points[i].y = ((uint16_t)(p[3] & 0x0F) << 8) | p[2]; // Y坐标
touchData->points[i].size = p[4]; // 触摸面积
touchData->points[i].flag = 1; // 标记有效
// 调试输出
printf("点%d: ID=%d, X=%d, Y=%d, 面积=%d\r\n",
i,
touchData->points[i].trackId,
touchData->points[i].x,
touchData->points[i].y,
touchData->points[i].size);
}
}
// 6. 读取完成后,必须清除状态寄存器(写入0x00)
GT911_ClearStatus();
return 0; // 成功
}
/**
* @brief 清除状态寄存器(必须每次读取触摸数据后调用)
* @retval 0-成功, 非0-失败
*/
uint8_t GT911_ClearStatus(void)
{
uint8_t clear_data = 0x00;
uint8_t ret = GT911_I2C_Write(GT911_STATUS_REG, &clear_data, 1);
if(ret != 0) {
printf("清除状态寄存器失败,错误码: %d\r\n", ret);
} else {
printf("状态寄存器已清除\r\n");
printf("\r\n");
printf("\r\n");
}
return ret;
}
/**
* @brief 硬件复位
*/
void GT911_Reset(void)
{
GPIO_ResetBits(GT911_RST_PORT, GT911_RST_PIN);
MyI2C_Delay(10000); // 10ms
GPIO_SetBits(GT911_RST_PORT, GT911_RST_PIN);
MyI2C_Delay(100000); // 100ms
}
/**
* @brief 读取并打印GT911配置寄存器组 (0x8047 ~ 0x8100)
* @param store_config: (可选)用于存储读取到的186字节配置的缓冲区。
* 如果为NULL,则只打印不存储。
* @retval 0-成功, 非0-失败 (I2C读取错误码)
*/
uint8_t GT911_ReadAndPrintConfig(uint8_t *store_config)
{
uint8_t config_buf[186] = {0}; // 0x8100 - 0x8047 + 1 = 186 字节
uint8_t ret = 0;
uint16_t i, j;
printf("\r\n========== GT911 配置寄存器组 (0x8047~0x8100) ==========\r\n");
// 1. 读取全部186字节配置
ret = GT911_I2C_Read(0x8047, config_buf, sizeof(config_buf));
if(ret != 0) {
printf("[错误] 读取配置寄存器失败,错误码: %d\r\n", ret);
return ret;
}
// 2. 打印关键配置信息(头部)
printf("配置版本: %d.%d.%d.%d\r\n",
config_buf[0], config_buf[1], config_buf[2], config_buf[3]);
printf("X分辨率: %d\r\n", (config_buf[0x4A] << 8) | config_buf[0x49]);
printf("Y分辨率: %d\r\n", (config_buf[0x4C] << 8) | config_buf[0x4B]);
printf("触摸点数: %d\r\n", config_buf[0x4D]);
// 3. 计算并验证校验和
// GT911配置的校验和通常是前184字节的和,存储在第185(0x80FF)、186(0x8100)字节
uint16_t calc_checksum = 0;
for(i = 0; i < 184; i++) {
calc_checksum += config_buf[i];
}
uint16_t stored_checksum = (config_buf[184] << 8) | config_buf[185];
printf("存储的校验和: 0x%04X\r\n", stored_checksum);
printf("计算的校验和: 0x%04X\r\n", calc_checksum);
if(calc_checksum == stored_checksum) {
printf("校验和: ? 正确\r\n");
} else {
printf("校验和: ? 错误 (配置可能已损坏)\r\n");
}
// 4. 以十六进制格式打印全部配置数据(每行16字节)
printf("\r\n--- 完整配置数据 (HEX) ---\r\n");
for(i = 0; i < sizeof(config_buf); i += 16) {
printf("0x%04X: ", 0x8047 + i); // 打印当前行起始地址
// 打印16个字节的HEX值
for(j = 0; j < 16; j++) {
if(i + j < sizeof(config_buf)) {
printf("%02X ", config_buf[i + j]);
} else {
printf(" "); // 对齐最后一行
}
}
printf(" "); // 分隔符
// 打印ASCII字符(可打印字符)
for(j = 0; j < 16 && i + j < sizeof(config_buf); j++) {
uint8_t c = config_buf[i + j];
if(c >= 32 && c <= 126) { // 可打印字符范围
printf("%c", c);
} else {
printf(".");
}
}
printf("\r\n");
}
printf("============================================================\r\n\r\n");
// 5. 如果调用者提供了存储缓冲区,则将数据拷贝过去
if(store_config != NULL) {
memcpy(store_config, config_buf, sizeof(config_buf));
}
return 0;
}
/*
* 函数名称: GT911_Send_Cfg
* 功能描述: 更新GT911配置参数
* 传入参数: mode:0,参数不保存到flash
* 1:参数保存到flash
* 返回值: 0,成功;1,失败.
*/
void GT911_Send_Cfg(uint8_t mode)
{
uint8_t buf[2];
uint8_t i=0;
buf[0]=0;
buf[1]=mode; //是否写入到GT911 FLASH? 即是否掉电保存
for(i=0;i<sizeof(GT911_CFG_TBL);i++)buf[0]+=GT911_CFG_TBL[i];//计算校验和
buf[0]=(~buf[0])+1;
GT911_I2C_Write(GT911_CONFIG_VERSION,(uint8_t*)GT911_CFG_TBL,sizeof(GT911_CFG_TBL));//发送寄存器配置
GT911_I2C_Write(0x80FF,buf,2);//写入校验和,和配置更新标记 0x80FF校验和寄存器
}