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