一 电阻驱动与电容驱动原理
& t/ `! u+ V% F& F. y) b
! l1 V0 F- ]; b3 i8 K1 p1. 电阻屏等效电路如下所示, 当产生按压时:
) e! e6 {' a+ s2 b: yX-接地,X+接电源,Y+接ADC输入.通过读取Y+的电压以及电阻分压原理,可以得出触点的x坐标5 Z2 v- ]( l. y2 g( w
Y-接地,Y+接电源,X+接ADC输入.通过读取X+的电压以及电阻分压原理,可以得出触点的y坐标
& p; f% J7 g" ?6 {; x" F3 T* q+ E
5 F5 N7 R; s2 d. F6 c3 e( o6 T/ `7 I9 m
1 y6 ^+ K; `+ i8 L- _+ p& T3 {: e( u1 T
2. 电容屏等效图如下所示, 检测原理类似矩阵按键, 当产生按压时:
9 {1 [5 t x: [7 [7 g- S: g) x% v4 U
X轴产生从上至下依次产生激励信号(AC交流信号), Y轴电极同时接受信号 (该激励信号是交流电,可以通过电容穿到Y轴).: [& R; [0 T+ T4 d0 f" n- v# R
. q) E2 s9 n- c- V假设有如下两个按压点(分别位于(1,1)与(2,2)的位置),检测过程如下:. z* \' N4 M9 ?, w; `- M# E
当X1产生激励信号时,Y1接受到的交流信号产生了变化, 所以可以确认(1,1)处有触摸.* e/ H, Q6 i) X, Y) m+ i
接着当当X2产生激励信号时,Y2接受到的交流信号产生了变化, 所以可以确认(2,2)处也有有触摸.
; J+ z: o, D: }+ U4 p, Y* i: a' e8 Z( ?
! `. ]/ F6 q+ M8 W4 E$ ?; `* C3 u- ]8 U; }, E
二 软件模拟IIC! x M2 ^, t' l6 L
由于stm32的硬件iic有各种各样的问题,所以采用软件模拟IIC的方式,主要实现IIC起始信号函数、IIC停止信号函数、等待ACK函数、产生ACK应答函数、不产生ACK应答函数、发送字节函数、读字节函数
. I, O& b& R* R& z% ?& r1 i9 h
: \8 K& p3 j2 j: e0 A2 z) X1. 起始信号与停止信号
6 d% h6 D6 z# }/ S/ O$ I* U3 T
- O0 ^& x' L! Z9 f2 @$ {下图是IIC起始信号与停止信号时序图,通过观察该图编写起始信号与停止信号函数。
' ~& _( Q5 N. U L
2 Y4 B0 q# s0 Q8 U' p. S |+ E" x% f* d/ C3 Q
, S; I4 T4 S# x* E% _
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
5 Q9 Q1 t$ T9 _+ V- Q- /***************************************************************************************3 A6 C( b2 e) I t
- * @brief 产生IIC起始信号,当SCL为高期间,SDA由高到低的跳变
$ ]& ?9 m( g8 c/ p9 @; K( _- ] - ***************************************************************************************/
6 F! n/ B# R0 {& f$ w5 K, D) f m$ A - void CT_IIC_Start(void)! @3 G3 ~8 ?1 h7 a9 H" r+ b" F2 E' N
- {
. Z, X h; g M* F - CT_SDA_OUT(); //sda线输出: z7 @ C; \' F/ H
- CT_IIC_SCL(1);5 S5 ^# q9 M' _. X4 K
- CT_IIC_SDA(1); 1 g7 ~$ S, z) W: Q9 Q
- CT_Delay();" N5 D7 q. X" v8 t: Q
- CT_IIC_SDA(0);
' U5 {8 m" M# ?, r1 l/ { - }
复制代码
3 A( ]+ I) j; P. Q, U( w4 U' T& _停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。+ m& I6 ~) l- F7 X! p) g$ s6 n
- /***************************************************************************************
6 Z; \+ r) v3 z4 k6 W" \ - * @brief 产生IIC停止信号,当SCL为高期间,SDA由低到高的跳变+ D7 D; T, |) W1 C% O' _
- ***************************************************************************************/( N* E5 ~4 J. I" R8 x
- void CT_IIC_Stop(void)6 N2 n% |* W1 r
- {# ^# S) Q% Z' M7 d& ]- C
- CT_SDA_OUT();//sda线输出* L5 z8 Y: p: N8 g- s
- CT_IIC_SCL(1);7 l* M* C9 r/ u+ z6 l j
- CT_IIC_SDA(0);//STOP:when CLK is high DATA change form low to high, y3 z) A5 g6 P6 O! r h0 ~0 T0 |- I+ D. j
- CT_Delay();' x3 j+ _+ u) i6 |! [# I
- CT_IIC_SDA(1);) l+ L7 [, b) ?3 b2 j y
- }
复制代码
3 x7 l+ B4 n: ^3 p在GT9147数据手册中可以发现如下截图所示内容,SCL在低电平期间至少保持1.3us,其他电平最小保持0.6
& ?+ s3 Y1 ^; g( Z; z! c) `% B3 E% C8 o! ?
8 f; ~# H3 X2 Z4 \5 k* S& g+ x0 G w# q( I+ A& k
所以将IIC延时函数定时为2us可以满足所有时序。(一般支持最高速度400k的IIC设备,基本都可以使用2us延时。)8 o3 p5 w2 x$ k' f
0 q/ k! S o1 ^1 u x! R# ~1 L, w2 s- //控制I2C速度的延时
, U6 {* l2 O# d7 ?$ `- T - void CT_Delay(void)
$ N# y* N% l: O9 y5 ? - {
0 W2 A4 U( h; J0 k; J; F - delay_us(2);
4 w a5 ~% d2 ]& i% x- Q- J9 N - }
复制代码
$ W* N* F/ ~8 k4 p; Q+ E2. 数据传输 与 ACK时序
' o- m# f; B" ?( j/ E: F, }
$ B0 }- z1 @$ i" T& {/ y% v$ e4 q4 ?下图是ACK时序与 传输数据0的时序图,这两种时序图是一样的,区别在于ACK是在8个数据时序后产生,且SDA电平是由接受数据端拉低的。: ^8 J! L, H, p) o
! y, N0 O. o7 N; m6 m" q0 Q( R
) E5 O. i( D# _( t* L: k3 R9 I/ @9 S, N/ i) c5 V/ m% @
产生ACK时序:在SCL高电平期间,SDA为低电平状态。
4 s- M; ~3 y6 A" o- /***************************************************************************************% `9 ` t/ d* J5 h& q
- * @brief 产生ACK应答,
; j7 G/ P# n' L w - ***************************************************************************************/7 n' H4 F- h9 z$ j: V
- void CT_IIC_Ack(void)
5 h! X# e/ M5 l* v - {' P J% `/ S( u; E( \
- CT_IIC_SCL(0);
* B3 u# R( D' R4 y: ~ - CT_Delay();
4 B4 \1 e a# l. Y9 l) _. }1 N5 B/ { - CT_SDA_OUT();
3 a& j/ K; E6 Z' p8 s- `" ~ - CT_IIC_SDA(0);" ?0 Y4 x' D" s: {2 ]2 y$ o
- CT_IIC_SCL(1);' t+ p' ]6 t7 G) F7 r( S- N
- CT_Delay();& u9 j2 W S, {7 W4 q6 s1 f
- CT_IIC_SCL(0);
8 e- n( c: L9 e7 G - }
复制代码
8 ]2 [3 x: c6 Z& E8 k等待ACK时序:拉高SCL与SDA后, 然后设置SDA为输入检测状态,等待接受数据端拉低SDA. X. I" {/ M7 y- a/ k
- /***************************************************************************************
z: U) a# X. T. }# ~/ @ - * @brief 等待应答信号到来,等待接受数据端拉低SDA
6 P' V. }2 u0 ?' }' [- D - * @input 3 H# Q# ~2 M) N
- * @return 1,接收应答失败 ; 0,接收应答成功
S: e$ @) s3 A% _2 |" B - ***************************************************************************************/
2 \4 t2 b& c0 ]- @8 s - uint8_t CT_IIC_Wait_Ack(void), w+ J/ z G. d/ K U. i; p
- {
9 _. X# d1 p! K - uint8_t ucErrTime=0;
) T/ g: x% s1 Q- f$ R - CT_IIC_SDA(1);
3 Q7 z. }# R8 R+ Y$ n - CT_IIC_SCL(1);6 P- F# T% j0 _
- CT_SDA_IN(); //SDA设置为输入 ; d7 }3 F0 K8 {& Y4 z
- while(CT_READ_SDA)
/ _+ x0 x- j+ q6 b* c \; { - {
4 m/ L" Y+ O7 v! o5 Y - ucErrTime++;0 N! j' Z) M& Z& T8 s6 z8 H3 H
- if(ucErrTime>250){
& C% j$ \& f+ o1 j! I: x) m9 W - CT_IIC_Stop();( q3 X5 H! A! d2 a: q' n+ \
- return 1;
, M6 p* G4 v4 L) N' v - }, y% u" j" Z$ T
- CT_Delay();
2 v; E# c+ j4 J0 Q0 J4 u, h) X - }
' [( V0 w: Z, l, v! H! o* u- i2 K: T - CT_IIC_SCL(0);9 r3 p& \0 r; r' y9 {+ T7 J
- return 0; $ I/ j7 S! u, O6 |
- }
复制代码 ; U1 h+ R5 q" c0 b4 X
下图是nACK时序与 传输数据1的时序图,这两种时序图是一样的,区别在于ACK是在8个数据时序后产生,且SDA电平是由接受数据端拉低的。
; F8 e. a6 F' |
& c f; a5 ~9 @. a
1 V. o9 k7 V& `* u( u0 ^% G9 R! T7 u6 i) Y! E& g
产生ACK时序:在SCL高电平期间,SDA为高电平状态。
4 z% K" v( X0 @# k% A! u" }, V- /***************************************************************************************) Q& I% w& j. D# l5 ]
- * @brief 不产生ACK应答
& H" W2 D6 W$ b9 ^) _# l* U) F - ***************************************************************************************/
' i% c- ]8 j' ?) {6 @ - void CT_IIC_NAck(void)# S0 I6 A/ J0 f4 b
- {
) R% E- t, ]7 M8 h6 `; P2 R U3 i - CT_IIC_SCL(0);
+ k9 `4 ^( y% O7 z1 w - CT_Delay();% s) D! O: F. c l
- CT_SDA_OUT();
1 O( A' p% v) h( A - CT_IIC_SDA(1);. Y" O5 J/ @7 l6 c
- CT_IIC_SCL(1);
1 e% v7 x) k; u1 {, {1 [7 A - CT_Delay();
; w% k0 A; c2 R! j! J - CT_IIC_SCL(0);
( V2 S! Q% L$ v9 t - }
复制代码 " o' P& V' W5 `, |7 g
发送一个字节函数,优先发送高位,即从bit7开始发送。# u5 p3 b% g6 ]
- /***************************************************************************************& m7 I1 H2 O8 S# b* `$ ^
- * @brief IIC发送一个字节,! T$ l2 B4 J: g7 m' [" g3 @
- * @input ! l% M* _5 k, M
- * @return W2 p& Q& \/ b
- ***************************************************************************************/
" L, s8 l; j% T' F( F+ P* Q+ f ^ - void CT_IIC_Send_Byte(uint8_t txd)# k, m# j. P8 h. Z |
- {
- Y4 C$ R9 c+ j - uint8_t t;
* A) H) Z* Z! I d - CT_SDA_OUT();
' m, p+ t/ D; [( j. b - CT_IIC_SCL(0);//拉低时钟开始数据传输; k8 B5 Y/ }) c5 z; E% B( ~ J
- CT_Delay(); @% z" r+ X3 |7 M
- for(t=0;t<8;t++) M w V/ u$ K. }+ a1 d
- {: m# E2 \2 s% g$ ~+ Y- V( h
- CT_IIC_SDA((txd&0x80)>>7);//发送bit7位9 i2 X8 I" ?. {
- txd<<=1; //将txd的次高位左移到最高位 % K. _7 h$ K3 W5 I
- CT_IIC_SCL(1);
0 h# j9 h& u/ g) ` - CT_Delay();
9 n4 t: q$ V- X _! [) E - CT_IIC_SCL(0);
* q# L: G. d1 m+ B, j - CT_Delay();# H) X0 f* p. e6 P6 C. Z- Z
- }1 m. w2 [( i$ |8 M; R0 i
- }
复制代码
+ U5 u% g$ ~+ s, a5 S读字一个字节函数,接受到1bit数据后,将该bit放在bit0位置(通过receive++实现),如果还要继续接受数据,则将之前接受到的数据左移一位(通过receive<<=1实现),留出bit0位置接受新的数据。9 |8 R9 B; w& I2 r4 ~" M
- /***************************************************************************************
$ Y$ P! l" B2 z) \ - * @brief 读1个字节% B7 T/ R2 T/ |9 W
- * @input ack=1时,发送ACK,ack=0,发送nACK
2 l8 h5 T) P+ i - * @return
" ?& g4 b8 k$ z/ ^" G' a - ***************************************************************************************/& c) a' o/ f# ~$ y1 O
- uint8_t CT_IIC_Read_Byte(unsigned char ack)
( @" R) [1 j |; C' d0 ^* }" t4 M - {
8 D+ }1 i; v: K4 \6 ~5 {$ d - uint8_t i,receive=0;
" y9 `& p' U: U7 b- \8 {5 E - CT_SDA_IN();//SDA设置为输入! p6 A* w1 I6 y$ G
- CT_Delay();
% c, w; D# k& \2 M - for(i=0;i<8;i++ )2 U+ Z$ a( @8 l) n5 k" m
- { # f& X9 r+ c* Y% Z% K8 g
- CT_IIC_SCL(0);
0 v8 U/ H7 L7 o! _ - CT_Delay();( j8 E) d/ |& p0 k% x8 x+ I* w
- CT_IIC_SCL(1);
q3 N, A/ s9 k( ^2 D - receive<<=1;
* j+ {" z7 v$ @, a1 C9 q+ s - if(CT_READ_SDA)receive++; 8 ^* C6 n9 I* F: p) w0 z
- }
5 f1 A5 n+ n% g - if (!ack)
# W; t7 A9 L4 o1 M - CT_IIC_NAck();//发送nACK b/ Y" a6 |5 O4 W# d4 A! x: t) v
- else
: l- [0 p0 ~4 V - CT_IIC_Ack(); //发送ACK % I0 S K3 s& i) D
- return receive;
. p/ z/ A- L7 A4 w8 u - }
复制代码 ^" v2 y5 T8 X9 T6 W
三 GT9147电容触摸屏控制芯片驱动
, C2 [3 t2 O$ o6 e+ h: O% \1. GT914内部结构框图如下图所示/ W8 B0 [2 S* B" A# h+ x: c
9 I, ^* [1 i6 }7 `/ z
6 G8 O3 ]1 r- t2 ^6 D5 R# ]0 w! ]! V
5 Y/ Z& y& f- e* B. F: H
9 H3 D1 [& b# O2 w/ z M
2. 上电流程
F7 r/ l/ v+ x
7 v' D2 M& ?: z Z, aGT9147上电初始化流程如下所示:' |6 w: j- L; D Y# h! S2 M
& Q/ ], ~% p3 V配置RST输出低电平,INT输出低(或者高)电平后,位置100us以上,此阶段配置IIC地址为 0xBA/0xBB(或者0x28/0x29)
. X/ f: h% B& U/ P; V i; u4 ^接着配置RST输出高电平并维持5ms以上后,可以配置INT引脚为悬浮输入模式。7 D' G& j8 {, `4 j
等待50ms以上后,可以发送配置信息。1 s; T' m2 x. R' [2 Q( o9 x
$ a* K. `6 ~4 V8 E2 C2 \% ?1 H2 K7 x- ~
5 Y& p g# X% \" S2 X) g
6 G5 N# {0 K- E代码参考原子例程编写,贴上代码:9 W" T1 Z2 ~" E' W
+ i& a6 T1 q1 W* Y- uint8_t GT9147_Init(void)
+ t {: L2 e% y3 g' D - {
; _3 Z5 K6 z4 A- e* m3 f& D* Q - uint8_t temp[5];
% A8 k" I/ G# [8 P - & ?: S8 y3 u% V' u3 v' c
- GPIO_InitTypeDef GPIO_Initure;4 g) b- Q2 y* \, J( @
6 ?; T" A& o* u5 t- GPIO_Initure.Pin = GPIO_PIN_7; //PH7
0 _: x) ~! y& Q - GPIO_Initure.Mode = GPIO_MODE_INPUT; //输出
% i* b: X. q1 m2 E: { - GPIO_Initure.Pull = GPIO_PULLUP; //上拉
$ @( G( e( P8 z; Z8 q2 Y; j& S - GPIO_Initure.Speed = GPIO_SPEED_HIGH; //高速
" i8 f, C& ]7 k2 H" A - HAL_GPIO_Init(GPIOH, &GPIO_Initure); //初始化 D. j( }! i7 B c# a7 N% e
/ \) b4 L) B" Z5 W3 N/ K- Q- GPIO_Initure.Pin = GPIO_PIN_8; //PI8' h4 n2 K! N! a2 a5 F7 T/ ]
- GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出; j& u1 [+ [3 H5 b U
- HAL_GPIO_Init(GPIOI, &GPIO_Initure); //初始化$ C+ \; c3 G; b0 J: g z7 d
- # T# v9 V g) t- k; L- M
- CT_IIC_Init(); //初始化电容屏的I2C总线% N; M% n' r$ t) m% X7 ?! x
5 [" V3 K/ m0 ^' E3 E) \7 Q- GT_RST(0); //复位
- Q" c- F) s* O# P* M - delay_ms(1); //INT引脚电平维持100us以上: ]& y. s( c# q$ v
- GT_RST(1); //释放复位
6 r& L" j8 r/ Q9 t' E# j3 f2 R8 g - delay_ms(10); //释放复位后维持5ms以上,设置INT为悬浮输入1 `5 E& Z, l! ?& U! Q0 Q2 a4 ?- ~: z
- GPIO_Initure.Pin = GPIO_PIN_7;
$ N+ R9 g) t) I/ |0 [$ h5 H+ O - GPIO_Initure.Mode = GPIO_MODE_IT_RISING;
4 _, j% B8 X. ]0 L/ n& I - GPIO_Initure.Pull = GPIO_NOPULL;
: W' K g8 a% `/ _5 h6 _ - HAL_GPIO_Init(GPIOH, &GPIO_Initure); //初始化
5 r% a; M7 T) U8 j4 m( A; y - delay_ms(60);
) S$ w7 d- g1 @* t1 \
& v7 P; p1 f; I( Y0 C% I6 i- GT9147_RD_Reg(GT_PID_REG, temp, 4); //读取产品ID: n- s+ x' \, R) x- e1 t2 {
- temp[4] = 0;1 V/ l/ [ b3 `7 ^; D9 m2 o5 b
- printf("CTP ID:0x%s\r\n", temp); //打印ID
5 |" g( w g' |3 K( { @
3 E2 h$ z! J& Q6 \ E& _- GT9147_Send_Cfg(1);//更新并保存配置# f* }' n6 {, K/ V8 D( ?, M7 x
& g( G0 C6 A; [- L2 e$ R7 ]- return 1;- {! m9 m' H, |! m* g
- }
复制代码 / X, N; w1 L8 a( a
3. 读取坐标流程
+ f4 \5 g p/ f3 a/ Y W3 c# l
; ]+ j m/ l3 b) d) S6 p' c6 S使用中断方式读取坐标,需要注意的是,如果不及时读取坐标信息会一直产生中断。GT9147的中断脚与STM32的LINE7中断线相连,中断回调函数如下所示。当按下触摸屏时,touch_x与touch_y分别保存触摸时的xy坐标;当松开触摸屏时,touch_x,touch_y赋值0xffff
) D; M6 j# J# k: b* X
+ W1 R" |) C. I- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)8 [+ m5 g; z1 v# [* v. [
- {$ e: R* l3 Z% U& S9 P- |9 ]
- uint8_t buf[4];' A: v+ A* q% [: N) P1 Q) g8 s
- uint8_t i = 0, mode = 0, temp = 0;
- Z8 ]$ M2 t& ^0 i9 P - uint16_t x[5], y[5];
' i. o3 [0 F: O( \+ U+ r - if(GPIO_Pin == GPIO_PIN_7) { //读取坐标, 否则会一直有INT脉冲
7 [3 i F5 S# W) U - GT9147_RD_Reg(GT_GSTID_REG, &mode, 1); //读取触摸点的状态% N+ p. X# l2 T- S
- if(mode & 0X80 && ((mode & 0XF) < 6)) //有坐标可读取
9 |4 W8 o% f" C$ t! c0 P# ? - {
7 J0 ]3 f9 Z* E+ v5 M- h - temp = 0;$ j# \+ W1 f1 Z) A2 P
- GT9147_WR_Reg(GT_GSTID_REG, &temp, 1);//清标志3 h7 Q7 J$ y/ Q! @) L' Y2 l
- }% C& k0 J _% ^& t0 P
- if( (mode & 0xF) && ((mode & 0xF) < 6)) //判断触摸点个数/ q! Q+ q2 ^0 S+ Y& z; ^$ w
- {
# P+ M8 k- G, I - for(i = 0; i < (mode & 0xF); i++)
8 T2 \# r# W1 p& x - {
2 h& E- t4 x; X) z( l/ { - GT9147_RD_Reg(GT9147_TPX_TBL<i>, buf, 4); //读取XY坐标值
! g3 |) Y4 V" n9 W- E" w( X4 F* S - </i>x = (((uint16_t)buf[1] << 8) + buf[0]);
; S& n; t. @. S - y = (((uint16_t)buf[3] << 8) + buf[2]);
' Q; t+ L! Y* M2 W$ |$ K9 t - }& H* A) K! a2 k0 M5 i+ H$ p
- touch_x = x[0];
: C" q- W$ i4 T/ g - touch_y = y[0];
5 M& v" N# ?: l9 c. m- w3 X: J - }% g( G: l( m+ K% A m
- 9 x; ~* \% a* \
- if((mode&0x8F)==0x80)//无触摸点按下,xy赋值为0xffff
4 r; p* Y r# ~ - {- r, {- d5 V* k7 `
- touch_x = 0xffff;6 c$ e. s1 w3 `5 K% l- e2 N- P
- touch_y = 0xffff;+ d+ _( T' Q6 \( v5 B8 `
- }
& Y9 k6 p' |1 Y0 ~+ Z - }
4 q0 z x$ P- u! I. q8 W - }
复制代码 4.主机 对 GT9147 进行读操作时序" b8 r! u& Z) Q
7 [* X8 }$ M% o* _4 `$ i# D) c$ F/ ^- Q% G: G, Y/ V
( Q* t2 e) d% P. V4 `0 ?$ j根据该时序图编写读寄存器函数如下:
# F6 B% @0 k; v$ X7 ]( {
' O+ H- }' z' w b' B- /***************************************************************************************
' n% k" ~7 C7 t1 }, t - * @brief 从GT9147读出一次数据
" z6 v" n& }9 J2 x4 e5 Q0 | - * @input reg:起始寄存器地址0 _) Q. G9 o3 D0 P$ X7 Y3 M
- buf:数据缓缓存区
! i; M8 d6 p" P* K( G4 U - len:读数据长度 / d- h, d, Q; K0 r1 ]2 h* {
- * @return
5 \% ~$ K; d* I7 Z# g - ***************************************************************************************/
# f% L4 _; ?& ^9 D( Z - void GT9147_RD_Reg(uint16_t reg,uint8_t *buf,uint8_t len)% m! e9 L0 A$ J) w! P
- {
' s3 M& E) c7 K9 S6 ?1 Y - uint8_t i; 2 G0 y, }( r2 ?/ n
- CT_IIC_Start();
$ x: m. S* H, W6 t, m. F; P - CT_IIC_Send_Byte(GT_CMD_WR); //发送写命令 / D- v4 T# |( ]& c) o9 D* i/ A* @. V
- CT_IIC_Wait_Ack();
x% E) z' p$ {& m - CT_IIC_Send_Byte(reg>>8); //发送高8位地址: E- k# Y/ h Q) V3 `9 u
- CT_IIC_Wait_Ack(); . ]4 c/ k* j [2 q& j; x
- CT_IIC_Send_Byte(reg&0XFF); //发送低8位地址
( y9 Y) i3 |5 A - CT_IIC_Wait_Ack();
7 \8 I9 ]" \0 r - CT_IIC_Start(); - \) @$ J2 B5 u% I) e; r
- CT_IIC_Send_Byte(GT_CMD_RD); //发送读命令 t, W" z S* i9 P& b: @3 x/ G
- CT_IIC_Wait_Ack(); : l: e( F* c2 v3 R2 e* ?) q
- for(i=0;i<len;i++)
4 v3 g' W1 {% X6 i/ X% g4 J; ^9 f8 b, J - {
9 u5 P3 q" S8 `. Z0 o8 Z. ~ - buf<span style="font-style: italic;"><span style="font-style: normal;">=CT_IIC_Read_Byte(i==(len-1)?0:1); //发数据 ' u3 E. `$ g! w; F2 Y5 f# t, A* Y
- }9 {# l4 A- `( c3 Q. F
- CT_IIC_Stop();//产生一个停止条件
2 P, X4 F- G% R+ `! e2 x - }</span></span>
复制代码 . ]$ m0 U% c9 ?2 d" d+ T
5.主机对 GT9147 进行写操作时序7 q* e8 e0 ^, N* K$ i9 K; r
" b, z) \4 _1 j7 |
: n, J) l4 ]) o0 q3 b
9 Z) ]; |7 }3 M# C$ \9 m% E通过该时序图,编写写寄存器函数如下 {& \- A4 @/ ^- M6 r$ p
7 i$ c- G- N+ o5 q' |) A: g) ]- /***************************************************************************************, |1 r( M3 O* X
- * @brief 向GT9147写入一次数据" I4 p. X; o; \! U: O/ c. L4 v
- * @input reg:起始寄存器地址;
% p0 Y& r0 l. D4 L1 [ - buf:数据缓缓存区
3 i' M4 N+ _; c" B( L - len:写数据长度- u- h6 R; [& k3 H$ i6 ^; Y
- * @return 0,成功; 1,失败.
! @8 i5 O' ^% D$ }% B - ***************************************************************************************/
1 q0 K$ `3 `$ G- r - uint8_t GT9147_WR_Reg(uint16_t reg,uint8_t *buf,uint8_t len)
* C7 ]6 M' T# g: U3 U5 F - {# k5 l) v. U" y4 i5 F
- uint8_t i;
- p2 P3 {$ K% v- W9 f# m - uint8_t ret=0;* Y8 Z3 \6 M8 o# |
- CT_IIC_Start(); : z" [9 I( V: T* L' ^
- CT_IIC_Send_Byte(GT_CMD_WR); //发送写命令 ; l. L+ f0 e2 V6 Y, ?
- CT_IIC_Wait_Ack();8 K3 I" |+ ]- V" ^
- CT_IIC_Send_Byte(reg>>8); //发送高8位地址
/ Q+ o( u9 V& L - CT_IIC_Wait_Ack();
: L N5 V* H/ Y4 k; M# \! I; p+ v - CT_IIC_Send_Byte(reg&0XFF); //发送低8位地址- k8 j" K/ I' e: c
- CT_IIC_Wait_Ack(); 2 L2 w; M- F$ v3 [8 c
- for(i=0;i<len;i++)) [5 o: q6 H: o! Z
- {
0 N8 s4 B* q9 z. C - CT_IIC_Send_Byte(buf<span style="font-style: italic;"><span style="font-style: normal;">); //发数据1 w, D' _* [2 H1 }
- ret = CT_IIC_Wait_Ack();
" G9 I( n& F/ N/ w6 { G - if(ret)break;
" Q/ g& Q1 Q) X% p o - }
+ }: Q0 m5 o0 I. e6 ` - CT_IIC_Stop(); //产生一个停止条件
8 Y) t6 F3 Y0 }2 z, {! n - return ret;
; Q# C3 D, c- _+ O - }</span></span>
复制代码
6 M# K. P3 f% e8 G! E6. GT9147配置函数如下,GT9147_CFG_TBL针对分辨率480×272的触摸屏。
) V* F- _4 {* q
& d$ L( M& E$ q) L配置寄存器时是要注意以下几点:2 z% m- C! X- A7 e9 k w+ u D
$ b4 g; Z5 z0 M( o( \新的版本号大于等于GT9147内部flash原有版本号,才会更新配置.) U) n% @: y8 @8 l1 m# Y, | C
写完GT9147_CFG_TBL中的配置后,还需要往0x80FF寄存器中写入校验,0x8100寄存器中写1。
+ Z4 S8 l0 B5 {2 Q关于配置更详细的信息可以参考GT9147编程参考手册
9 I4 J) ?& @/ I6 M- const uint8_t GT9147_CFG_TBL[]=
5 f, q. x2 n( Z4 w& Q: L s7 d - {$ |0 |& k' d2 V0 V
- 0x60,0xe0,0x01,0x10,0x01,0x05,0x0C,0x00,0x01,0x08,
3 ]5 I2 [4 ~: J, t* h' K5 n% Y - 0x28,0x05,0x50,0x32,0x03,0x05,0x00,0x00,0xff,0xff,4 g* J1 v. g! g- A# Q) D, d
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89,0x28,0x0a,& N$ g( D; J4 y; G* w1 k
- 0x17,0x15,0x31,0x0d,0x00,0x00,0x02,0x9b,0x03,0x25,. o' ]6 W* c. e' I
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x00,
3 w: g. A0 O: P' y - 0x00,0x0f,0x94,0x94,0xc5,0x02,0x07,0x00,0x00,0x04,
2 K+ v; G" j$ @$ o. T. | - 0x8d,0x13,0x00,0x5c,0x1e,0x00,0x3c,0x30,0x00,0x29,
; @$ s5 ^ @6 P5 V0 }; r9 q - 0x4c,0x00,0x1e,0x78,0x00,0x1e,0x00,0x00,0x00,0x00,
. e' `# _# l! _, v0 I7 n. T8 f% c9 t - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
9 \5 ?7 H6 b6 b' s2 O) J; J: f+ \ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,4 E. k+ ]/ N4 l+ v4 F: D7 u, B
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,- ^ C! x% k, _ w
- 0x00,0x00,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,7 m. ]6 B. z" Y1 ~/ L
- 0x18,0x1a,0x00,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,
' A- e# i( W: e7 t- a - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
. K' ^ A7 |7 L% H, S - 0xff,0xff,0x00,0x02,0x04,0x05,0x06,0x08,0x0a,0x0c,
! \0 C) i3 o' i+ P, u. ~ - 0x0e,0x1d,0x1e,0x1f,0x20,0x22,0x24,0x28,0x29,0xff,
/ p" ~) W( w9 z" V - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,9 |1 ]% g W& b4 k7 A& S- F
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
8 U* x* H4 V0 S9 X$ H6 L* Z - 0xff,0xff,0xff,0xff,% }+ O& f. q" b0 y" j/ O. l
- };
+ d; y& q; g1 z( T6 f - ' H3 B5 `2 z! W" p2 l
- uint8_t GT9147_Send_Cfg(uint8_t mode), n' ~- H6 X; ~2 I; h) f8 W
- {
& }! h" g) d( k9 \2 N5 E* ? - uint8_t buf[2];
9 {; x% P2 v* s4 O: g4 b6 l" n - uint8_t i=0;
; `4 |; E3 {3 x6 W1 g - buf[0]=0;
* T/ a* d0 }, z2 l; n - buf[1]=mode; //是否写入到GT9147 FLASH? 即是否掉电保存
( p; l i6 G) e, t) M - for(i=0;i<sizeof(GT9147_CFG_TBL);i++)
- L5 d) d! R; N% k - buf[0]+=GT9147_CFG_TBL<span style="font-style: italic;"><span style="font-style: normal;">;//计算校验和
& i: F- L- ~7 X7 Q" Z: s - buf[0]=(~buf[0])+1;0 t- O" U3 @3 v) h* ~
- GT9147_WR_Reg(GT_CFGS_REG,(uint8_t*)GT9147_CFG_TBL,sizeof(GT9147_CFG_TBL));//发送寄存器配置) t. Z; c: ^4 B3 Y7 f1 N
- GT9147_WR_Reg(GT_CHECK_REG,buf,2);//写入校验和,和配置更新标记- w6 O6 D4 o" N6 z$ E$ v! \# @- o/ F
- return 0;8 a+ z" \8 X t. A$ u/ D
- }</span></span>
复制代码
+ b- D6 C1 \* s6 d7 V四 移植触摸屏驱动到STemWin
* ^: D( c8 D9 d这里假设已经成功移植了STemWin到STM32F7工程。' l; e2 a! \: u% P
0 z" i4 D5 G" X' F1 ?
1. 在GUIConf打开STemWin触摸屏驱动宏1 b/ X% t' C7 c3 s. K
& b- J' W% L; K- #define GUI_SUPPORT_TOUCH (1) // Support touchscreen
复制代码 4 W1 y9 q0 S% d8 p; t+ a
2. 新建GUI_X_Touch_Analog.c文件实现以下四个函数,在第三章第3小节我们知道touch_x,touch_y表示当前触摸的xy坐标。整个文件的内容如下所示。8 f4 C5 F+ `4 D$ H
9 ~7 _6 K/ H7 f' ^# @; v
- void GUI_TOUCH_X_ActivateX(void)
8 R) D: T! X- f% P" r - {
0 @) \1 p: ^# ~/ u4 W8 Z5 Y$ d - 4 e8 E8 Y; f* t
- }
: x8 q' c H1 F$ J% Y7 i' _ - ; A! v( M) B+ _# E4 i7 w4 P x3 i
- void GUI_TOUCH_X_ActivateY(void)
/ B( q' O1 t( Q - {, r$ H5 T# U/ }! l
- - e& y' R/ f6 C/ B5 k5 l4 x/ O
- }9 b1 z! |# B f3 e$ l" @9 F
% t& D {6 J6 a! @/ u- /*获取x坐标*/: K& e; I& g4 H+ T$ e6 x+ V, X
- int GUI_TOUCH_X_MeasureX (void)2 b. }$ ]% P/ ^. m6 Q! I1 F
- {
+ r( N$ n) B9 x. Z7 D7 C$ H - return touch_x;2 @. H7 N, _5 L2 \
- }: T3 D+ u* ~& x- N0 r0 }, m3 w
- 9 v& i2 r: v* p. Q
- /*获取y坐标*/+ b4 E e: t+ R# M
- int GUI_TOUCH_X_MeasureY (void)0 N" [1 p% B% b) v# ]
- {4 n0 z! z% n# _- o! j+ y4 u
- return touch_y;7 G: Q5 x/ { D% i3 _
- }
复制代码
! T3 y& p3 M) i% M, y- X9 |7 U3. 使用GUI_TOUCH_Calibrate函数校准x与y值,然后才能调用GUI_TOUCH_Exec()函数处理触摸事件。
- n3 J: s4 V$ m" S; J4 n6 _( V P/ J
- void StartTouchTask(void const * argument)
1 ]; K4 a6 O) j. f! R; | - {( Z+ H8 b N! E9 V, z3 T
- /* USER CODE BEGIN StartTouchTask */. d8 x. K3 ^/ f+ {/ ?
- GUI_CURSOR_Show();//显示鼠标指针% f2 |9 c+ b+ H- P9 `: i+ h
- GUI_TOUCH_Calibrate(GUI_COORD_X,0,LCD_WIDTH,0,LCD_WIDTH); 7 `! F5 b4 Z9 `
- GUI_TOUCH_Calibrate(GUI_COORD_Y,0,LCD_HEIGHT,0,LCD_HEIGHT);
4 V3 n8 z# M1 s, q. Q, Z3 \ - /* Infinite loop */
1 q+ U1 N7 A! \8 |& P% D - for(;;)4 a' x. W# @5 ~0 {$ v B
- {
; o: X& M0 {4 Y8 u- n3 X- D - GUI_TOUCH_Exec();4 e' @0 T$ M; d" c- D* G) `
- osDelay(5);
. O, H1 S7 ^9 `8 j1 b" b% _ - }) U3 x Q5 \6 e6 `, ?/ j7 A
- /* USER CODE END StartTouchTask */
7 R4 q$ c# n" G6 T: G - }
复制代码
) \: I* |( X2 e# w3 @. i1 q a. x! d
2 ~2 Y, U1 B7 ]1 ^9 I' N) K' `5 F* m5 g0 W, W
|