【13】、STM32F767——————>电阻触摸屏(XPT2046 模拟SPI)

  1. 简述:
    1. 触摸屏又称控制面板,它是一种把触摸位置转换成坐标数据的输入设备;
  2. 按检测原理分类:
    1. 电阻式触摸屏:
      1. 优点:价格便宜,抗干扰能力强;
      2. 缺点:单点触控,压力感应,经常校准,表面易刮花,易磨损;
    2. 电容式触摸屏:
      1. 优点:多点触控,不用校准,检测精度高; 
      2. 缺点:只能感应导电物体,表面有水珠时影响检测结果;
  3. 电阻式触摸屏检测原理:
    1. 触摸屏结构:
    2. 触摸原理:
      1. 当触摸屏按下时,XY的IOT层相互接触(类似于薄膜键盘,按键按下,触点将上面两面导通,从而检测键盘位置),从触点处把ITO层分为两个电阻,由于均匀导电的关系,两个电阻的大小与触点离两电极的距离成比例关系,利用这个特性; 可通过下述过程来检测坐标;
    3. 检测原理:
      1. 等效电路:
      2. 原理描述:
        1. X坐标计算:
          1. X+电极接驱动电压Vref,X-极接地,因此X+与X-之间形成了匀强电场,触点处的电压通过Y+电极采集得到;触点电压/驱动电压 = 触点X坐标/屏宽;
          2. 公式为:X = Vy+(Y+采集到的触点电压)*Width / Vref(X+所施加电压)
        2. Y坐标计算:原理同上
          1. Y+电极接驱动电压Vref,Y-极接地,因此Y+与Y-之间形成了匀强电场,触点处的电压通过X+电极采集得到;触点电压/驱动电压 = 触点X坐标/屏宽;
          2. 公式为:Y = Vx+(X+采集到的触点电压)*Hight / Vref(Y+所施加电压)
    4. 常用电阻触摸芯片:电阻触摸为4线制
      1. XPT2046、ADS7843、ADS7846这三款芯片完全兼容;
    5. XPT2046芯片介绍:
      1. 工作电压:2.2v~5.25v
      2. 支持1.5V~5.25V的数字I/O口
      3. 内建2.5V参考电压源
      4. SPI3线控制通信
        1. (开发板没有接到SPI接口,此处软件模拟)
      5. 模拟输入:
        1. 差分输入:本例程所用方式
        2. 单端输入:
      6. 自动Power-Down功能
    6. 芯片框图:
    7. 电气连接(软件模拟驱动):
      1. DCLK:外部时钟输入信号; ---------->PH6
      2. CS:片选信号,低电平有效;  ---------->PI8
      3. DIN:串行数据输入端,CS为低电平时,数据在DCLK上升沿锁存进来; ---------->PI3
      4. DOUT:串行数据输出端,CS为高电平时,数据在DCLK下升沿锁存进来; ---------->PG3
      5. PENIRQ:笔接触中断引脚;  ---------->PH7
    8. 时序框图:
      1. 读/写时序图:
      2. 输入配置寄存器详解:
      3. S位始终为1;
      4. 通道位只看红线标注的地方; 
      5. 其他位默认为0;
      6. 两个读指令:
        1. X轴:0xd0;
        2. Y轴:0x90;
    9. 初始化例程:
      1. I/O端口初始化;
      2. 触摸芯片初始化;
      3. 上电读取存储器数据,是否有校准触摸屏,若无进行校准,也可以用按键做强制校准;并保存数据
      4. 计算坐标,并在液晶屏显示
    10. 管脚初始化:
       /*********************************************************
       * 函数名:void BSP_Touch_IOInit(void)
       * 描述  :
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      void BSP_Touch_IOInit(void)
      {
          GPIO_InitTypeDef GPIO_InitStruct;
       
          __HAL_RCC_GPIOH_CLK_ENABLE();			//开启GPIOH时钟
          __HAL_RCC_GPIOI_CLK_ENABLE();			//开启GPIOI时钟
          __HAL_RCC_GPIOG_CLK_ENABLE();			//开启GPIOG时钟
          
          //PH6
          GPIO_InitStruct.Pin=GPIO_PIN_6;            //PH6
          GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
          GPIO_InitStruct.Pull=GPIO_PULLUP;          //上拉
          GPIO_InitStruct.Speed=GPIO_SPEED_HIGH;     //高速
          HAL_GPIO_Init(GPIOH,&GPIO_InitStruct);     //初始化
          
          //PI3,8
          GPIO_InitStruct.Pin=GPIO_PIN_3|GPIO_PIN_8; //PI3,8
          HAL_GPIO_Init(GPIOI,&GPIO_InitStruct);     //初始化
          
          //PH7
          GPIO_InitStruct.Pin=GPIO_PIN_7;            //PH7
          GPIO_InitStruct.Mode=GPIO_MODE_INPUT;      //输入
          HAL_GPIO_Init(GPIOH,&GPIO_InitStruct);     //初始化
          
          //PG3
          GPIO_InitStruct.Pin=GPIO_PIN_3;            //PG3
          HAL_GPIO_Init(GPIOG,&GPIO_InitStruct);     //初始化 
      }
    11. 写命令函数
       /*********************************************************
       * 函数名:void BSP_Touch_WriteByte(u8 num)
       * 描述  :向控制芯片写入一个命令数据
       * 输入  :时序:CS为低电平,CLK上升沿锁存数据; 
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **********************************************************/
      void BSP_Touch_WriteByte(u8 num)
      {
      	u8 count=0;   
      	for(count=0;count<8;count++)  
      	{ 	  
      		if(num&0x80)
                  TDIN(1);  
      		else
                  TDIN(0);   
      		num<<=1;    
      		TCLK(0); 
      		delay_us(1);
      		TCLK(1);		//上升沿有效	        
      	}	
      }  
    12. 读命令函数
       /*********************************************************
       * 函数名:u16 BSP_Touch_ReadAD(u8 cmd)
       * 描述  :读取X/Y轴坐标,并返回AD值; 2^12 = 4096;
       * 输入  :
       * 输出  :无
       * 返回  : 
       * 调用  :内部调用 
       **********************************************************/
      u16 BSP_Touch_ReadAD(u8 cmd)
      {
      	u8 count=0; 	  
      	u16 Num=0; 
      	TCLK(0);		//先拉低时钟 	 
      	TDIN(0); 	//拉低数据线
      	TCS(0); 		//选中触摸屏IC
      	BSP_Touch_WriteByte(cmd);//发送命令字
      	delay_us(6);//ADS7846的转换时间最长为6us
      	TCLK(0); 	     	    
      	delay_us(1);    	   
      	TCLK(1);		//给1个时钟,清除BUSY
      	delay_us(1);    
      	TCLK(0); 	     	    
      	for(count=0;count<16;count++)//读出16位数据,只有高12位有效 
      	{ 				  
      		Num<<=1; 	 
      		TCLK(0);	//下降沿有效  	    	   
      		delay_us(1);    
       		TCLK(1);
       		if(DOUT)Num++; 		 
      	}  	
      	Num>>=4;   	//只有高12位有效.
      	TCS(1);		//释放片选	 
      	return(Num);   
      }
    13. 连续采样5次,丢掉最大最小剩余数求平均值
       /*********************************************************
       * 函数名:u16 BSP_Touch_XYAverage(u8 xy)
       * 描述  :带滤波的坐标读取(X/Y),读取5次数据; 
       * 输入  :f
       * 输出  :无
       * 返回  : 
       * 调用  :内部调用 
       **********************************************************/
      u16 BSP_Touch_XYAverage(u8 xy)
      {
      	u16 i, j;
      	u16 buf[AVERAGE_TIMES];
      	u16 sum=0;
      	u16 temp;
      	for(i=0;i<AVERAGE_TIMES;i++)
              buf[i]=BSP_Touch_ReadAD(xy);		 		    
      	for(i=0;i<AVERAGE_TIMES-1; i++)//排序
      	{
      		for(j=i+1;j<AVERAGE_TIMES;j++)
      		{
      			if(buf[i]>buf[j])//升序排列
      			{
      				temp=buf[i];
      				buf[i]=buf[j];
      				buf[j]=temp;
      			}
      		}
      	}	  
      	sum=0;
      	for(i=LOST_AVE;i<AVERAGE_TIMES-LOST_AVE;i++)
              sum+=buf[i];
      	temp=sum/(AVERAGE_TIMES-2*LOST_AVE);
          
      	return temp;  
      }
    14. 误差值:连续采样2次,误差范围在设定范围内,坐标正确
       /*********************************************************
       * 函数名:u8 BSP_Touch_XYErr_Range(u16 *x,u16 *y)
       * 描述  :连续采样2次; 误差范围在50以内,正确; 
       * 输入  :
       * 输出  :无
       * 返回  : 
       * 调用  :内部调用 
       **********************************************************/
      u8 BSP_Touch_XYErr_Range(u16 *x,u16 *y)
      {
          u16 x1,x2,y1,y2;
          
          x1 = BSP_Touch_XYAverage(CMD_RDX);
          y1 = BSP_Touch_XYAverage(CMD_RDY);
          
          x2 = BSP_Touch_XYAverage(CMD_RDX);
          y2 = BSP_Touch_XYAverage(CMD_RDY);
      
          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;
      }
    15. 校准算法:4点校准,对边相等,对角相等判断为正确
       //对边相等
                          TP_temp1 = abs(TP_Value[1][0] - TP_Value[0][0]);    //x2 - x1;
                          TP_temp2 = abs(TP_Value[1][1] - TP_Value[0][1]);    //y2 - y1;
                          TP_temp1 *= TP_temp1;
                          TP_temp2 *= TP_temp2;
                          TP_d1 = sqrt(TP_temp1 + TP_temp2); //得到1,2的距离;
                      
                          TP_temp1 = abs(TP_Value[3][0] - TP_Value[2][0]);    //x4 - x3;
                          TP_temp2 = abs(TP_Value[3][1] - TP_Value[2][1]);    //y4 - y3;
                          TP_temp1 *= TP_temp1;
                          TP_temp2 *= TP_temp2;
                          TP_d2 = sqrt(TP_temp1 + TP_temp2); //得到3,4的距离; 
                      
                          TP_fac = (float)TP_d1/TP_d2;
                      
        					if(TP_fac<0.95||TP_fac>1.05||TP_d1==0||TP_d2==0)//不合格
      					{
      						count=0;
       				    	BSP_Touch_DrawPoint(BSP_LCD_InitStructure.width - 20,BSP_LCD_InitStructure.height - 20,WHITE);	//清除点4
         	 					BSP_Touch_DrawPoint(20,20,RED);     //画点1
                              BSP_LCD_ShowString(40,40,160,100,16,(u8*)TP_Again_Adjust_MSG);//提示开始校准;
                              continue;
      					}                  
                          //对角线相等
                          TP_temp1 = abs(TP_Value[3][0] - TP_Value[0][0]);    //x4 - x1;
                          TP_temp2 = abs(TP_Value[3][1] - TP_Value[0][1]);    //y4 - y1;
                          TP_temp1 *= TP_temp1;
                          TP_temp2 *= TP_temp2;
                          TP_d1 = sqrt(TP_temp1 + TP_temp2); //得到1,4的距离;
                      
                          TP_temp1 = abs(TP_Value[2][0] - TP_Value[1][0]);    //x3 - x2;
                          TP_temp2 = abs(TP_Value[2][1] - TP_Value[1][1]);    //y3 - y2;
                          TP_temp1 *= TP_temp1;
                          TP_temp2 *= TP_temp2;
                          TP_d2 = sqrt(TP_temp1 + TP_temp2); //得到2,3的距离; 
                      
                          TP_fac = (float)TP_d1/TP_d2;
                      
        					if(TP_fac<0.95||TP_fac>1.05)//不合格
      					{
      						count=0;
       				    	BSP_Touch_DrawPoint(BSP_LCD_InitStructure.width - 20,BSP_LCD_InitStructure.height - 20,WHITE);	//清除点4
         	 					BSP_Touch_DrawPoint(20,20,RED);     //画点1
                              BSP_LCD_ShowString(40,40,160,100,16,(u8*)TP_Again_Adjust_MSG);//提示开始校准;
                              continue;
      					}                     
                          
                          //计算正确
                          TP_xfac = (float)(BSP_LCD_InitStructure.width - 40)/(TP_Value[1][0] - TP_Value[0][0]); //得到xfac;
                          TP_xoff = (BSP_LCD_InitStructure.width - TP_xfac*(TP_Value[1][0] + TP_Value[0][0]))/2; //得到xoff;
       
                          TP_yfac = (float)(BSP_LCD_InitStructure.height - 40)/(TP_Value[2][1] - TP_Value[0][1]); //得到Yfac;
                          TP_yoff = (BSP_LCD_InitStructure.height - TP_yfac*(TP_Value[2][1] + TP_Value[0][1]))/2; //得到Yoff;
    16. 坐标转换:
                  Touch_X = TP_xfac * Touch_X + TP_xoff;
                  Touch_Y = TP_yfac * Touch_Y + TP_yoff;
    17. 总结:触摸算法多种多样,可以选择其他算法;

    18. 参考资料:

       
      1. 正点原子:STM32F7 开发指南(HAL 库版)
      2. 野火:STM32 HAL 库开发实战指南
发布了24 篇原创文章 · 获赞 1 · 访问量 1513

猜你喜欢

转载自blog.csdn.net/Linux_ARM9/article/details/104830868