STM32-触摸屏(XPT2064)
触摸屏简介:
触摸屏又称触控面板,它是一种把触摸位置转化成坐标数据的输入设备,根据触摸屏的检测原理,主要分为电阻式触摸屏和电容式触摸屏。
TFTLCD模块使用的是四线电阻式触摸屏,这种触摸屏的控制芯片有很多,包括:ADS7843、 ADS7846、 TSC2046、 XPT2046 和 AK4182 等。
电阻式触摸屏
电阻式触摸屏是一种传感器,它将矩形区域中触摸点(X,Y)的物理位置转换为代表X坐标和Y坐标的电压。电阻触摸屏的工作原理主要是通过压力感应原理来实现对屏幕内容的操作和控制的。电阻式触摸屏结构:
优点:
精度高、价格便宜、抗干扰能力强、稳定性好。
缺点:
容易被划伤、透光性不太好、不支持多点触摸。
ps:触摸屏都需要一个 AD 转换器,也就是要将电压变化读取出来,供主机求出触摸的位置。
XPT2046 :(电阻式)
- 一款 4 导线制触摸屏控制器,采用 SPI 模式进行通信。
- 内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。
- 支持从 1.5V 到 5.25V 的低电压 I/O 接口。
- 只需执行两次 A/D 转换即可查出被按的屏幕位置。
- 可以测量加在触摸屏上的压力
- 芯片内部自带温度检测、电池电压(0-6V)监测等等
引脚:
电容式触摸屏
电容屏是利用人体感应进行触点检测控制,不需要直接接触或只需要
轻微接触,通过检测感应电流来定位触摸坐标。
电容式触摸屏主要分为两种:
(1)表面电容式电容触摸屏。
表面电容式触摸屏技术是利用 ITO(铟锡氧化物,是一种透明的导电
材料)导电膜,通过电场感应方式感测屏幕表面的触摸行为进行。但是表
面电容式触摸屏有一些局限性,它只能识别一个手指或者一次触摸。
(2)投射式电容触摸屏。
投射式电容触摸屏却具有多指触控的功能。投射电容式触摸屏是传感
器利用触摸屏电极发射出静电场线。一般用于投射电容传感技术的电容
类型有两种:自我电容和交互电容。
自我电容又称绝对电容,是最广为采用的一种方法,自我电容通常是
指扫描电极与地构成的电容。
交互电容又叫做跨越电容,它是在玻璃表面的横向和纵向的 ITO 电
极的交叉处形成电容。
code:例举扫描和校正函数,具体code找stm32f4例子
int main()
{
u8 i=0;
u8 key;
u16 penColor = BLUE;
SysTick_Init(168);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init();
USART1_Init(115200);
TFTLCD_Init(); //LCD初始化(显示)
KEY_Init();
TP_Init(); //触摸屏初始化(触摸识别)
kai_display();//初始显示文字
delay_ms(2000);
LCD_Clear(WHITE); //清屏-填充颜色
display_init();//初始化显示填充颜色
while(1)
{
key=KEY_Scan(0); //扫描按键是否有键按下
if(key==KEY_UP_PRESS) //如果UP按下
{
TP_Adjust(); //校正
display_init();//初始化显示填充颜色
}
if(TP_Scan(0)) //扫描现在按下的x,y,然后进行后续的判断与画点
{
/* 选择画笔的颜色 */
if(tp_dev.y[0] > tftlcd_data.height - 18&&tp_dev.y[0]<tftlcd_data.height)
{
if(tp_dev.x[0]>220)
{
penColor = YELLOW;
}
else if(tp_dev.x[0]>200)
{
penColor = CYAN;
}
else if(tp_dev.x[0]>180)
{
penColor = GREEN;
}
else if(tp_dev.x[0]>160)
{
penColor = MAGENTA;
}
else if(tp_dev.x[0]>140)
{
penColor = RED;
}
else if(tp_dev.x[0]>120)
{
penColor = BLUE;
}
}
else //画点
{
LCD_Fill(tp_dev.x[0]-1, tp_dev.y[0]-1, tp_dev.x[0]+2,
tp_dev.y[0]+2, penColor);
}
/* 清屏 */
if ((tp_dev.x[0] > tftlcd_data.width-8*4) && (tp_dev.y[0] < 16))
{
LCD_Fill(0, 0, tftlcd_data.width-1,tftlcd_data.height-16-1, BACK_COLOR);
LCD_ShowString(tftlcd_data.width-8*4,0,tftlcd_data.width,tftlcd_data.height,16,"RST");
}
}
i++;
if(i%20==0)
{
LED1=!LED1;
}
// delay_ms(10);
}
}
//触摸屏校准代码
//得到四个校准参数
void TP_Adjust(void)
{
#if defined(TFTLCD_HX8357D
)||defined(TFTLCD_ILI9341)||defined(TFTLCD_HX8352C)|| \
defined(TFTLCD_R61509V)||defined(TFTLCD_R61509VN)||defined(TFTLCD_R61509V3)|| \
defined(TFTLCD_ILI9486)||defined(TFTLCD_ST7793)||defined(TFTLCD_ILI9325)|| \
defined(TFTLCD_ILI9327)||defined(TFTLCD_ILI9481)||defined(TFTLCD_SSD1963)|| \
defined(TFTLCD_R61509VE)
u16 pos_temp[4][2];//坐标缓存值
u8 cnt=0;
u16 d1,d2;
u32 tem1,tem2;
double fac;
u16 outtime=0;
cnt=0;
FRONT_COLOR=BLUE;
BACK_COLOR =WHITE;
LCD_Clear(WHITE);//清屏
FRONT_COLOR=RED;//红色
LCD_Clear(WHITE);//清屏
FRONT_COLOR=BLACK;
LCD_ShowString(40,40,160,100,16,(u8*)TP_REMIND_MSG_TBL);//显示提示信息
TP_Drow_Touch_Point(20,20,RED);//画点1
tp_dev.sta=0;//消除触发信号
tp_dev.xfac=0;//xfac用来标记是否校准过,所以校准之前必须清掉!以免错误
while(1)//如果连续10秒钟没有按下,则自动退出
{
tp_dev.scan(1);//扫描物理坐标
if((tp_dev.sta&0xc0)==TP_CATH_PRES)//按键按下了一次(此时按键松开了.)
{
outtime=0;
tp_dev.sta&=~(1<<6);//标记按键已经被处理过了.
pos_temp[cnt][0]=tp_dev.x[0];
pos_temp[cnt][1]=tp_dev.y[0];
cnt++;
switch(cnt)
{
case 1:
TP_Drow_Touch_Point(20,20,WHITE); //清除点1
TP_Drow_Touch_Point(tftlcd_data.width-20,20,RED); //画点2
break;
case 2:
TP_Drow_Touch_Point(tftlcd_data.width-20,20,WHITE); //清除点2
TP_Drow_Touch_Point(20,tftlcd_data.height-20,RED); //画点3
break;
case 3:
TP_Drow_Touch_Point(20,tftlcd_data.height-20,WHITE); //清除点3
TP_Drow_Touch_Point(tftlcd_data.width-20,tftlcd_data.height-20,RED); //画点4
break;
case 4: //全部四个点已经得到
//对边相等
tem1=abs(pos_temp[0][0]-pos_temp[1][0]);//x1-x2
tem2=abs(pos_temp[0][1]-pos_temp[1][1]);//y1-y2
tem1*=tem1;
tem2*=tem2;
d1=sqrt(tem1+tem2);//得到1,2的距离
tem1=abs(pos_temp[2][0]-pos_temp[3][0]);//x3-x4
tem2=abs(pos_temp[2][1]-pos_temp[3][1]);//y3-y4
tem1*=tem1;
tem2*=tem2;
d2=sqrt(tem1+tem2);//得到3,4的距离
fac=(float)d1/d2;
if(fac<0.95||fac>1.05||d1==0||d2==0)//不合格
{
cnt=0;
TP_Drow_Touch_Point(tftlcd_data.width-20,tftlcd_data.height-20,WHITE); //清除点4
TP_Drow_Touch_Point(20,20,RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
continue;
}
tem1=abs(pos_temp[0][0]-pos_temp[2][0]);//x1-x3
tem2=abs(pos_temp[0][1]-pos_temp[2][1]);//y1-y3
tem1*=tem1;
tem2*=tem2;
d1=sqrt(tem1+tem2);//得到1,3的距离
tem1=abs(pos_temp[1][0]-pos_temp[3][0]);//x2-x4
tem2=abs(pos_temp[1][1]-pos_temp[3][1]);//y2-y4
tem1*=tem1;
tem2*=tem2;
d2=sqrt(tem1+tem2);//得到2,4的距离
fac=(float)d1/d2;
if(fac<0.95||fac>1.05)//不合格
{
cnt=0;
TP_Drow_Touch_Point(tftlcd_data.width-20,tftlcd_data.height-20,WHITE); //清除点4
TP_Drow_Touch_Point(20,20,RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
continue;
}//正确了
//对角线相等
tem1=abs(pos_temp[1][0]-pos_temp[2][0]);//x1-x3
tem2=abs(pos_temp[1][1]-pos_temp[2][1]);//y1-y3
tem1*=tem1;
tem2*=tem2;
d1=sqrt(tem1+tem2);//得到1,4的距离
tem1=abs(pos_temp[0][0]-pos_temp[3][0]);//x2-x4
tem2=abs(pos_temp[0][1]-pos_temp[3][1]);//y2-y4
tem1*=tem1;
tem2*=tem2;
d2=sqrt(tem1+tem2);//得到2,3的距离
fac=(float)d1/d2;
if(fac<0.95||fac>1.05)//不合格
{
cnt=0;
TP_Drow_Touch_Point(tftlcd_data.width-20,tftlcd_data.height-20,WHITE); //清除点4
TP_Drow_Touch_Point(20,20,RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
continue;
}//正确了
//计算结果
tp_dev.xfac=(float)(tftlcd_data.width-40)/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac
tp_dev.xoff=(tftlcd_data.width-tp_dev.xfac*(pos_temp[1][0]+pos_temp[0][0]))/2;//得到xoff
tp_dev.yfac=(float)(tftlcd_data.height-40)/(pos_temp[2][1]-pos_temp[0][1]);//得到yfac
tp_dev.yoff=(tftlcd_data.height-tp_dev.yfac*(pos_temp[2][1]+pos_temp[0][1]))/2;//得到yoff
if(abs(tp_dev.xfac)>2||abs(tp_dev.yfac)>2)//触屏和预设的相反了.
{
cnt=0;
TP_Drow_Touch_Point(tftlcd_data.width-20,tftlcd_data.height-20,WHITE); //清除点4
TP_Drow_Touch_Point(20,20,RED); //画点1
LCD_ShowString(40,26,tftlcd_data.width,tftlcd_data.height,16,"TP Need readjust!");
tp_dev.touchtype=!tp_dev.touchtype;//修改触屏类型.
if(tp_dev.touchtype)//X,Y方向与屏幕相反
{
CMD_RDX=0X90;
CMD_RDY=0XD0;
}else //X,Y方向与屏幕相同
{
CMD_RDX=0XD0;
CMD_RDY=0X90;
}
continue;
}
FRONT_COLOR=BLUE;
LCD_Clear(WHITE);//清屏
LCD_ShowString(35,110,tftlcd_data.width,tftlcd_data.height,16,"Touch Screen Adjust OK!");//校正完成
delay_ms(1000);
TP_Save_Adjdata();
LCD_Clear(WHITE);//清屏
return;//校正完成
}
}
delay_ms(10);
outtime++;
if(outtime>1000)
{
TP_Get_Adjdata();
break;
}
}
#endif
#if defined(TFTLCD_NT35510)
return; //电容触摸屏不需要校准
#endif
}
u8 TP_Scan(u8 tp)
{
#if defined(TFTLCD_HX8357D)||defined(TFTLCD_ILI9341)||defined(TFTLCD_HX8352C)|| \
defined(TFTLCD_R61509V)||defined(TFTLCD_R61509VN)||defined(TFTLCD_R61509V3)|| \
defined(TFTLCD_ILI9486)||defined(TFTLCD_ST7793)||defined(TFTLCD_ILI9325)|| \
defined(TFTLCD_ILI9327)||defined(TFTLCD_ILI9481)||defined(TFTLCD_SSD1963)|| \
defined(TFTLCD_R61509VE)
if(PEN==0)//有按键按下
{
if(tp)TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]);//读取物理坐标
else if(TP_Read_XY2(&tp_dev.x[0],&tp_dev.y[0]))//读取屏幕坐标
{
tp_dev.x[0]=tp_dev.xfac*tp_dev.x[0]+tp_dev.xoff;//将结果转换为屏幕坐标
tp_dev.y[0]=tp_dev.yfac*tp_dev.y[0]+tp_dev.yoff;
}
if((tp_dev.sta&TP_PRES_DOWN)==0)//之前没有被按下
{
tp_dev.sta=TP_PRES_DOWN|TP_CATH_PRES;//按键按下
tp_dev.x[4]=tp_dev.x[0];//记录第一次按下时的坐标
tp_dev.y[4]=tp_dev.y[0];
}
}else
{
if(tp_dev.sta&TP_PRES_DOWN)//之前是被按下的
{
tp_dev.sta&=~(1<<7);//标记按键松开
}else//之前就没有被按下
{
tp_dev.x[4]=0;
tp_dev.y[4]=0;
tp_dev.x[0]=0xffff;
tp_dev.y[0]=0xffff;
}
}
return tp_dev.sta&TP_PRES_DOWN;//返回当前的触屏状态
#endif
#if defined(TFTLCD_NT35510)
return (!GT5663_Scan(0));
#endif
}