一、硬件环境
野火F429第一代开发板,5寸触摸屏,触摸IC为GT9157,支持5点触控(但IC是支持10点触控的)
二、GT9157初始化
总的流程:1、初始化GPIO --> 2、初始化I2C --> 3、复位GT9157以确定IC从地址 --> 4、写配置寄存器(0x8047~0x8100)
(1)初始化GPIO与I2C
这个不详述,I2C可用模拟,也可用硬件I2C。STM32F4的硬件I2C稳定性还行,最重要的是,需要设置I2C等待时间
与等待次数,超时跳出等待防止卡死。野火的I2C读取移植自GT9157的Linux驱动,使用一个i2c_msg结构体控制读写
static int I2C_Transfer( struct i2c_msg *msgs,int num)
{
int im = 0;
int ret = 0;
GTP_DEBUG_FUNC();
for (im = 0; ret == 0 && im != num; im++)
{
if ((msgs[im].flags&I2C_M_RD)) //根据flag判断是读数据还是写数据
{
ret = I2C_ReadBytes(msgs[im].addr, msgs[im].buf, msgs[im].len); //IIC读取数据
} else
{
ret = I2C_WriteBytes(msgs[im].addr, msgs[im].buf, msgs[im].len); //IIC写入数据
}
}
if(ret)
return ret;
return im; //正常完成的传输结构个数
}
以下是使用这个I2C传输函数的实例应用,先发送地址,后接收数据,总共2个传输过程故 i2c_msg 结构体数组个数为2
/**
* @brief 从IIC设备中读取数据
* @param
* @arg client_addr:设备地址
* @arg buf[0~1]: 读取数据寄存器的起始地址
* @arg buf[2~len-1]: 存储读出来数据的缓冲buffer
* @arg len: GTP_ADDR_LENGTH + read bytes count(寄存器地址长度+读取的数据字节数)
* @retval i2c_msgs传输结构体的个数,2为成功,其它为失败
*/
static int32_t GTP_I2C_Read(uint8_t client_addr, uint8_t *buf, int32_t len)
{
struct i2c_msg msgs[2];
int32_t ret=-1;
int32_t retries = 0;
GTP_DEBUG_FUNC();
/*一个读数据的过程可以分为两个传输过程:
* 1. IIC 写入 要读取的寄存器地址
* 2. IIC 读取 数据
* */
msgs[0].flags = !I2C_M_RD; //标志位取反,在I2C_Transfer中会启用发送功能
msgs[0].addr = client_addr; //IIC设备地址,GT9157可设为:0xBA XBB或者0x28 x29
msgs[0].len = GTP_ADDR_LENGTH; //寄存器地址为2字节(即写入两字节的数据)
msgs[0].buf = &buf[0]; //buf[0~1]存储的是要读取的寄存器地址
msgs[1].flags = I2C_M_RD; //读取
msgs[1].addr = client_addr; //IIC设备地址
msgs[1].len = len - GTP_ADDR_LENGTH; //要读取的数据长度
msgs[1].buf = &buf[GTP_ADDR_LENGTH]; //buf[GTP_ADDR_LENGTH]之后的缓冲区存储读出的数据
while(retries < 5)
{
ret = I2C_Transfer( msgs, 2); //调用IIC数据传输过程函数,有2个传输过程,返回成功读写次数,0代表读写失败
if(ret == 2)break;
retries++;
}
if((retries >= 5))
{
GTP_ERROR("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret);
}
return ret;
}
(2)复位GT9157
控制RESER跟INT引脚就行,不多说,注意引脚电平状态持续时间就可以
(3)写配置寄存器
把野火的程序稍微改动了以下,更好理解,实际使用的时候建议使用野火的I2C驱动
u8 test[200];
int32_t GTP_Init_Panel(void)
{
int32_t ret = -1;
int32_t i = 0;
uint8_t check_sum = 0; //用于缓存配置元素的和,用于计算校验的补码
uint8_t cfg_info[] = CTP_CFG_GROUP1;
uint8_t cfg_info_len =CFG_GROUP_LEN(cfg_info) ; //配置数组元素的个数
uint8_t cfg_num =0x80FE-0x8047+1 ; //需要配置的寄存器个数
GTP_DEBUG_FUNC();
I2C_Touch_Init(); //初始化GPIO与I2C,复位GT9157
//ret = GTP_I2C_Test();
/****** 1、测试I2C读写功能,读取0x8047这个地址的数据,如果读取成功则I2C通讯正常 *******/
test[0] = GTP_REG_CONFIG_DATA>>8; //读写的地址为0x8047
test[1] = GTP_REG_CONFIG_DATA&0xff;
for(i=0; i<5; i++)
{
ret = -1;
ret += I2C_WriteBytes(GTP_ADDRESS, test, 2); //1、写入读取的寄存器(0x8047)的地址,成功返回0
ret += I2C_ReadBytes(GTP_ADDRESS,test+2, 1); //2、将寄存器(0x8047)的数据读出,成功返回0
if(ret == -1) break; //如果读写成功则返回
}
if (ret != -1)
{
GTP_ERROR("I2C communication ERROR!");
}
//GTP_Read_Version();
/************************** 2、读取Product ID与Firmware version ************************/
test[0] = GTP_REG_VERSION>>8; //读写的地址为0x8047
test[1] = GTP_REG_VERSION&0xff;
ret += I2C_WriteBytes(GTP_ADDRESS, test, 2); //1、写入读取的寄存器地址,成功返回0
ret += I2C_ReadBytes(GTP_ADDRESS,test+2, 6); //2、将寄存器的数据读出,成功返回0
if (ret != -1)
{
GTP_ERROR("GTP read version failed");
}
if (test[5] == 0x00) //Product ID有3位与4位的区别,此屏幕ID为9157 4位
{
GTP_INFO("IC Version: %c%c%c_%02x%02x", test[2], test[3], test[4], test[7], test[6]);
}
else
{
GTP_INFO("IC Version: %c%c%c%c_%02x%02x", test[2], test[3], test[4], test[5], test[7], test[6]);
}
//将数组config从第GTP_ADDR_LENGTH个元素开始,后面的GTP_CONFIG_MAX_LENGTH个元素变成 0
memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
//将数组cfg_info的cfg_info_len个元素复制到config数组的第GTP_ADDR_LENGTH以及后面位置
memcpy(&config[GTP_ADDR_LENGTH], cfg_info, cfg_info_len);
//计算要写入checksum寄存器的值
check_sum = 0;
for (i = GTP_ADDR_LENGTH; i < cfg_num+GTP_ADDR_LENGTH; i++)
{
check_sum += config[i];
}
config[ cfg_num+GTP_ADDR_LENGTH] = (~check_sum) + 1; //checksum
config[ cfg_num+GTP_ADDR_LENGTH+1] = 1; //refresh 配置更新标志
//写入配置信息
for (i = 0; i < 5; i++)
{
ret = I2C_WriteBytes(GTP_ADDRESS, config, cfg_num + GTP_ADDR_LENGTH+2);
if (ret == 0)
{
break;
}
}
Delay(0xfffff); //延迟等待芯片更新
GTP_Get_Info();
return 0;
}
三、读取触摸坐标数据
读取的时候直接读0x814e地址,根据需要读取的触摸点的数量控制连续读取字节数。参考编程手册可知数据的意义:
修改了一下获取触摸屏坐标的函数:
/**
* @brief 触屏处理函数,轮询或者在触摸中断调用
* @param 无
* @retval 无
*/
u8 Touch_Point[35]; //5个触摸点35个数据
static void Goodix_TS_Work_Func(void)
{
u16 i;
uint8_t end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
uint8_t point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
uint8_t touch_num = 0;
uint8_t finger = 0;
uint8_t client_addr=GTP_ADDRESS;
int32_t ret = -1;
GTP_DEBUG_FUNC();
ret = GTP_I2C_Read(client_addr, point_data, 2+1+8*GTP_MAX_TOUCH);//10字节寄存器加2字节地址
if (ret < 0)
{
GTP_ERROR("I2C transfer error. errno:%dn ", ret);
return;
}
finger = point_data[GTP_ADDR_LENGTH];//状态寄存器数据
GTP_DEBUG("I2C finger:%X",finger);
if((finger & 0x80) == 0)//判断buffer status位
{
goto exit_work_func;//坐标未就绪,数据无效
}
touch_num = finger & 0x0f;//坐标点数
for(i=0;i Touch_Point[0+i*7] = point_data[3+i*8]; //ID Touch_Point[1+i*7] = point_data[4+i*8]; //x Touch_Point[2+i*7] = point_data[5+i*8]; //x Touch_Point[3+i*7] = point_data[6+i*8]; //y Touch_Point[4+i*7] = point_data[7+i*8]; //y Touch_Point[5+i*7] = point_data[8+i*8]; //xize Touch_Point[6+i*7] = point_data[9+i*8]; //xize } for(i=touch_num*7;i<5*7;i++) //清除后续触摸点数据 Touch_Point[i] = 0; exit_work_func: { ret = GTP_I2C_Write(client_addr, end_cmd, 3); if (ret < 0) { GTP_INFO("I2C write end_cmd error!"); } } } 主函数中每隔100MS输出一次坐标参数到自制上位机: void GT9xx_GetOnePiont(void) { GUI_PID_STATE State; GTP_DEBUG_FUNC(); Goodix_TS_Work_Func(); if((pre_x==-1) || (pre_y==-1)) { State.x = -1; State.y = -1; State.Pressed = 0; State.Layer = 1; GUI_PID_StoreState(&State); return; } State.Pressed = 1; State.x = pre_x; State.y =pre_y; State.Layer = 1; GUI_PID_StoreState(&State); } extern u8 Touch_Point[35]; //5个触摸点35个数据 void SendTouch_Point(void) { u8 i; for(i=0;i<35;i++) { USART_SendData(DEBUG_USART, Touch_Point[i]); while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET); } for(i=0;i<4;i++) { USART_SendData(DEBUG_USART, 0xff); while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET); } } /** * @brief 主函数 * @param 无 * @retval 无 */ int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 初始化调试串口,一般为串口1 */ Debug_USART_Config(); GTP_Init_Panel(); //触摸屏初始化必须优先于系统滴答定时器初始化 SysTick_Init(); while(1) { GT9xx_GetOnePiont(); SendTouch_Point(); Delay_MS(100); } } 四、数据获取与显示 上位机采用VS2015 C#编写,具体代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; namespace WindowsFormsApplication1 { public partial class TouchApp : Form { int MAXDATA; //计算存储对应触摸点需要的字节数 int Buffoffset = 0, EndFlag = 0, i,temp; byte[] Buff = new byte[4096]; //缓存串口数据 byte[] DisData = new byte[70]; //缓存串口数据 public TouchApp() //初始化 { InitializeComponent();
上一篇:基于STM32F103的红外遥控小车
下一篇:STM32----LTDC与DMA2D
推荐阅读最新更新时间:2024-11-12 12:16
- 热门资源推荐
- 热门放大器推荐
设计资源 培训 开发板 精华推荐
- 使用 ON Semiconductor 的 KA278RA05 的参考设计
- LM2902S 单电源函数发生器运算放大器的典型应用电路
- LTC1701,2mm 高 1.5V 转换器
- 使用 NXP Semiconductors 的 TDA2582Q 的参考设计
- 适用于 ATCA 背板的 MOSFET 功率驱动器参考设计
- LF33CPT-TR 3.3V 多路低压降稳压电源的典型应用,带 ON/OFF 拨动开关
- RT9285C 微型封装、高性能、二极管嵌入式白光 LED 驱动器的典型应用电路
- LT6656ACS6-3.3、3.3V 低功率 ADC 电压基准的典型应用
- Arduino ISP烧写器二合一
- DAPLink_Pro