|
STM32f103的电阻触摸屏的五点校正算法 由于电阻式触摸屏就是一种传感器,它利用压力感应进行控制,将矩形区域中触摸点(X,Y)的物理位置转换为代表 X坐标和 Y 坐标的电压。这里先引入两个概念,物理坐标和逻辑坐标。物理坐标指触摸屏上点的实际位置,通常以液晶上点的个数来度量。逻辑坐标指这点被触摸时A/D 转换后的坐标值。如图1,我们假定液晶最左下角为坐标轴原点A ,在液晶上任取一点B (十字线交叉中心),B 在X 方向距离A 10 个点,在Y 方向距离A20 个点,则这点的物理坐标为(10,20)。如果我们触摸这一点时得到的X 向A/D 转换值为100,Y 向A/D 转换值为200,则这点的逻辑坐标为(100,200)。
: N6 [1 P. T9 K, q/ N! {$ O) y( b' W9 i
常用的电阻式触摸屏矫正方法有两点校准法和三点校准法。本文这里介绍的是结合了不同的电阻式触摸屏矫正法的优化算法:五点校正法。其中主要的原理是使用4点矫正法的比例运算以及三点矫正法的基准点运算。五点校正法优势在于可以更加精确的计算出X和Y方向的比例缩放系数,同时提供了中心基准点,对于一些线性电阻系数比较差电阻式触摸屏有很好的校正功能。# G8 U7 ]1 H7 G, }# M" A
; A: Q; n5 P( Z4 n& s 校正相关的变量主要有:
% Y" f3 d% x" m. A) z" F* n; {# ~; [) B8 }6 h0 z/ r
x[5] , y[5] 五点定位的物理坐标
( {& r( n# b) j# X# Q w2 g( f: w6 L) V) S
xl[5] , yl[5] 五点定位的逻辑坐标1 f1 i# C. I; X! I( X
3 k5 j V" r$ E8 v4 ~5 ` KX , KY 横纵方向伸缩系数
* T) d. I+ J/ m; v3 Y+ j
8 h' B/ t8 w {+ N XLC , YLC 中心基点逻辑坐标
& G- v9 Y, c3 C
3 E/ U# j. V n2 m0 O, m2 _) n XC , YC 中心基点物理坐标(数值采用LCD显示屏的物理长宽分辨率的一半)
2 E" f1 g/ v- J/ j
3 @$ ]& T: b7 Y' q9 p6 } 触摸屏常和点阵式液晶显示(LCD)屏叠加在一起配套使用,构成一个矩形的实际物理平面; 而由用户触摸的触摸点集合经过 A/D 转换器,得到具体显示坐标的集合,这个集合构成了一个逻辑平面。 由于存在误差,这两个平面并不重合,校准的作用就是要将逻辑平面映射到物理平面上,即得到触点在液晶屏上的位置坐标。 校准算法的中心思想也就是要建立这样一个映射函数现有的校准算法大多是基于线性校准, 即首先假定物理平面和逻辑平面之间的误差是线性误差,由旋转和偏移形成。1 n. z0 Z8 v/ p' V
; z( [* P4 b" p/ A" F9 t1 l+ J: M6 ~0 v; }
x[5] , y[5] 五点定位的物理坐标是已知的,其中4点分别设置在LCD的角落,一点设置在LCD正中心,作为基准矫正点。校正关键点和距离布局如图。校正步骤如下:7 s6 m* }$ a9 I) T e7 E
1. 通过先后点击LCD的4个角落的矫正点,获取4个角落的逻辑坐标值。# \" {! J4 r( b; F
2. 计算 s1’ = xl[2] - xl[1] 、 s3’ = xl[3] - xl[4] 、 s2’ = yl[3] - yl[2] 、 s4’ = yl[4] - yl[1]
' F4 A$ q0 g" Z' p7 { 计算 s1 = x[2] - x[1] 、 s3 = x[3] - x[4] 、 s2 = y[3] - y[2] 、 s4 = y[4] - y[1],一般取点可以人为的设定s1 = s3 和 s2 = s4,以方便运算。4 K$ g4 s$ K6 X R+ l2 b
计算 KX = ( s1’ + s3’ )/2/s1 、KY = ( s2’ + s4’ )/2/s2
* s/ B1 h9 |/ y$ T 3. 点击LCD正中心,获取中心点的逻辑坐标,作为矫正的基准点。
# U9 W6 e3 s/ ` 4. 完成以上步骤则校正完成。下次点击触摸屏的时候获取的逻辑值XL和YL,可根据公式转换成物理值:
0 W. d0 S L! o1 G* V X = ( XL - XLC ) / KX + XC ; g4 n: F/ }! H) N
Y = ( YL - YLC ) / KY + YC7 T! P: a$ s0 Z* Q! E4 y" h
换算出来的X , Y即是和LCD像素相对应的物理坐标值,方便对触屏响应程序做区域判别。
$ D( D/ X' V8 M F# r
5 e0 \; ~ S% Q' W5 a" x- N2 l- v以下是校正程序:
4 I9 ?/ L# o# u! K; J! j- * 名 称:void LCD_Adjustd(void)
4 b i: d/ b( w1 n2 G9 u$ \ - * 功 能:校正电阻屏系数 ! Y2 _, S# E8 X$ G3 ], p5 t
- * 入口参数: null . C1 I& W" O6 S: `& \% P3 i
- * 出口参数:无 4 c! `2 ?9 ` P! Q5 U- i& B* Y1 ?
- * 说 明:null . W0 [" F* O6 ]1 i1 @: R. D
- * 调用方法:LCD_Adjustd();
' ~5 u6 g% o: v. _7 r, J - ****************************************************************************/ * b8 p' n* L/ g& K$ F6 I7 o8 W
- u8 LCD_Adjustd(void) ! K& ~2 e' G7 q' e2 E [
- { 2 ?+ X" x) {% q& k% T. x
- EXTI_InitTypeDef EXTI_InitStructure; ! W; I" ?9 k& B; I4 _. K
-
- @* s( b5 r! B3 |. n9 e - EXTI_InitStructure.EXTI_Line = EXTI_Line7; ' M6 o7 I+ H! z( M. Y7 O. u
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //为中断请求
$ i3 [8 L$ H6 t$ G' {& n - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//Falling下降沿 Rising上升
3 S3 @/ ] I3 O. _; ]( m9 f% Y - EXTI_InitStructure.EXTI_LineCmd = DISABLE;
) G) J( f# }6 q8 V* W - EXTI_Init(&EXTI_InitStructure);
$ M7 s& |' S$ _8 j; o* t - //显示停止刷屏 + d: u" P* u# Z, P$ @
- TIM_Cmd(TIM3, DISABLE); //使能TIMx外设 8 j( R& I$ m+ e+ |! E& m; e
-
- A* ^ b+ s+ g! l - LCD_Clear(White );
. F8 j$ ]4 r& u9 M7 h& ~1 T- S) h - LCD_printString(110,20, "Adjustd Begin" ,Black);
" y& b/ j; }0 o" U1 x - delay_ms(5000);
; x3 \! j/ U) J5 j- o* h - // 定第一个点 / d. `! A v' x5 P3 r7 n: Y }! U2 k3 H
- LCD_Draw_Target(20, 20, Red);
1 |% o7 i' r! j$ }& d - while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)); - }/ e( z; V6 f1 w1 h+ \ d
- while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
6 j" [* K% d& {) A' Y0 W$ _ - { 1 P, D o! R+ M" R8 R* K0 o
- x[0] = Read_XY(CMD_RDX);
! u/ N0 L/ x% T9 F - y[0] = Read_XY(CMD_RDY);
: v' J6 C, a/ U$ K - LCD_ShowNum(150,80,x[0],Black); 6 B. W/ V8 V0 p) e* \! V5 B
- LCD_ShowNum(150,110,y[0],Black); 7 e( ]& l/ V: j0 d ^4 u5 l& m
- delay_ms(200); 0 j1 e6 D& m) @
- LCD_Color_Fill(150,80,200,120, White); : d1 ~4 U1 k, [; J
- }
6 Y1 C5 v" x8 A1 P - // 定第二个点 # x+ H( [4 I5 d$ U
- LCD_Draw_Target(300, 20, Red);
' p" C! x; N3 q% f2 q5 y7 W- O4 \4 z: U - LCD_Draw_Target(20, 20, White);
% P; a( L' g2 b/ M - while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
! [0 \4 Q- O: X4 Z+ s5 ~ - while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
- {% R9 _# t( k- R - {
' V V3 f- N# Z - x[1] = Read_XY(CMD_RDX); ' ^$ m$ T1 F7 A! o! _8 l/ M
- y[1] = Read_XY(CMD_RDY); , ?1 c/ _( l$ ~3 u7 d
- LCD_ShowNum(150,80,x[1],Black); ) B9 O8 t; Y$ Z7 @
- LCD_ShowNum(150,110,y[1],Black); ) _) T; S& P0 }1 I# K& A
- delay_ms(200);
6 ^0 c7 Q$ N8 ]) G - LCD_Color_Fill(150,80,200,120, White);
+ L( D! K, u% y! o9 J9 b - }
0 |/ d' q" u7 B; C - if(abs(y[1]-y[0]) >60)
# |) S" h/ q9 r - { 9 u) k" p/ @! S- k) t$ C
- LCD_Clear(White ); ( Q# k8 R, |3 D/ I9 u
- LCD_printString(110,20, "Adjustd Fail" ,Black); 9 U/ x# P8 e- h3 Z- D
- delay_ms(5000); 7 p2 [+ c: [. w! {5 [+ r' ^
- LCD_Clear(White );
( `$ s7 Q2 v: Z5 i' w0 g - return 1;
1 J8 \% ^7 s7 y7 r, C6 l* ^, J1 f - }
$ b* t, K5 j7 z! P' v+ A - // 定第三个点
1 k6 J; s- N: u4 o+ z - LCD_Draw_Target(20, 220, Red);
0 P0 m4 u- I7 J8 |- S, U, E% p% q - LCD_Draw_Target(300, 20, White); / Y0 `* Y5 M) O$ ?# M$ Z
- while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
' o8 W* p6 d4 |6 s - while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7))) + |+ E/ f( I- w6 G
- { 7 v. w p' G" I4 U& [' x" O
- x[2] = Read_XY(CMD_RDX); . P S3 v8 W8 f% Q# ]
- y[2] = Read_XY(CMD_RDY); - q p! K, y! V+ I
- LCD_ShowNum(150,80,x[2],Black); 6 g: x. E: c. b' I# E7 v& ?
- LCD_ShowNum(150,110,y[2],Black);
$ q& k9 P0 ]9 G! A - delay_ms(200);
, }$ Z: o8 k! @9 b0 V8 T% f3 c - LCD_Color_Fill(150,80,200,120, White); : s( A. @) b9 }& B6 v
- } 3 @% T& A9 c' _+ E4 s, b
- if(abs(x[2]-x[0]) >80)
* Z6 K; g- w, H8 H& ~ - {
: a [3 D4 @5 i - LCD_Clear(White );
& t b( X/ \) V2 d - LCD_printString(110,20, "Adjustd Fail" ,Black); + S8 K: q' o" w7 r* m6 V
- delay_ms(5000);
+ z7 h5 j+ t6 U/ x0 l - LCD_Clear(White ); % l' b0 w& n% r2 w# k/ y
- return 1;
0 l7 S- g- z/ A. A - } g7 p2 ?' c$ {0 O
- // 定第四个点
: k- C% I, [1 Q: E/ B - LCD_Draw_Target(300, 220, Red); ' D- Z& t& ]. X7 w" Z% Y
- LCD_Draw_Target(20, 220, White);
2 t5 e& S4 E9 l7 U - while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)); - k( q+ F8 U. `, C: A7 Y1 V7 U8 b
- while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
7 k* r) M# V' n3 M, ^7 Q3 t - { ( S( F* w- j4 W8 C; d; U
- x[3] = Read_XY(CMD_RDX); 5 W( o% D6 X, i- o- Q# r) v
- y[3] = Read_XY(CMD_RDY); : P, M A4 D$ z4 J7 Z
- LCD_ShowNum(150,80,x[3],Black); " i4 w3 B( I8 F+ V
- LCD_ShowNum(150,110,y[3],Black);
6 w; {& Z s2 d) R - delay_ms(200); $ J2 Z+ P* i9 f" `9 ^
- LCD_Color_Fill(150,80,200,120, White);
) @. O" O6 v/ L4 y) _1 Z" ~$ E% T3 _, ^ - }
5 L$ Q; \# [8 a+ c, _' i' y - if((abs(y[2]-y[3]) >60) || (abs(x[1]-x[3]) >80)) , w6 l+ `4 W6 b5 i+ e* P
- { % `5 W8 \6 ?* _2 ~3 C! D
- LCD_Clear(White );
6 h4 i: B( B6 n G$ ]6 e - LCD_printString(110,20, "Adjustd Fail" ,Black); ; K( _" A& W L9 @+ @
- delay_ms(5000); + ]5 _" X% f) S8 S0 ~ q7 \
- LCD_Clear(White );
# _0 A- G3 X6 D& g) J* o, i# v+ _ - return 1;
8 { F! R x* N, l9 t7 \+ o - }
" A4 H- E% {6 Q) T4 b( X5 f7 K( H - // 定第五个点
* {: [1 T1 v \* [& {6 @ - LCD_Draw_Target(160, 120, Red); # P+ l% q3 b. G
- LCD_Draw_Target(300, 220, White); : l4 p6 A* l' {' I3 H* W- X# C
- while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
; o1 N# R: g! K' { [: v: k - while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7))) 8 j* e1 x" P0 O' O3 g
- { 4 E! }4 ~) p, q) h9 l j# p
- x[4] = Read_XY(CMD_RDX); Y K4 \3 `5 A0 L. @3 q
- y[4] = Read_XY(CMD_RDY); " w+ k4 C6 e; w/ t* z: M
- delay_ms(200);
: _0 ?: i B) w - }
- z. q$ X- _& w" F! r2 E/ C - //计算校正系数
& v/ j6 L3 j/ M8 z - // KX = ((abs(y[0]-y[2])/280+abs(y[1]-y[3])/280)/2); \ S# R6 e2 T- [; ]+ a Y
- // KY = ((abs(x[0]-x[1])/200+abs(x[2]-x[3])/200)/2); ! S1 s+ J' l7 W; y
- KX = (((float)(y[0]-y[2])/280+(float)(y[1]-y[3])/280)/2); 5 J0 b% f9 y: R4 f9 @ T T: H* e# p
- KY = (((float)(x[0]-x[1])/200+(float)(x[2]-x[3])/200)/2);
; P" Y, H2 b6 p$ o8 ^ ~: x6 U* ? - XC = 160;
, ?$ q# u2 [5 `" ? - YC = 120;
6 J. i# b! P5 H8 Q - XLC = y[4]; # A4 S, }5 ~* p* l$ q( a
- YLC = x[4]; * O+ d7 v$ C( `# h
- 9 Z+ Q1 g9 s7 p5 j. j! f
- // 定点完成 * a( H. D2 _' Z$ t& V+ c# ?
- LCD_Clear(White );
0 ^8 S* u0 E. ] - LCD_printString(110,20, "Adjustd Done" ,Black);
3 ^' h1 E. |, c - delay_ms(5000); c9 ^8 q5 A1 m7 |: u- Z9 s
- LCD_Color_Fill(110,20,200,35, White);
+ x" x; n; }% z. T9 C M' L3 V- I - LCD_printString(110,20, "Testing" ,Black);
" W# s1 s' s& u! h -
% y9 r* ]1 P) w9 W' g - EXTI_InitStructure.EXTI_Line = EXTI_Line7;
$ L7 g1 `/ o9 h/ N" R - EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //为中断请求
$ R$ ~! }' U: v9 p0 ^ - EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//Falling下降沿 Rising上升
* J0 V Y5 D) h# y. p6 ^) g - EXTI_InitStructure.EXTI_LineCmd = ENABLE;
5 R3 m: ~& H; H1 c( _ - EXTI_Init(&EXTI_InitStructure);
% R6 \ \+ e f" e" h1 _ - EXTI_ClearITPendingBit(EXTI_Line7); //清除线路挂起位
7 W$ u) X. X0 W( w7 v: O - ( J8 q2 g8 E7 f. N
- //显示开始刷屏
% U' N0 P; Y% Z+ v1 ~ - TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
: a b- _; Q7 G+ ~) |# c; A -
% ?' L' @* g* ^6 K/ P: e - Add_Button();
* n- x- Q9 g- e4 m X S2 j -
! {: [6 f# o, g - return 0; $ \9 \6 g" Y8 x \) n
- }
复制代码 " ?4 w% z: C* K
& c1 V* R( @* Z# u& z
|