正在学习探索者F4开发板中4.3寸触摸屏操作,驱动芯片是GT9147。看了例程后觉得程序有点乱,书写风格不符合自己的审美观。把例程烧进单片机后运行,发现触摸灵敏度不行,经常按下几次都没有反应。综上,决定自己重新编写这个驱动,我是菜鸟,花了将近两天时间。对自己编写的驱动程序进行了一些测试,结果良好,挺开心的。现共享出驱动源码,大家一起讨论下,望指正。由于系统原因,复制到帖子上的源码格式稍乱,大家可以下载下来。
/****************************************************
* 文 件 名:
* 描 述:GT9147操作文件
* 作 者:YouDream
* 编写时间:2015.02.04
* 说 明:在探索者STM32F4开发平台试验通过
引用请说明出处
*****************************************************/
#ifndef _GT9147_H
#define _GT9147_H
/*********************头文件包含*********************/
#include "stm32f4xx.h"
#include "BitBand.h"
#include "Delay.h"
/********端口模式寄存器设置,PF11设置为输入模式*******/
#define GT9147_SDA_SetAsIntput() {
GPIOF->MODER &= ~(3 << (11 * 2));
GPIOF->MODER |= 0 << (11 * 2);
}
/******端口模式寄存器设置,PF11设置为通用输出模式******/
#define GT9147_SDA_SetAsOutput() {
GPIOF->MODER &= ~(3 << (11 * 2));
GPIOF->MODER |= 1 << (11 * 2);
}
/*********************IO操作函数*********************/
#define GT9147_RST GPIOC_UAOPin(13) //用在输出模式
#define GT9147_SCL GPIOB_UAOPin(0) //用在输出模式
#define GT9147_SDA GPIOF_UAOPin(11) //用在输出模式
#define GT9147_SDA_Read GPIOF_UAIPin(11) //用在输入模式
#define GT9147_INT GPIOB_UAIPin(1) //用在输入模式
/***************GT9147 Device Address****************/
#define GT9147_DevAdr0 0x28 //最低位是读写控制位,按位或0x01则读,按位与0xfe则写
/*
#define GT9147_DevAdr1 0xBA //最低位是读写控制位,按位或0x01则读,按位与0xfe则写
*/
/******************GT9147寄存器地址*******************/
#define GT9147_ConfigMsgReg 0x8047 //GT9147配置信息寄存器起始地址
#define GT9147_ProductIDReg 0x8140 //GT9147产品ID寄存器地址
#define GT9147_TouchStateReg 0X814E //GT9147当前触摸情况寄存器地址
#define GT9147_TouchPoint1Reg 0X8150 //GT9147触摸点1寄存器起始地址
#define GT9147_TouchPoint2Reg 0X8158 //GT9147触摸点2寄存器起始地址
#define GT9147_TouchPoint3Reg 0X8160 //GT9147触摸点3寄存器起始地址
#define GT9147_TouchPoint4Reg 0X8168 //GT9147触摸点4寄存器起始地址
#define GT9147_TouchPoint5Reg 0X8170 //GT9147触摸点5寄存器起始地址
//触摸点相关数据结构体定义
typedef struct
{
uint8_t TouchSta; //触摸情况,bit7-bit5:保留;bit4-bit0触摸点按下有效标志,有效为1,分别对应触摸点5-1;
uint16_t x[5]; //支持5点触摸,需要使用5组坐标存储触摸点数据
uint16_t y[5];
}TouchPointRefTypeDef;
//声明一个TouchPointRefTypeDef类型的结构体
extern TouchPointRefTypeDef TPR_Structure;
/********************外部函数声明********************/
extern void GT9147_WrNByte(uint8_t Daddr,uint16_t Waddr,uint8_t a[],uint8_t n);
extern void GT9147_RdNByte(uint8_t Daddr,uint16_t Waddr,uint8_t a[],uint8_t n);
extern void GT9147_SendConfigMSG(uint8_t cmd);
extern void GT9147_Init(void);
extern void GT9147_Scan(void);
#endif
/*********************End of File********************/
/****************************************************
* 文 件 名:
* 描 述:GT9147操作文件
* 作 者:YouDream
* 编写时间:2015.02.04
* 说 明:在探索者STM32F4开发平台试验通过
引用请说明出处
*****************************************************/
#include "GT9147.h"
/****************************************************
* GT9147配置信息表
* 第一个字节为版本号(0X60),必须保证新的版本号大于等于GT9147内部flash原有版本号,才会更新配置.
* 最后两个字节分别为写入“配置信息校验(0x8047到0x80FE之字节和的补码)和配置已更新标记(由主控写入标记0x01)”寄存器的值,
* 在写入配置信息表之时需要进行计算,预设值为0。
*****************************************************/
uint8_t GT9147_ConfigMSGTBL[186] =
{
0X60,0XE0,0X01,0X20,0X03,0X05,0X35,0X00,0X02,0X08,
0X1E,0X08,0X50,0X3C,0X0F,0X05,0X00,0X00,0XFF,0X67,
0X50,0X00,0X00,0X18,0X1A,0X1E,0X14,0X89,0X28,0X0A,
0X30,0X2E,0XBB,0X0A,0X03,0X00,0X00,0X02,0X33,0X1D,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X32,0X00,0X00,
0X2A,0X1C,0X5A,0X94,0XC5,0X02,0X07,0X00,0X00,0X00,
0XB5,0X1F,0X00,0X90,0X28,0X00,0X77,0X32,0X00,0X62,
0X3F,0X00,0X52,0X50,0X00,0X52,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,
0X0F,0X03,0X06,0X10,0X42,0XF8,0X0F,0X14,0X00,0X00,
0X00,0X00,0X1A,0X18,0X16,0X14,0X12,0X10,0X0E,0X0C,
0X0A,0X08,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X29,0X28,0X24,0X22,0X20,0X1F,0X1E,0X1D,
0X0E,0X0C,0X0A,0X08,0X06,0X05,0X04,0X02,0X00,0XFF,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0 ,0
};
volatile uint8_t RevAckF = 0; //收到应答信号的标志位,为0表示收到
TouchPointRefTypeDef TPR_Structure = {0,{0},{0}}; //定义一个TouchPointRefTypeDef类型的结构体
/****************************************************
* 函数名称 :
* 功 能 :单片机发送起始信号
* 入口参数 :无
* 返回参数 :无
* 注意事项 :
*****************************************************/
void GT9147_Start(void)
{
GT9147_SDA_SetAsOutput(); //SDA口设置为输出
GT9147_SDA = 1;
GT9147_SCL = 1; //SCL最小高电平脉宽:0.6us
Delay_Xus(2); //起始信号的最小建立时间:0.6us
GT9147_SDA = 0; //SCL高电平期间,SDA的一个下降沿表示起始信号
Delay_Xus(2); //起始信号的最小保持时间:0.6us
GT9147_SCL = 0; //箝住总线,为发送器件地址做准备;
Delay_Xus(2); //SCL最小低电平脉宽:1.2us,由RET实现
}
/****************************************************
* 函数名称 :
* 功 能 :单片机发送停止信号
* 入口参数 :无
* 返回参数 :无
* 注意事项 :
*****************************************************/
void GT9147_Stop(void)
{
GT9147_SDA_SetAsOutput(); //SDA口设置为输出
GT9147_SDA = 0;
GT9147_SCL = 1; //SCL最小高电平脉宽:0.6us
Delay_Xus(2); //停止信号的最小建立时间:0.6us
GT9147_SDA = 1; //SCL高电平期间,SDA的一个上升沿表示停止信号
Delay_Xus(2); //新的发送开始前总线最小空闲时间:1.2us
// AT24Cxx_SDA=0;
GT9147_SCL = 0; //箝住总线,为新的发送做准备;
Delay_Xus(2); //SCL最小低电平脉宽:1.2us,由RET实现
}
/****************************************************
* 函数名称 :
* 功 能 :单片机发送应答信号
* 入口参数 :无
* 返回参数 :无
* 注意事项 :单片机读1B数据后发送一个应答信号
*****************************************************/
void GT9147_McuACK(void)
{
GT9147_SDA_SetAsOutput(); //SDA口设置为输出
GT9147_SDA = 0;
GT9147_SCL = 1; //SCL最小高电平脉宽:0.6us
Delay_Xus(2);
GT9147_SCL = 0; //SCL最小低电平脉宽:1.2us
Delay_Xus(2);
// GT9147_SDA = 1;
}
/****************************************************
* 函数名称 :
* 功 能 :单片机发送非应答信号
* 入口参数 :无
* 返回参数 :无
* 注意事项 :单片机读数据停止前发送一个非应答信号
*****************************************************/
void GT9147_McuNACK(void)
{
GT9147_SDA_SetAsOutput(); //SDA口设置为输出
GT9147_SDA = 1;
GT9147_SCL = 1; //SCL最小高电平脉宽:0.6us
Delay_Xus(2);
GT9147_SCL = 0; //SCL最小低电平脉宽:1.2us
Delay_Xus(2);
// GT9147_SDA = 0;
}
/****************************************************
* 函数名称 :
* 功 能 :单片机检查GT9147送来的应答信号
* 入口参数 :无
* 返回参数 :无
* 注意事项 :单片机写1个地址/数据后检查
全局变量RevAckF:收到AT24C应答信号的标志位,为0表示收到
*****************************************************/
void GT9147_CheckAck(void)
{
GT9147_SDA_SetAsIntput(); //置SDA为输入口
GT9147_SCL = 1; //使SDA上数据有效;SCL最小高电平脉宽:0.6us
Delay_Xus(2);
RevAckF = 0; //预设单片机收到应答信号
if (GT9147_SDA_Read ) //检查SDA状态,有应答则RevAckf=0
RevAckF = 1; //无应答则RevAckf=1
GT9147_SCL = 0; //箝住总线,为新的发送做准备;
Delay_Xus(2); //SCL最小低电平脉宽:1.2us,由RET实现
}
/****************************************************
* 函数名称 :
* 功 能 :单片机向IIC总线发送1B的地址/数据
* 入口参数 :待发送的1B地址/数据
* 返回参数 :无
* 注意事项 :不是一个完整的数据发送过程;送数的顺序是从高到低
*****************************************************/
void GT9147_WrOneByte(uint8_t dat)
{
uint8_t i; //地址/数据位数暂存单元
GT9147_SDA_SetAsOutput(); //SDA口设置为输出
for(i = 8; i > 0; i--) //8位1B地址/数据的长度
{
if(dat & 0x80)
GT9147_SDA = 1; //发送"1"
else
GT9147_SDA = 0; //发送"0"
// GT9147_SDA = dat & 0x80;
GT9147_SCL = 1; //使SDA上的数据有效
Delay_Xus(2); //SCL最小高电平脉宽:0.6us
GT9147_SCL = 0; //SCL最小低电平脉宽:1.2us
Delay_Xus(2);
dat <<= 1; //发送数据左移1位,为下位发送准备
}
}
/****************************************************
* 函数名称 :
* 功 能 :单片机从IIC总线接收1B的数据
* 入口参数 :无
* 返回参数 :收到的1B数据
* 注意事项 :不是一个完整的数据接收过程;从高到低的顺序接收数据
*****************************************************/
uint8_t GT9147_RdOneByte(void)
{
uint8_t i,dat = 0; //接收数据位数和内容暂存单元
GT9147_SDA_SetAsIntput(); //置SDA为输入口
for(i = 8;i > 0;i--)
{
GT9147_SCL = 1; //使SDA上的数据有效;SCL最小高电平脉宽:0.6us
Delay_Xus(2); //SCL最小高电平脉宽:0.6us
dat <<= 1; //数据dat左移1位,注意以下两句顺序不可颠倒
if(GT9147_SDA_Read) //读入SDA上的数据
dat |= 0x01;
GT9147_SCL = 0; //SCL为低电平允许SDA上的数据变化
Delay_Xus(2); //SCL最小低电平脉宽:1.2us
}
return(dat); //返回1B的数据
}
/****************************************************
* 函数名称 :
* 功 能 :单片机向GT9147发送n字节的数据
* 入口参数 :写器件地址,寄存器首地址,发送数据缓冲区首地址,写数据的长度
* 返回参数 :无
* 注意事项 :
*****************************************************/
void GT9147_WrNByte(uint8_t Daddr,uint16_t Waddr,uint8_t a[],uint8_t n)
{
uint8_t k;
do
{
GT9147_Start(); //发送起始信号
GT9147_WrOneByte(Daddr & 0xfe); //发送写器件地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
GT9147_WrOneByte((uint8_t)(Waddr >> 8));//发送1B的高位地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
GT9147_WrOneByte((uint8_t)(Waddr)); //发送1B的低位地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
for (k=0; k<n; k++)
{
GT9147_WrOneByte(a[k]); //发送1B的数据
GT9147_CheckAck(); //检查AT24Cxx送来的应答信号
if(RevAckF) break; //未收到应答位说明发送错误了,需从头开始
}
} while(RevAckF);
GT9147_Stop(); //发送停止信号
Delay_Xms(1); //延时1ms,延时等待EEPROM内部数据处理
}
/****************************************************
* 函数名称 :
* 功 能 :单片机从GT9147接收n字节的数据
* 入口参数 :器件地址,寄存器首地址,接收数据缓冲区首地址,写数据的长度
* 返回参数 :无
* 注意事项 :
*****************************************************/
void GT9147_RdNByte(uint8_t Daddr,uint16_t Waddr,uint8_t a[],uint8_t n)
{
uint8_t k;
do
{
GT9147_Start(); //发送起始信号
GT9147_WrOneByte(Daddr & 0xfe); //发送写器件地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
GT9147_WrOneByte((uint8_t)(Waddr >> 8));//发送1B的高位地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
GT9147_WrOneByte((uint8_t)(Waddr)); //发送1B的低位地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
GT9147_Start(); //发送起始信号
GT9147_WrOneByte(Daddr | 0x01); //发送读器件地址
GT9147_CheckAck(); //检查应答位
if(RevAckF) continue; //未收到应答位则重发
} while(RevAckF);
for(k = 0; k < n; k++)
{
a[k] = GT9147_RdOneByte(); //读入1B数据到接收数据缓冲区中
GT9147_McuACK(); //发送应答位
}
GT9147_McuNACK(); //n个字节读完,发送非应答位
GT9147_Stop(); //发送停止信号
}
/****************************************************
* 函数名称 :
* 功 能 :向GT9147写入配置信息
* 入口参数 :cmd,为1更新配置信息,为0不更新
* 返回参数 :None
* 注意事项 :
*****************************************************/
void GT9147_SendConfigMSG(uint8_t cmd)
{
uint8_t i;
GT9147_ConfigMSGTBL[184] = 0;
for(i = 0;i < 184;i++)
{
GT9147_ConfigMSGTBL[184] += GT9147_ConfigMSGTBL; //计算校验和(0x8047到0x80FE之间字节和)
}
GT9147_ConfigMSGTBL[184] = ~GT9147_ConfigMSGTBL[184] + 1; //配置信息校验(0x8047到0x80FE之间字节和的补码)
GT9147_ConfigMSGTBL[185] = cmd; //配置已更新标记,写入0x01则保存更新配置
GT9147_WrNByte(GT9147_DevAdr0,GT9147_ConfigMsgReg,GT9147_ConfigMSGTBL,186); //写入配置信息(0x8047到0x8100)
}
/****************************************************
* 函数功能 :GT9147控制端口配置
* 入口参数 :无
* 返回参数 :无
* 注意事项 :
*****************************************************/
void GT9147_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC |
RCC_AHB1Periph_GPIOF, ENABLE); //开启对应外设的时钟
/**********************PB0,时钟*********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //选择要控制的GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //设置引脚的操作模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置引脚的输出速率
// GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; //设置引脚的输出速率
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置引脚的输出类型
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //设置引脚的上下拉模式
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化对应GPIO
/**********************PB1,中断*********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //选择要控制的GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //设置引脚的操作模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置引脚的输出速率
// GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; //设置引脚的输出速率
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置引脚的输出类型
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //设置引脚的上下拉模式
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化对应GPIO
/*********************PC13,片选*********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //选择要控制的GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //设置引脚的操作模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置引脚的输出速率
// GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; //设置引脚的输出速率
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置引脚的输出类型
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //设置引脚的上下拉模式
GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化对应GPIO
/**********************PF11,数据*********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //选择要控制的GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //设置引脚的操作模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置引脚的输出速率
// GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; //设置引脚的输出速率
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置引脚的输出类型
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //设置引脚的上下拉模式
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化对应GPIO
}
/****************************************************
* 函数功能 :GT9147初始化
* 入口参数 :无
* 返回参数 :无
* 注意事项 :
*****************************************************/
void GT9147_Init(void)
{
uint8_t temp = 0;
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体
/*****************GT9147控制端口配置*****************/
GT9147_GPIO_Config();
/*****************设定地址为0x28/0x29****************/
GT9147_RST = 0; //前面IO配置中已将INT设置为高(上拉输入),故地址GT9147的地址将被设置为0x28/0x29
Delay_Xms(5); //地址设置完成后,应将INT设置为浮空输入模式
GT9147_RST = 1;
Delay_Xms(10);
/**********************PB1,中断*********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //选择要控制的GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //设置引脚的操作模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //设置引脚的输出速率
// GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; //设置引脚的输出速率
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置引脚的输出类型
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //设置引脚的上下拉模式,浮空
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化对应GPIO
Delay_Xms(80);
/********************写入配置信息********************/
GT9147_RdNByte(GT9147_DevAdr0,GT9147_ConfigMsgReg,&temp,1);//读取版本号,第一个字节为版本号
if(temp < 0x60) //版本号较低,则更新配置信息
{
GT9147_SendConfigMSG(0x01);
}
}
/****************************************************
* 函数名称 :
* 功 能 :扫描触摸屏,得到触摸点相关数据
* 入口参数 :无
* 返回参数 :无
* 注意事项 :
*****************************************************/
//为方便操作,将触摸点寄存器拟合在一个数组中
const uint16_t GT9147_TPR_TBL[5] = {GT9147_TouchPoint1Reg,GT9147_TouchPoint2Reg,GT9147_TouchPoint3Reg,GT9147_TouchPoint4Reg,GT9147_TouchPoint5Reg};
void GT9147_Scan(void)
{
uint8_t i,sta = 0,dat[4] = {0};
GT9147_RdNByte(GT9147_DevAdr0,GT9147_TouchStateReg,&sta,1); //读取当前触摸情况
if(sta & 0x80) //坐标数据有效,0x814E寄存器的最高位为1表示坐标已准备好
{ //此位使用完后应清零,若未清零,下次将不能读取坐标数据,亦即0x814E寄存器其余7位均将输出0
if(sta & 0x0F) //判断几个触摸点按下,0x814E寄存器的低4位表示有效触点个数
{
TPR_Structure.TouchSta = ~(0xFF << (sta & 0x0F)); //~(0xFF << (sta & 0x0F))将点的个数转换为触摸点按下有效标志
for(i = 0;i < 5;i++)
{
if (TPR_Structure.TouchSta & (1<<i)) //分别判断触摸点1-5是否被按下
{ //被按下则读取对应触摸点坐标数据
GT9147_RdNByte(GT9147_DevAdr0,GT9147_TPR_TBL,dat,4);
// TPR_Structure.x = ((uint16_t)(dat[1]) << 8) + dat[0]; //竖屏
// TPR_Structure.y = ((uint16_t)(dat[3]) << 8) + dat[2];
TPR_Structure.x = 800 - (((uint16_t)(dat[3]) << 8) + dat[2]);//横屏
TPR_Structure.y = ((uint16_t)(dat[1]) << 8) + dat[0];
}
}
}
sta = 0; //使用完后清空0x814E寄存器所有标志
GT9147_WrNByte(GT9147_DevAdr0,GT9147_TouchStateReg,&sta,1);
}
else //清除所有触摸点按下有效标志
{
TPR_Structure.TouchSta &= 0xE0; //低5位置0
}
}
/*********************End of File********************/
---------------------------------
你好,最近买了块2.8寸电容触摸屏,分辨率240*320,也是用的GT9147,厂家发的配置文件里面是480*320,感觉有点乱,问厂家就说只有这个,我只好改了分辨率,还可以用,就是我如果手指一直按着屏幕不松,它会正确的坐标+0xffff(参照你的程序做的)交替发送,怎么不是一直发送正确的坐标呢,有时候手抬起离开,还会多发几次坐标才停止,这是要配置那些参数啊 请教下~~~
一周热门 更多>