OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 11758|回复: 7

触摸屏校准和手写的奇怪现象

[复制链接]

4

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2011-11-2
在线时间
0 小时
发表于 2012-2-26 01:10:03 | 显示全部楼层 |阅读模式

     跪求高手指教!最近参照原子大哥的手册调试stm32触摸屏。实验现象很奇怪:校准时第三、四个校准点不显示!我降低了校准精度,才可以标准。但手写时不管在哪个位置写,只能在屏幕中间画一条横线,也不能通过点“RST”区域清屏!
    touch.c的程序贴在下面,主程序见附件。望高手指点迷津,共同进步,小弟感激不尽!
#include "touch.h"
#include "ili9320.h"
#include "delay.h"
#include "stdlib.h"
#include "math.h"
#include "24cxx.h"

#include <stdio.h>
 
Pen_Holder Pen_Point;//定义笔实体
//SPI写数据
//向7843写入1byte数据  
void ADS_Write_Byte(u8 num)   

 u8 count=0;  
 for(count=0;count<8;count++) 
 {   
  if(num&0x80)TDIN=1; 
  else TDIN=0;  
  num<<=1;   
  TCLK=0;//上升沿有效     
  TCLK=1;     
 }       
}   
//SPI读数据
//从7846/7843/XPT2046/UH7843/UH7846读取adc值   
u16 ADS_Read_AD(u8 CMD)  
{  
 u8 count=0;   
 u16 Num=0;
 TCLK=0;//先拉低时钟  
 TCS=0; //选中ADS7843 
 ADS_Write_Byte(CMD);//发送命令字
 delay_us(6);//ADS7846的转换时间最长为6us
 TCLK=1;//给1个时钟,清除BUSY       
 TCLK=0;  
 for(count=0;count<16;count++) 
 {      
  Num<<=1;  
  TCLK=0;//下降沿有效          
  TCLK=1;
  if(DOUT)Num++;   
 }   
 Num>>=4;   //只有高12位有效.
 TCS=1;//释放ADS7843 
 return(Num);  
}
//读取一个坐标值
//连续读取READ_TIMES次数据,对这些数据升序排列,
//然后去掉最低和最高LOST_VAL个数,取平均值
#define READ_TIMES 15 //读取次数
#define LOST_VAL 5   //丢弃值
u16 ADS_Read_XY(u8 xy)
{
 u16 i, j;
 u16 buf[READ_TIMES];
 u16 sum=0;
 u16 temp;
 for(i=0;i<READ_TIMES;i++)
 {    
  buf=ADS_Read_AD(xy);    
 }       
 for(i=0;i<READ_TIMES-1; i++)//排序
 {
  for(j=i+1;j<READ_TIMES;j++)
  {
   if(buf>buf[j])//升序排列
   {
    temp=buf;
    buf=buf[j];
    buf[j]=temp;
   }
  }
 }  
 sum=0;
 for(i=LOST_VAL;i<READ_TIMES-LOST_VAL;i++)sum+=buf;
 temp=sum/(READ_TIMES-2*LOST_VAL);
 return temp;  
}
//带滤波的坐标读取
//最小值不能少于100.
u8 Read_ADS(u16 *x,u16 *y)
{
 u16 xtemp,ytemp;         
 xtemp=ADS_Read_XY(CMD_RDX);
 ytemp=ADS_Read_XY(CMD_RDY);                 
 if(xtemp<100||ytemp<100)return 0;//读数失败
 *x=xtemp;
 *y=ytemp;
 return 1;//读数成功

//2次读取ADS7846,连续读取2次有效的AD值,且这两次的偏差不能超过
//50,满足条件,则认为读数正确,否则读数错误.   
//该函数能大大提高准确度
#define ERR_RANGE 50 //误差范围
u8 Read_ADS2(u16 *x,u16 *y)
{
 u16 x1,y1;
  u16 x2,y2;
  u8 flag;   
    flag=Read_ADS(&x1,&y1);  
    if(flag==0)return(0);
    flag=Read_ADS(&x2,&y2);   
    if(flag==0)return(0);  
    if(((x2<=x1&&x1<x2+ERR_RANGE)||(x1<=x2&&x2<x1+ERR_RANGE))//前后两次采样在+-50内
    &&((y2<=y1&&y1<y2+ERR_RANGE)||(y1<=y2&&y2<y1+ERR_RANGE)))
    {
        *x=(x1+x2)/2;
        *y=(y1+y2)/2;
        return 1;
    }else return 0;  
}
//读取一次坐标值 
//仅仅读取一次,知道PEN松开才返回!       
u8 Read_TP_Once(void)
{
 u8 t=0;    
 en_Int_Set(0);//关闭中断
 en_Point.Key_Sta=Key_Up;
 Read_ADS2(&en_Point.X,&en_Point.Y);
 while(PEN==0&&t<=250)
 {
  t++;
  delay_ms(10);
 };
 en_Int_Set(1);//开启中断  
 if(t>=250)return 0;//按下2.5s 认为无效
 else return 1; 
}

//////////////////////////////////////////////////
//与LCD部分有关的函数 
//画一个触摸点
//用来校准用的
void Drow_Touch_Point(u8 x,u16 y,u16 colour)
{
 LCD_DrawLine(x-12,y,x+13,y,colour);//横线
 LCD_DrawLine(x,y-12,x,y+13,colour);//竖线
 ili9320_SetPoint(x+1,y+1,colour);
 ili9320_SetPoint(x-1,y+1,colour);
 ili9320_SetPoint(x+1,y-1,colour);
 ili9320_SetPoint(x-1,y-1,colour);
// Draw_Circle(x,y,6,colour);//画中心圈
}  
//画一个大点
//2*2的点     
void Draw_Big_Point(u8 x,u16 y,u16 colour)
{    
 ili9320_SetPoint(x,y,colour);//中心点
 ili9320_SetPoint(x+1,y,colour);
 ili9320_SetPoint(x,y+1,colour);
 ili9320_SetPoint(x+1,y+1,colour);      
}
//////////////////////////////////////////////////

//转换结果
//根据触摸屏的校准参数来决定转换后的结果,保存在X0,Y0中
void Convert_Pos(void)
{     
 if(Read_ADS2(&en_Point.X,&en_Point.Y))
 {
  en_Point.X0=Pen_Point.xfac*Pen_Point.X+Pen_Point.xoff;
  en_Point.Y0=Pen_Point.yfac*Pen_Point.Y+Pen_Point.yoff; 
 }
}   
//中断,检测到PEN脚的一个下降沿.
//置位Pen_Point.Key_Sta为按下状态
//中断线0线上的中断检测

//void EXTI1_IRQHandler(void)
void EXTI9_5_IRQHandler(void)
{         
 en_Point.Key_Sta=Key_Down;//按键按下          
// EXTI->PR=1<<1;  //清除LINE1上的中断标志位
 EXTI->PR=1<<7;  //清除LINE1上的中断标志位

}
//PEN中断设置 
void Pen_Int_Set(u8 en)
{
/*
 if(en)EXTI->IMR|=1<<1;   //开启line1上的中断    
 else EXTI->IMR&=~(1<<1); //关闭line1上的中断   
*/
 if(en)EXTI->IMR|=1<<7;   //开启line7上的中断    
 else EXTI->IMR&=~(1<<7); //关闭line7上的中断   

}  
//////////////////////////////////////////////////////////////////////////
//此部分涉及到使用外部EEPROM,如果没有外部EEPROM,屏蔽此部分即可
#ifdef ADJ_SAVE_ENABLE
//保存在EEPROM里面的地址区间基址,占用13个字节(RANGE:SAVE_ADDR_BASE~SAVE_ADDR_BASE+12)
#define SAVE_ADDR_BASE 40
//保存校准参数             
void Save_Adjdata(void)
{
 s32 temp;   
 //保存校正结果!             
 temp=Pen_Point.xfac*100000000;//保存x校正因素     
    AT24CXX_WriteLenByte(SAVE_ADDR_BASE,temp,4);  
 temp=Pen_Point.yfac*100000000;//保存y校正因素   
    AT24CXX_WriteLenByte(SAVE_ADDR_BASE+4,temp,4);
 //保存x偏移量
    AT24CXX_WriteLenByte(SAVE_ADDR_BASE+8,Pen_Point.xoff,2);     
 //保存y偏移量
 AT24CXX_WriteLenByte(SAVE_ADDR_BASE+10,Pen_Point.yoff,2); 
               
 temp=AT24CXX_ReadOneByte(SAVE_ADDR_BASE+12);
 temp&=0XF0;
 temp|=0X0A;//标记校准过了
 AT24CXX_WriteOneByte(SAVE_ADDR_BASE+12,temp);   
}
//得到保存在EEPROM里面的校准值
//返回值:1,成功获取数据
//        0,获取失败,要重新校准
u8 Get_Adjdata(void)
{      
 s32 tempfac;
 tempfac=AT24CXX_ReadOneByte(52);//第五十二字节的第四位用来标记是否校准过!   
 if((tempfac&0X0F)==0X0A)//触摸屏已经校准过了     
 {                
  tempfac=AT24CXX_ReadLenByte(40,4);    
  Pen_Point.xfac=(float)tempfac/100000000;//得到x校准参数
  tempfac=AT24CXX_ReadLenByte(44,4);            
  Pen_Point.yfac=(float)tempfac/100000000;//得到y校准参数
     //得到x偏移量
  tempfac=AT24CXX_ReadLenByte(48,2);        
  Pen_Point.xoff=tempfac;     
     //得到y偏移量
  tempfac=AT24CXX_ReadLenByte(50,2);       
  Pen_Point.yoff=tempfac;     
  return 1; 
 }
 return 0;
}
#endif  
//触摸屏校准代码
//得到四个校准参数
void Touch_Adjust(void)
{        
 u16 pos_temp[4][2];//坐标缓存值
 u8  cnt; 
 u16 d1,d2;
 u32 tem1,tem2;
 float fac;    
 cnt=0;
/*    
 POINT_COLOR=BLUE;
 BACK_COLOR =White;
 LCD_Clear(White);//清屏  
 POINT_COLOR=RED;//红色
 LCD_Clear(White);//清屏
*/
 ili9320_Clear(White);
 
// Drow_Touch_Point(20,20,Red);//画点1
 Drow_Touch_Point(40,40,Red);//画点2

 Pen_Point.Key_Sta=Key_Up;//消除触发信号
 Pen_Point.xfac=0;//xfac用来标记是否校准过,所以校准之前必须清掉!以免错误 
 while(1)
 {
  if(Pen_Point.Key_Sta==Key_Down)//按键按下了
  {
   if(Read_TP_Once())//得到单次按键值
   {            
    pos_temp[cnt][0]=Pen_Point.X;
    pos_temp[cnt][1]=Pen_Point.Y;
    cnt++;
   }   
   switch(cnt)
   {     
    case 1:
     ili9320_Clear(White);//清屏

//     Drow_Touch_Point(220,20,Red);//画点2
     Drow_Touch_Point(200,40,Red);//画点2

     break;
    case 2:
     ili9320_Clear(White);//清屏

//     Drow_Touch_Point(20,300,Red);//画点3
     Drow_Touch_Point(40,280,Red);//画点2

     break;
    case 3:
     ili9320_Clear(White);//清屏

//     Drow_Touch_Point(220,300,Red);//画点4
     Drow_Touch_Point(200,280,Red);//画点2

     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)//不合格
     if(fac<0.85||fac>1.15)//不合格

     {
      cnt=0;
      ili9320_Clear(White);//清屏

//      Drow_Touch_Point(20,20,Red);
      Drow_Touch_Point(40,40,Red);//画点2

      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)//不合格
     if(fac<0.85||fac>1.15)//不合格

     {
      cnt=0;
      ili9320_Clear(White);//清屏

//      Drow_Touch_Point(20,20,Red);
      Drow_Touch_Point(40,40,Red);//画点2

      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)//不合格
     if(fac<0.85||fac>1.15)//不合格

     {
      cnt=0;
      ili9320_Clear(White);//清屏

//      Drow_Touch_Point(20,20,Red);
      Drow_Touch_Point(40,40,Red);//画点2

      continue;
     }//正确了
     //计算结果

//     Pen_Point.xfac=(float)200/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac  
     Pen_Point.xfac=(float)160/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac  

     Pen_Point.xoff=(240-Pen_Point.xfac*(pos_temp[1][0]+pos_temp[0][0]))/2;//得到xoff
       
//     Pen_Point.yfac=(float)280/(pos_temp[2][1]-pos_temp[0][1]);//得到yfac
     Pen_Point.xfac=(float)240/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac  

     Pen_Point.yoff=(320-Pen_Point.yfac*(pos_temp[2][1]+pos_temp[0][1]))/2;//得到yoff 
//     POINT_COLOR=BLUE;
     ili9320_Clear(White);//清屏
     WriteString(35,110,"Touch Screen Adjust OK!",Blue,White);//校正完成
     delay_ms(1000);
     ili9320_Clear(White);//清屏  
     return;//校正完成    
   }
  }
 }
}     
//外部中断初始化函数
void Touch_Init(void)
{           
 //注意,时钟使能之后,对GPIO的操作才有效
 //所以上拉之前,必须使能时钟.才能实现真正的上拉输出
/* 
#define PEN  PGin(7)   //PG7  INT   
#define DOUT PBin(14)   //PB14  MISO 
#define TDIN PBout(15)  //PB15  MOSI 
#define TCLK PBout(13)  //PB13  SCLK  
#define TCS  PBout(12)  //PB12  CS
*/
 RCC->APB2ENR|=1<<8;    //PG时钟使能   

 RCC->APB2ENR|=1<<3;    //PB时钟使能   
 RCC->APB2ENR|=1<<0;    //开启辅助时钟        
 GPIOG->CRL&=0X0FFFFFFF;//PG7
 GPIOB->CRH&=0X000FFFFF;//PB13,14,15
 GPIOG->CRL|=0X80000000;
 GPIOB->CRH|=0X38300000; 

 GPIOB->CRH&=0XFFF0FFFF;//PB12
 GPIOB->CRH|=0X00030000;//PB12推挽输出
 GPIOB->ODR|=0XE000;    //PB13,14,15全部上拉

 GPIOG->ODR|=0X0080;    //PG7上拉
    
  Read_ADS(&Pen_Point.X,&Pen_Point.Y);//第一次读取初始化   

 Ex_NVIC_Config(GPIO_G,7,FTIR);
// MY_NVIC_Init(2,0,EXTI1_IRQChannel,2);
 MY_NVIC_Init(2,0,EXTI9_5_IRQChannel,2);
/* 
 RCC->APB2ENR|=0x01;    //使能io复用时钟    
    AFIO->EXTICR[0]|=0X0020; //EXTI13映射到PC1  
 EXTI->IMR|=1<<1;        //开启line1上的中断
 EXTI->EMR|=1<<1;        //不屏蔽line1上的事件
 EXTI->FTSR|=1<<1;       //line1上事件下降沿触发
*/ 
 RCC->APB2ENR|=0x01;    //使能io复用时钟    
    AFIO->EXTICR[1]|=0X6000; //EXTI映射到PG7  
 EXTI->IMR|=1<<7;        //开启line7上的中断
 EXTI->EMR|=1<<7;        //不屏蔽line7上的事件
 EXTI->FTSR|=1<<7;       //line7上事件下降沿触发 
 
#ifdef ADJ_SAVE_ENABLE  
 AT24CXX_Init();//初始化24CXX
 if(Get_Adjdata())return;//已经校准
 else      //未校准?
 {              
  ili9320_Clear(White);//清屏
     Touch_Adjust();  //屏幕校准
  Save_Adjdata(); 
 }   
 Get_Adjdata();
#else
 LCD_Clear(White);//清屏
    Touch_Adjust();  //屏幕校准,带自动保存     
#endif
 printf("Pen_Point.xfac:%f\n",Pen_Point.xfac);
 printf("Pen_Point.yfac:%f\n",Pen_Point.yfac);
 printf("Pen_Point.xoff:%d\n",Pen_Point.xoff);
 printf("Pen_Point.yoff:%d\n",Pen_Point.yoff);
}


 

Touch_main.c

1.9 KB, 下载次数: 94

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-2-26 02:07:51 | 显示全部楼层
直接用我们的代码是什么现象?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2011-11-2
在线时间
0 小时
 楼主| 发表于 2012-2-26 22:42:23 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
接口不对,肯定不行。我就改了接口和中断线。还有劳老师或经验人士指导一下:出现这种现象可能是什么原因?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-2-26 22:45:24 | 显示全部楼层
是不是在我们的板子上做实验?
我们板子接口固定了的,你是如何改呢?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2011-11-2
在线时间
0 小时
 楼主| 发表于 2012-2-28 22:44:16 | 显示全部楼层
我的书是用的原子老师的,板子当时问了好多家,只能买到红牛的。老师能再具体一点指明什么问题吗?接口与您的例程不符的话有哪些地方的代码需要改动?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-2-28 23:19:14 | 显示全部楼层
对照原理图修改
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2011-11-2
在线时间
0 小时
 楼主| 发表于 2012-3-1 18:17:47 | 显示全部楼层
可以手写了,但校准时下面两个点还是不显示,导致较准不准确!实在费解、、、这到底是为什么?
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2013-3-13
在线时间
0 小时
发表于 2013-3-13 16:55:48 | 显示全部楼层
回复【7楼】好好学习:
---------------------------------
楼主,你好!你那个手写怎么弄好的?我这屏校准没有问题,但是手写时怎么画都只有一个点、、、望楼主赐教!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-23 13:59

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表