首页资源分类嵌入式系统 > STM32触摸屏程序

STM32触摸屏程序

已有 445005个资源

下载专区

上传者其他资源

    文档信息举报收藏

    标    签:触摸屏

    分    享:

    文档简介

    算法进行了改进,三点校正和五点校正可选

    文档预览

    #include"touch.h" uint8_t TouchPress=0,TouchGet=0; uint8_t CalStart=0,CalFinish=0,CalCount=0; Calibration ACal; static Coordinate TestPoint={150,230}; /* 测试点 */ /* * 函数名: Config_XPT2046_INT_GPIO * 函数描述:配置PB6(XPT2046的中断引脚)为普通IO口 * 输入参数:无 * 输出参数:无 * 硬件连接:----------------- * GPIOB_Pin_6- PENIRQ(由开发板硬件连接所决定) * 调用: 外部调用 */ void Config_XPT2046_INT_GPIO(void) { /*定义一个GPIO_InitTypeDef型的结构体*/ /*这里不能定义一个指向GPIO_InitTypeDef型的结构体的指针(指针没有任何指向),如GPIO_InitTypeDef * GPIO_InitStructure*/ GPIO_InitTypeDef GPIO_InitStructure; /*开启GPIOB的外设时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); /*选择要控制的GPIOB引脚*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6; /*设置引脚模式为上拉输入*/ GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; /*调用库函数,初始化GPIOB*/ GPIO_Init(GPIOB,&GPIO_InitStructure); } /* * 函数名:Init_Touch * 描述:初始化触摸屏 * 输入:无 * 输出:无 * 调用: 外部调用 */ void Init_Touch(void) { Init_SPI_GPIO(); Config_XPT2046_INT_GPIO(); SPI_TOUCH_CS_HIGH(); Enable_SPI1(); } /* * 函数名:Scan_Touch * 描述:检查触摸屏是否有按下,按下置位TouchPress * 输入:GPIOx:x 可以是 A,B,C,D或者 E * GPIO_Pin:待读取的端口位 * 输出:无 * 调用: 外部调用 */ void Scan_Touch(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { if(!GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)) { if(!TouchGet) { if(!TouchPress) { TouchGet=1; TouchPress=1; } } } else TouchPress=0; } /****************************************************** * 函数名:XPT2046_ReadAD * 描述 :通过SPI方式读取 XPT2046 所获得的触摸AD值 * 输入 : ch取值范围 CHX:表示X通道 CHY:表示Y通道 * 输出 :无 * 举例 :无 * 调用 :内部使用 *********************************************************/ static uint16_t XPT2046_ReadAD(uint8_t ch) { uint16_t ad_value; SPI_TOUCH_CS_LOW(); SPI1_ReadWriteByte(ch); ad_value=SPI1_ReadWriteByte(Dummy_Byte); /* 第一次8个脉冲接收5-11位,第一个脉冲不接收数据 */ ad_value<<=8; ad_value|=SPI1_ReadWriteByte(Dummy_Byte); /* 第二次8个脉冲接收0-4位,最后三个脉冲不接收数据 */ ad_value>>=3; SPI_TOUCH_CS_HIGH(); return ad_value; } /****************************************************** * 函数名:Drow_Touch_Point * 描述 :在LCD指定位置画十字 * 输入 : x: X方向位置 y: Y方向位置 * 输出 :无 * 举例 :Drow_Touch_Point(100,100); * 注意 :触摸校正专用 * 调用 : 外部调用 *********************************************************/ void Drow_Touch_Point(uint16_t x,uint16_t y) { LCD_DrawLine(x-10,y,x+10,y,RED); LCD_DrawLine(x,y-10,x,y+10,RED); LCD_DrawPoint(x+1,y+1,RED); LCD_DrawPoint(x-1,y+1,RED); LCD_DrawPoint(x+1,y-1,RED); LCD_DrawPoint(x-1,y-1,RED); LCD_DrawCircle(x,y,6,RED); } /****************************************************** * 函数名:GetMidVal * 描述 :获得中位数 * 输入 : 数组a中数据的范围为-32768~32767 left的范围为0~255 right的范围为0~255 * 输出 :无 * 举例 :无 * 调用 : 内部调用 *********************************************************/ static uint8_t GetMidVal(int16_t *a,uint8_t left,uint8_t right) { uint8_t mid=left+((right-left)>>1); uint8_t y1= *(a+left) > *(a+mid) ? left : mid; uint8_t y2= *(a+left) > *(a+right) ? left : right; uint8_t y3= *(a+mid) > *(a+right) ? mid : right; if(y1==y2) { return y3; } else { return *(a+y1) > *(a+y2) ? y2 : y1; } } /****************************************************** * 函数名:Quicksort * 描述 :快速排序法,思想:利用基准数将数列分成两块(分别大于、小于基准数的两块) * 输入 : 数组a中数据的范围为-32768~32767 left的范围为0~255 right的范围为0~255 * 输出 :无 * 举例 :无 * 调用 : 内部调用 *********************************************************/ static void Quicksort(int16_t *a,uint8_t left,uint8_t right) { uint8_t lptr=left; uint8_t rptr=right; uint8_t index=GetMidVal(a,left,right); int16_t base; if(left=*(a+lptr)) lptr++; /* 左指针向后移动 */ *(a+rptr)=*(a+lptr); /* 找到一个数大于基准数 */ } *(a+lptr)=base; if(lptr>1) /* 左边至少有一个元素 */ { Quicksort(a,left,lptr-1); } Quicksort(a,lptr+1,right); } } /****************************************************** * 函数名:Touch_Sample * 描述 :连续多次读取数据,对这些数据升序排列,得到简单滤波之后的X Y * 输入 : 无 * 输出 :Coordinate结构体地址 * 举例 :无 * 注意 :”画板应用实例"专用,不是很精准,但是速度比较快 * 调用 : 内部调用 *********************************************************/ //static Coordinate *Touch_Sample(void) //{ // uint8_t count=0; // uint8_t i,j; // uint16_t temp=0; // static Coordinate screen; // // /* 对坐标X和Y进行10次采样 */ // //uint16_t Xbuf[SAMPLETIMES] = {0}; // //uint16_t Ybuf[SAMPLETIMES] = {0}; // uint16_t buf[2][SAMPLETIMES] = {{0},{0}}; // // /* 用户点击触摸屏时TOUCH_INT引脚为低 */ // while( !TOUCH_INT && (count= SAMPLETIMES) // { // LED3(!GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_5)); // //Quicksort((int16_t*)Xbuf,0,SAMPLETIMES-1); // //Quicksort((int16_t*)Ybuf,0,SAMPLETIMES-1); // // for(i=0;ibuf[0][j])//对坐标X进行升序排列 // { // temp=buf[0][i]; // buf[0][i]=buf[0][j]; // buf[0][j]=temp; // } // if(buf[1][i]>buf[1][j])//对坐标Y进行升序排列 // { // temp=buf[1][i]; // buf[1][i]=buf[1][j]; // buf[1][j]=temp; // } // } // } // for(count=1;count>3; // screen.y=screen.y>>3; // // printf("screen.x is %d",screen.x); // printf("screen.y is %d",screen.y); // // return &screen; // } // return 0; //} static Coordinate *Touch_Sample(void) { uint8_t count=0; static Coordinate screen; /* 对坐标X和Y进行10次采样 */ uint16_t Xbuf[SAMPLETIMES] = {0}; uint16_t Ybuf[SAMPLETIMES] = {0}; /* 用户点击触摸屏时TOUCH_INT引脚为低 */ while( !TOUCH_INT && (count= SAMPLETIMES) { LED3(!GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_5)); Quicksort((int16_t*)Xbuf,0,SAMPLETIMES-1); Quicksort((int16_t*)Ybuf,0,SAMPLETIMES-1); for(count=1;count>3; screen.y=screen.y>>3; printf("screen.x is %d",screen.x); printf("screen.y is %d",screen.y); return &screen; } return 0; } /******************************************************** * 函数名:Cal_3Point_Para * 描述 :三点触摸屏校正算法 * 输入 : *cal - 指向Calibration类型的指针变量 * 输出 :返回1表示成功 0失败 * 调用 : 内部调用 * 注意 :只有在LCD和触摸屏间的误差角度非常小时,才能运用下面公式 X0 X1 X2 Y0 Y1 Y2 表示触摸点的坐标值 XV0 XV1 XV2 YV0 YV1 YV2表示触摸点的电压值 *********************************************************/ static FunctionalState Cal_3Point_Para(Calibration *cal) { FunctionalState error=DISABLE; /* K=(XV0-XV2)(YV1-YV2)-(XV1-XV2)(YV0-YV2) */ cal->para.Divider1 = ((*cal).xoyfb[0].x - (*cal).xoyfb[2].x) * ((*cal).xoyfb[1].y - (*cal).xoyfb[2].y) - ((*cal).xoyfb[1].x - (*cal).xoyfb[2].x) * ((*cal).xoyfb[0].y - (*cal).xoyfb[2].y) ; if( cal->para.Divider1 == 0 ) { return error; } else { /* A=((X0-X2)(YV1-YV2)-(X1-X2)(YV0-YV2)) */ cal->para.An = ((*cal).xoy[0].x - (*cal).xoy[2].x) * ((*cal).xoyfb[1].y - (*cal).xoyfb[2].y) - ((*cal).xoy[1].x - (*cal).xoy[2].x) * ((*cal).xoyfb[0].y - (*cal).xoyfb[2].y) ; /* B=((X1-X2)(XV0-XV2)-(X0-X2)(XV1-XV2)) */ cal->para.Bn = ((*cal).xoy[1].x - (*cal).xoy[2].x) * ((*cal).xoyfb[0].x - (*cal).xoyfb[2].x) - ((*cal).xoy[0].x - (*cal).xoy[2].x) * ((*cal).xoyfb[1].x - (*cal).xoyfb[2].x) ; /* C=(YV0(XV2X1-XV1X2)+YV1(XV0X2-XV2X0)+YV2(XV1X0-XV0X1)) */ cal->para.Cn = ((*cal).xoyfb[2].x * (*cal).xoy[1].x - (*cal).xoyfb[1].x * (*cal).xoy[2].x) * (*cal).xoyfb[0].y + ((*cal).xoyfb[0].x * (*cal).xoy[2].x - (*cal).xoyfb[2].x * (*cal).xoy[0].x) * (*cal).xoyfb[1].y + ((*cal).xoyfb[1].x * (*cal).xoy[0].x - (*cal).xoyfb[0].x * (*cal).xoy[1].x) * (*cal).xoyfb[2].y ; /* D=((Y0-Y2)(YV1-YV2)-(Y1-Y2)(YV0-YV2)) */ cal->para.Dn = ((*cal).xoy[0].y - (*cal).xoy[2].y) * ((*cal).xoyfb[1].y - (*cal).xoyfb[2].y) - ((*cal).xoy[1].y - (*cal).xoy[2].y) * ((*cal).xoyfb[0].y - (*cal).xoyfb[2].y) ; /* E=(Y1-Y2)((XV0-XV2)-(Y0-Y2)(XV1-XV2)) */ cal->para.En = ((*cal).xoy[1].y - (*cal).xoy[2].y) * ((*cal).xoyfb[0].x - (*cal).xoyfb[2].x) - ((*cal).xoy[0].y - (*cal).xoy[2].y) * ((*cal).xoyfb[1].x - (*cal).xoyfb[2].x) ; /* F=(YV0(XV2Y1-XV1Y2)+YV1(XV0Y2-XV2Y0)+YV2(XV1Y0-XV0Y1)) */ cal->para.Fn = ((*cal).xoyfb[2].x * (*cal).xoy[1].y - (*cal).xoyfb[1].x * (*cal).xoy[2].y) * (*cal).xoyfb[0].y + ((*cal).xoyfb[0].x * (*cal).xoy[2].y - (*cal).xoyfb[2].x * (*cal).xoy[0].y) * (*cal).xoyfb[1].y + ((*cal).xoyfb[1].x * (*cal).xoy[0].y - (*cal).xoyfb[0].x * (*cal).xoy[1].y) * (*cal).xoyfb[2].y ; error=ENABLE; return(error) ; } } /******************************************************** * 函数名:Cal_5Point_Para * 描述 :五点触摸屏校正算法 * 输入 : *cal - 指向Calibration类型的指针变量 * 输出 :返回1表示成功 0失败 * 调用 : 内部调用 *********************************************************/ static FunctionalState Cal_5Point_Para(Calibration *cal) { FunctionalState error=DISABLE; if ( fabs((*cal).xoyfb[2].x - (*cal).xoyfb[0].x)>ERR_RANGE || fabs((*cal).xoyfb[3].x - (*cal).xoyfb[1].x)>ERR_RANGE || fabs((*cal).xoyfb[1].y - (*cal).xoyfb[0].y)>ERR_RANGE || fabs((*cal).xoyfb[3].y - (*cal).xoyfb[2].y)>ERR_RANGE ) { return error; } else { /* KX1=(XV1-XV0) */ cal->para.An = ((*cal).xoyfb[1].x - (*cal).xoyfb[0].x); /* KX2=(XV3-XV2) */ cal->para.Bn = ((*cal).xoyfb[3].x - (*cal).xoyfb[2].x); /* KX=(KX1(X3-X2)+KX2(X1-X0)) */ cal->para.Cn = (cal->para.An * ((*cal).xoy[3].x - (*cal).xoy[2].x) + cal->para.Bn * ((*cal).xoy[1].x - (*cal).xoy[0].x)); /* (X3-X2)(X1-X0) */ cal->para.Divider1 = ((*cal).xoy[3].x - (*cal).xoy[2].x) * ((*cal).xoy[1].x - (*cal).xoy[0].x) * 2; /* KY1=(YV2-YV0) */ cal->para.Dn = ((*cal).xoyfb[2].y - (*cal).xoyfb[0].y); /* KY2=(YV3-YV1) */ cal->para.En = ((*cal).xoyfb[3].y - (*cal).xoyfb[1].y); /* KY=(KY1(Y3-Y1)+KY2(Y2-Y0)) */ cal->para.Fn = (cal->para.Dn * ((*cal).xoy[3].y - (*cal).xoy[1].y) + cal->para.En * ((*cal).xoy[2].y - (*cal).xoy[0].y)); /* (Y3-Y1)(Y2-Y0) */ cal->para.Divider2 = ((*cal).xoy[3].y - (*cal).xoy[1].y) * ((*cal).xoy[2].y - (*cal).xoy[0].y) * 2; error=ENABLE; return(error) ; } } /******************************************************** * 函数名:Perform_Calibration * 描述 :进行触摸屏校正,获取校准参数 * 输入 : *cal - 指向Calibration类型的指针变量 * 输出 :返回1表示成功 0失败 * 调用 : 内部调用 *********************************************************/ static FunctionalState Perform_Calibration(Calibration *cal) { FunctionalState error=DISABLE; LCD_Clear(BACK_COLOR); #if CALMETHOD if(Cal_3Point_Para(cal)) { LCD_DisStr(50,100,(uint8_t *)"Sample Succeed",16,RED); LCD_DisStr(50,120,(uint8_t *)"Draw validated point",16,RED); error=ENABLE; return error; } else { LCD_DisStr(50,100,(uint8_t *)"Sample Fail",16,RED); LCD_DisStr(50,120,(uint8_t *)"Try Again",16,RED); return error; } #else if(Cal_5Point_Para(cal)) { LCD_DisStr(50,100,(uint8_t *)"Sample Succed",16,RED); LCD_DisStr(50,120,(uint8_t *)"Draw validated point",16,RED); error=ENABLE; return error; } else { LCD_DisStr(50,100,(uint8_t *)"Sample Fail",16,RED); LCD_DisStr(50,120,(uint8_t *)"Try Again",16,RED); return error; } #endif } /******************************************************** * 函数名:Touch_Calibration * 描述 :触摸屏校正 * 输入 : 无 * 输出 :无 * 调用 : 外部调用 *********************************************************/ void Touch_Calibration(void) { static Calibration cal; Coordinate *Sample; Coordinate Measure; switch(CalCount) { case 0: Drow_Touch_Point(20,20); break; case 1: Sample=Touch_Sample(); cal.xoyfb[0].x=Sample->x; cal.xoyfb[0].y=Sample->y; cal.xoy[0].x=20; cal.xoy[0].y=20; printf("\r\n%d,\r\n%d,\r\n%d,\r\n%d",cal.xoyfb[0].x,cal.xoyfb[0].y,cal.xoy[0].x,cal.xoy[0].y); Drow_Touch_Point(LCD_WIDTH-20,20); break; case 2: Sample=Touch_Sample(); cal.xoyfb[1].x=Sample->x; cal.xoyfb[1].y=Sample->y; cal.xoy[1].x=LCD_WIDTH-20; cal.xoy[1].y=20; printf("\r\n%d,\r\n%d,\r\n%d,\r\n%d",cal.xoyfb[1].x,cal.xoyfb[1].y,cal.xoy[1].x,cal.xoy[1].y); Drow_Touch_Point(20,LCD_HEIGHT-20); break; case 3: Sample=Touch_Sample(); cal.xoyfb[2].x=Sample->x; cal.xoyfb[2].y=Sample->y; cal.xoy[2].x=20; cal.xoy[2].y=LCD_HEIGHT-20; printf("\r\n%d,\r\n%d,\r\n%d,\r\n%d",cal.xoyfb[2].x,cal.xoyfb[2].y,cal.xoy[2].x,cal.xoy[2].y); #if CALMETHOD if(Perform_Calibration(&cal)) /* 采样正确 */ { LCD_DisStr(50,140,(uint8_t *)"Validating para",16,RED); Drow_Touch_Point(TestPoint.x,TestPoint.y); /* 绘制测试点 */ } else /* 采样错误,重新采样 */ { Drow_Touch_Point(20,20); CalCount=0; } #else Drow_Touch_Point(LCD_WIDTH-20,LCD_HEIGHT-20); #endif break; case 4: Sample=Touch_Sample(); #if CALMETHOD Measure.x=(Sample->x * cal.para.An + Sample->x * cal.para.Bn + cal.para.Cn)/cal.para.Divider1; Measure.y=(Sample->y * cal.para.Dn + Sample->y * cal.para.En + cal.para.Fn)/cal.para.Divider1; LCD_Clear(BACK_COLOR); if( fabs(TestPoint.x-Measure.x) < ERR_RANGE && fabs(TestPoint.y-Measure.y) < ERR_RANGE) { LCD_DisStr(50,100,(uint8_t *)"Validate Succeed",16,RED); ACal=cal; CalFinish=1; CalStart=0; } else { LCD_DisStr(50,100,(uint8_t *)"Validate Fail",16,RED); LCD_DisStr(50,120,(uint8_t *)"Try Again",16,RED); Drow_Touch_Point(20,20); } printf("\r\n%d,\r\n%d",Measure.x ,Measure.y); CalCount=0; #else cal.xoyfb[3].x=Sample->x; cal.xoyfb[3].y=Sample->y; cal.xoy[3].x=LCD_WIDTH-20; cal.xoy[3].y=LCD_HEIGHT-20; printf("\r\n%d,\r\n%d,\r\n%d,\r\n%d",cal.xoyfb[3].x,cal.xoyfb[3].y,cal.xoy[3].x,cal.xoy[3].y); if(Perform_Calibration(&cal)) /* 采样正确 */ { LCD_DisStr(50,140,(uint8_t *)"Validating para",16,RED); Drow_Touch_Point(TestPoint.x,TestPoint.y); /* 绘制测试点 */ } else /* 采样错误,重新采样 */ { Drow_Touch_Point(20,20); CalCount=0; } break; case 5: Sample=Touch_Sample(); Measure.x=(Sample->x-cal.xoyfb[1].x)*cal.para.Divider1/cal.para.Cn+cal.xoy[1].x; Measure.y=(Sample->y-cal.xoyfb[1].y)*cal.para.Divider2/cal.para.Fn+cal.xoy[1].y; LCD_Clear(BACK_COLOR); if( (fabs(TestPoint.x-Measure.x) < ERR_RANGE) && (fabs(TestPoint.y-Measure.y) < ERR_RANGE) ) { LCD_DisStr(50,100,(uint8_t *)"Validate Succeed",16,RED); ACal=cal; CalFinish=1; CalStart=0; } else { LCD_DisStr(50,100,(uint8_t *)"Validate Fail",16,RED); LCD_DisStr(50,120,(uint8_t *)"Try Again",16,RED); Drow_Touch_Point(20,20); } printf("\r\n%d,\r\n%d",Measure.x ,Measure.y); CalCount=0; break; #endif } CalCount++; } /******************************************************** * 函数名:ACalCoordinate * 描述 :经过校正之后触摸屏的坐标 * 输入 : 无 * 输出 :无 * 调用 : 外部调用 *********************************************************/ void ACalCoordinate(void) { Coordinate *Sample; Coordinate Measure; Sample=Touch_Sample(); #if CALMETHOD Measure.x=(Sample->x * ACal.para.An + Sample->x * ACal.para.Bn + ACal.para.Cn)/ACal.para.Divider1; Measure.y=(Sample->y * ACal.para.Dn + Sample->y * ACal.para.En + ACal.para.Fn)/ACal.para.Divider1; #else Measure.x=(Sample->x-ACal.xoyfb[1].x)*ACal.para.Divider1/ACal.para.Cn+ACal.xoy[1].x; Measure.y=(Sample->y-ACal.xoyfb[1].y)*ACal.para.Divider2/ACal.para.Fn+ACal.xoy[1].y; #endif LCD_Clear(BACK_COLOR); LCD_DrawPoint(Measure.x,Measure.y,RED); }

    Top_arrow
    回到顶部
    EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高员外,我们会尽快处理。