STM32使用电容屏,从查询改为中断

tech2022-09-29  60

之前玩arm都是电阻屏,但是电容屏更加通用,这次拿ALIENTEK 4.3’LCD进行学习,里面有GT9147驱动IC(相当于控制触摸屏的一个小芯片) 把源码进行修改,从官方给的查询模式触发,变成中断触发,源码可下载,另带找到的芯片手册 找到的资源,和编写好的中断代码

关于电容屏

有自我电容和交互电容 我们一般用的是投射电容式触摸屏里面的交互电容

原理

自我电容: 在玻璃表面有用 ITO 制成的横向与纵向的扫描电极,这些电极和地之间就构成一个电 容的两极。当用手或触摸笔触摸的时候就会并联一个电容到电路中去,从而使在该条扫描线上 的总体的电容量有所改变,就能检测出来什么地方电容改变 用在笔记本电脑上的触摸屏上 交互电容: 交互电容又叫做跨越电容,它是在玻璃表面的横向和纵向的 ITO 电极的交叉处形成电容。 交互电容的扫描方式就是扫描每个交叉处的电容变化,来判定触摸点的位置。 用在平板电脑和手机上

所以电容屏和电阻屏相比电容屏 优点:手感好、无需校准、支持多点触摸、透光性好。 缺点:成本高、精度不高、抗干扰能力差(要在良好的环境下才能工作)。

操控电容屏

我们用MCU通过四根线进行IIC的数据传输来对驱动IC进行读取,可以得到此时触摸屏上返回的数据 四条线 :SDA、SCL、RST 和 INT SDA 和 SCL 作为 IIC通信 RST复位引脚(低电平有效) INT中断输出信号

硬件连接

PH7 = INT , PI8 =RST , PI3=SDA ,

找到电容屏地址

我们的IIC传输数据是八位的,所以在datasheet里面找到地址说明,个人推断地址线应该要照着上面进行连接

所以我们要对电容屏进行地址设置 用这段代码确定地址

u8 temp[5]; RCC->AHB1ENR|=1<<7; //使能PORTH时钟 RCC->AHB1ENR|=1<<8; //使能PORTI时钟 GPIO_Set(GPIOH,PIN7,GPIO_MODE_IN,0,0,GPIO_PUPD_PU); //PH7设置为上拉输入 GPIO_Set(GPIOI,PIN8,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);//PI8设置为推挽输出 CT_IIC_Init(); //初始化电容屏的I2C总线 GT_RST=0; //复位 delay_ms(10); GT_RST=1; //释放复位 delay_ms(10); GPIO_Set(GPIOH,PIN7,GPIO_MODE_IN,0,0,GPIO_PUPD_NONE);//PH7设置为浮空输入 delay_ms(100);
对电容屏进行数据读取

读就复杂点:start信号–>电容屏地址写信号–>寄存器地址高八位–>寄存器地址低八位 –>start信号–>电容屏地址读信号–>一直读就返回ACK,不读返回NACK reg:起始寄存器地址 buf:数据缓缓存区 len:读数据长度

void GT9147_RD_Reg(u16 reg,u8 *buf,u8 len) { u8 i; CT_IIC_Start(); CT_IIC_Send_Byte(GT_CMD_WR); //发送写命令 CT_IIC_Wait_Ack(); CT_IIC_Send_Byte(reg>>8); //发送高8位地址 CT_IIC_Wait_Ack(); CT_IIC_Send_Byte(reg&0XFF); //发送低8位地址 CT_IIC_Wait_Ack(); CT_IIC_Start(); CT_IIC_Send_Byte(GT_CMD_RD); //发送读命令 CT_IIC_Wait_Ack(); for(i=0;i<len;i++) { buf[i]=CT_IIC_Read_Byte(i==(len-1)?0:1); //发数据 } CT_IIC_Stop();//产生一个停止条件 }
对电容屏进行数据写入

start信号–>带写信号的电容屏地址–>寄存器地址高位—>寄存器地址低位–>多个数据 reg:起始寄存器地址 buf:数据缓缓存区 len:写数据长度

u8 GT9147_WR_Reg(u16 reg,u8 *buf,u8 len) { u8 i; u8 ret=0; CT_IIC_Start(); CT_IIC_Send_Byte(GT_CMD_WR); //发送写命令 CT_IIC_Wait_Ack(); CT_IIC_Send_Byte(reg>>8); //发送高8位地址 CT_IIC_Wait_Ack(); CT_IIC_Send_Byte(reg&0XFF); //发送低8位地址 CT_IIC_Wait_Ack(); for(i=0;i<len;i++) { CT_IIC_Send_Byte(buf[i]); //发数据 ret=CT_IIC_Wait_Ack(); if(ret)break; } CT_IIC_Stop(); //产生一个停止条件 return ret; }

使用电容屏

更新配置

从寄存器里面读取版本号 看看我们的有没有更新信息 当发现版本较低时,开始我们的更新,好像就是把新的序列码写上去(厂家提供,说实话找了半天也不知道哪来的) 对我们的电容屏进行跟新前版本号检验

for(i=0;i<sizeof(GT9147_CFG_TBL);i++)buf[0]+=GT9147_CFG_TBL[i];//计算校验和

把之前厂家提供的序列码依次写入个个寄存器,让厂家帮配置,把所有的补码进行校验,并且配置更新标记 这样我们的电容屏也就初始化好啦

使用查询方式知道有无按下触摸屏

我们电容屏只支持最高5点触碰,所以number of touch points 要小于6 ,并且buffer status为1,表明有触碰 用mode保存数据,清空寄存器,方便下一次读取

假如有3点按下 sta = 0xFF07|0x80|0x40 =0xFFC7 这个很精妙,是源码里给的结构体

对按下的点进行记录和判断

从寄存器里读取数值保存进buf里 并且对数据进行判断,看是否超出了lcd的数值

开始进行划线
//电容触摸屏测试函数 void ctp_test(void) { u8 t=0; u8 i=0; u16 lastpos[10][2]; //最后一次的数据 u8 maxp=5;//最多画5个点 if(lcddev.id==0X1018)maxp=10; while(1) { tp_dev.scan(0); for(t=0;t<maxp;t++) { if((tp_dev.sta)&(1<<t)) { if(tp_dev.x[t]<lcddev.width&&tp_dev.y[t]<lcddev.height)//不超出范围 { if(lastpos[t][0]==0XFFFF) { lastpos[t][0] = tp_dev.x[t]; lastpos[t][1] = tp_dev.y[t]; } lcd_draw_bline(lastpos[t][0],lastpos[t][1],tp_dev.x[t],tp_dev.y[t],2,POINT_COLOR_TBL[t]);//一个个点连接画线 lastpos[t][0]=tp_dev.x[t]; lastpos[t][1]=tp_dev.y[t]; if(tp_dev.x[t]>(lcddev.width-24)&&tp_dev.y[t]<20) { Load_Drow_Dialog();//点击res清屏幕 } } }else lastpos[t][0]=0XFFFF; } delay_ms(5);i++; if(i%20==0)LED0=!LED0; } }

把电容屏从查询模式改为中断模式

重新设置中断引脚INT

GPIO_Initure.Pin=GPIO_PIN_7; //PH7 GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //输入 GPIO_Initure.Pull=GPIO_PULLDOWN; //不带上下拉,浮空输入 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速 HAL_GPIO_Init(GPIOH,&GPIO_Initure); //初始化 HAL_NVIC_SetPriority(EXTI9_5_IRQn,2,0); //抢占优先级为2,子优先级为0 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); //使能中断线0

用自带的中断处理函数

void EXTI9_5_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);//调用中断处理公用函数 }

把之前的查询函数改为中断处理函数–>callback函数

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { u8 mode=0,temp=0,i,buf[4]; static u16 lastpos[5][2]; //最后一次的数据 GT9147_RD_Reg(GT_GSTID_REG,&mode,1); //读取触摸点的状态 if(mode&0X80&&((mode&0XF)<6)) { temp=0; GT9147_WR_Reg(GT_GSTID_REG,&temp,1);//清标志 } if((mode&0XF)&&((mode&0XF)<6)) { for(i=0;i<(mode&0XF);i++) { GT9147_RD_Reg(GT9147_TPX_TBL[i],buf,4); //读取XY坐标值 tp_dev.x[i]=((u16)buf[1]<<8)+buf[0]; tp_dev.y[i]=((u16)buf[3]<<8)+buf[2]; if(tp_dev.x[i]<lcddev.width&&tp_dev.y[i]<lcddev.height) { lcd_draw_bline(lastpos[i][0],lastpos[i][1],tp_dev.x[i],tp_dev.y[i],2,POINT_COLOR_TBL[i]);//画线 lastpos[i][0]=tp_dev.x[i]; lastpos[i][1]=tp_dev.y[i]; if(tp_dev.x[i]>(lcddev.width-24)&&tp_dev.y[i]<20) { Load_Drow_Dialog();//清除 } } } } }
最新回复(0)