$ X=\frac{V_{Y+}}{V_{ref}}\times{Width} $
$ Y=\frac{V_{X+}}{V_{ref}}\times{Height} $
my_XPT2046.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#ifndef __MY_XPT2046_H
#define __MY_XPT2046_H
#include "stm32f10x.h"
/******************************* XPT2046 触摸屏触摸信号指示引脚定义(不使用中断) ***************************/
#define XPT2046_PENIRQ_GPIO_CLK RCC_APB2Periph_GPIOC
#define XPT2046_PENIRQ_GPIO_PORT GPIOC
#define XPT2046_PENIRQ_GPIO_PIN GPIO_Pin_12
//触屏信号有效电平
#define XPT2046_PENIRQ_ActiveLevel 0
#define XPT2046_PENIRQ_Read() GPIO_ReadInputDataBit ( XPT2046_PENIRQ_GPIO_PORT, XPT2046_PENIRQ_GPIO_PIN )
/******************************* XPT2046 触摸屏模拟SPI引脚定义 ***************************/
#define XPT2046_SPI_GPIO_CLK RCC_APB2Periph_GPIOC
#define XPT2046_SPI_CS_PIN GPIO_Pin_9
#define XPT2046_SPI_CS_PORT GPIOC
#define XPT2046_SPI_CLK_PIN GPIO_Pin_8
#define XPT2046_SPI_CLK_PORT GPIOC
#define XPT2046_SPI_MOSI_PIN GPIO_Pin_10
#define XPT2046_SPI_MOSI_PORT GPIOC
#define XPT2046_SPI_MISO_PIN GPIO_Pin_11
#define XPT2046_SPI_MISO_PORT GPIOC
#define XPT2046_CS_ENABLE() GPIO_SetBits ( XPT2046_SPI_CS_PORT, XPT2046_SPI_CS_PIN )
#define XPT2046_CS_DISABLE() GPIO_ResetBits ( XPT2046_SPI_CS_PORT, XPT2046_SPI_CS_PIN )
#define XPT2046_CLK_HIGH() GPIO_SetBits ( XPT2046_SPI_CLK_PORT, XPT2046_SPI_CLK_PIN )
#define XPT2046_CLK_LOW() GPIO_ResetBits ( XPT2046_SPI_CLK_PORT, XPT2046_SPI_CLK_PIN )
#define XPT2046_MOSI_1() GPIO_SetBits ( XPT2046_SPI_MOSI_PORT, XPT2046_SPI_MOSI_PIN )
#define XPT2046_MOSI_0() GPIO_ResetBits ( XPT2046_SPI_MOSI_PORT, XPT2046_SPI_MOSI_PIN )
#define XPT2046_MISO() GPIO_ReadInputDataBit ( XPT2046_SPI_MISO_PORT, XPT2046_SPI_MISO_PIN )
/******************************* XPT2046 触摸屏参数定义 ***************************/
//校准触摸屏时触摸坐标的AD值相差门限
#define XPT2046_THRESHOLD_CalDiff 2
#define XPT2046_CHANNEL_X 0x90 //通道Y+的选择控制字
#define XPT2046_CHANNEL_Y 0xD0 //通道X+的选择控制字
//触摸参数写到FLASH里的标志
#define FLASH_TOUCH_PARA_FLAG_VALUE 0xA5
//触摸标志写到FLASH里的地址
#define FLASH_TOUCH_PARA_FLAG_ADDR (1*1024)
//触摸参数写到FLASH里的地址
#define FLASH_TOUCH_PARA_ADDR (2*1024)
/******************************* 声明 XPT2046 相关的数据类型 ***************************/
typedef struct //液晶坐标结构体
{
/*负数值表示无新数据*/
int16_t x; //记录最新的触摸参数值
int16_t y;
/*用于记录连续触摸时(长按)的上一次触摸位置*/
int16_t pre_x;
int16_t pre_y;
} strType_XPT2046_Coordinate;
typedef struct //校准因子结构体
{
float An, //注:sizeof(long double) = 8
Bn,
Cn,
Dn,
En,
Fn,
Divider;
} strType_XPT2046_Calibration;
typedef struct //校准系数结构体(最终使用)
{
float dX_X,
dX_Y,
dX,
dY_X,
dY_Y,
dY;
} strType_XPT2046_TouchPara;
/******触摸状态机相关******/
typedef enum
{
XPT2046_STATE_RELEASE = 0, //触摸释放
XPT2046_STATE_WAITING, //触摸按下
XPT2046_STATE_PRESSED, //触摸按下
}enumTouchState ;
#define TOUCH_PRESSED 1
#define TOUCH_NOT_PRESSED 0
//触摸消抖阈值
#define DURIATION_TIME 2
/******************************* 声明 XPT2046 相关的外部全局变量 ***************************/
extern volatile uint8_t ucXPT2046_TouchFlag;
extern strType_XPT2046_TouchPara strXPT2046_TouchPara[];
/******************************** XPT2046 触摸屏函数声明 **********************************/
void XPT2046_Init( void );
uint8_t XPT2046_Touch_Calibrate( uint8_t LCD_Mode );
uint8_t XPT2046_Get_TouchedPoint( strType_XPT2046_Coordinate * displayPtr, strType_XPT2046_TouchPara * para );
void XPT2046_TouchDown(strType_XPT2046_Coordinate * touch);
void XPT2046_TouchUp(strType_XPT2046_Coordinate * touch);
void XPT2046_TouchEvenHandler(void );
void Calibrate_or_Get_TouchParaWithFlash(uint8_t LCD_Mode,uint8_t forceCal);
#endif
my_XPT2046.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
#include "my_XPT2046.h"
#include "my_ILI9341.h"
#include "my_W25Qx.h"
#include <string.h>
#include <stdio.h>
#include "palette.h"
/******************************* 声明 XPT2046 相关的静态函数 ***************************/
static void XPT2046_DelayUS ( __IO uint32_t ulCount );
static void XPT2046_WriteCMD ( uint8_t ucCmd );
static uint16_t XPT2046_ReadCMD ( void );
static uint16_t XPT2046_ReadAdc ( uint8_t ucChannel );
static void XPT2046_ReadAdc_XY ( int16_t * sX_Ad, int16_t * sY_Ad );
static uint8_t XPT2046_ReadAdc_Smooth_XY ( strType_XPT2046_Coordinate * pScreenCoordinate );
static uint8_t XPT2046_Calculate_CalibrationFactor ( strType_XPT2046_Coordinate * pDisplayCoordinate, strType_XPT2046_Coordinate * pScreenSample, strType_XPT2046_Calibration * pCalibrationFactor );
static void ILI9341_DrawCross ( uint16_t usX, uint16_t usY );
/******************************* 定义 XPT2046 全局变量 ***************************/
//默认触摸参数,不同的屏幕稍有差异,可重新调用触摸校准函数获取
strType_XPT2046_TouchPara strXPT2046_TouchPara[] = {
-0.006464, -0.073259, 280.358032, 0.074878, 0.002052, -6.545977,//扫描方式0
0.086314, 0.001891, -12.836658, -0.003722, -0.065799, 254.715714,//扫描方式1
0.002782, 0.061522, -11.595689, 0.083393, 0.005159, -15.650089,//扫描方式2
0.089743, -0.000289, -20.612209, -0.001374, 0.064451, -16.054003,//扫描方式3
0.000767, -0.068258, 250.891769, -0.085559, -0.000195, 334.747650,//扫描方式4
-0.084744, 0.000047, 323.163147, -0.002109, -0.066371, 260.985809,//扫描方式5
-0.001848, 0.066984, -12.807136, -0.084858, -0.000805, 333.395386,//扫描方式6
-0.085470, -0.000876, 334.023163, -0.003390, 0.064725, -6.211169,//扫描方式7
};
volatile uint8_t ucXPT2046_TouchFlag = 0;
/**
* @brief XPT2046 初始化函数
* @param 无
* @retval 无
*/
void XPT2046_Init ( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 开启GPIO时钟 */
RCC_APB2PeriphClockCmd ( XPT2046_SPI_GPIO_CLK|XPT2046_PENIRQ_GPIO_CLK, ENABLE );
/* 模拟SPI GPIO初始化 */
GPIO_InitStructure.GPIO_Pin=XPT2046_SPI_CLK_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz ;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(XPT2046_SPI_CLK_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = XPT2046_SPI_MOSI_PIN;
GPIO_Init(XPT2046_SPI_MOSI_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = XPT2046_SPI_MISO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(XPT2046_SPI_MISO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = XPT2046_SPI_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(XPT2046_SPI_CS_PORT, &GPIO_InitStructure);
/* 拉低片选,选择XPT2046 */
XPT2046_CS_DISABLE();
//触摸屏触摸信号指示引脚,不使用中断
GPIO_InitStructure.GPIO_Pin = XPT2046_PENIRQ_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(XPT2046_PENIRQ_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief 用于 XPT2046 的简单微秒级延时函数
* @param nCount :延时计数值,单位为微妙
* @retval 无
*/
static void XPT2046_DelayUS ( __IO uint32_t ulCount )
{
uint32_t i;
for ( i = 0; i < ulCount; i ++ )
{
uint8_t uc = 12; //设置值为12,大约延1微秒
while ( uc -- ); //延1微秒
}
}
/**
* @brief XPT2046 的写入命令
* @param ucCmd :命令
* 该参数为以下值之一:
* @arg 0x90 :通道Y+的选择控制字
* @arg 0xd0 :通道X+的选择控制字
* @retval 无
*/
static void XPT2046_WriteCMD ( uint8_t ucCmd )
{
uint8_t i;
XPT2046_MOSI_0();
XPT2046_CLK_LOW();
for ( i = 0; i < 8; i ++ )
{
( ( ucCmd >> ( 7 - i ) ) & 0x01 ) ? XPT2046_MOSI_1() : XPT2046_MOSI_0();
XPT2046_DelayUS ( 5 );
XPT2046_CLK_HIGH();
XPT2046_DelayUS ( 5 );
XPT2046_CLK_LOW();
}
}
/**
* @brief XPT2046 的读取命令
* @param 无
* @retval 读取到的数据
*/
static uint16_t XPT2046_ReadCMD ( void )
{
uint8_t i;
uint16_t usBuf=0, usTemp;
XPT2046_MOSI_0();
XPT2046_CLK_HIGH();
for ( i=0; i<12; i++ )
{
XPT2046_CLK_LOW();
usTemp = XPT2046_MISO();
usBuf |= usTemp << ( 11 - i );
XPT2046_CLK_HIGH();
}
return usBuf;
}
/**
* @brief 对 XPT2046 选择一个模拟通道后,启动ADC,并返回ADC采样结果
* @param ucChannel
* 该参数为以下值之一:
* @arg 0x90 :通道Y+的选择控制字
* @arg 0xd0 :通道X+的选择控制字
* @retval 该通道的ADC采样结果
*/
static uint16_t XPT2046_ReadAdc ( uint8_t ucChannel )
{
XPT2046_WriteCMD ( ucChannel );
return XPT2046_ReadCMD ();
}
/**
* @brief 读取 XPT2046 的X通道和Y通道的AD值(12 bit,最大是4096)
* @param sX_Ad :存放X通道AD值的地址
* @param sY_Ad :存放Y通道AD值的地址
* @retval 无
*/
static void XPT2046_ReadAdc_XY ( int16_t * sX_Ad, int16_t * sY_Ad )
{
int16_t sX_Ad_Temp, sY_Ad_Temp;
sX_Ad_Temp = XPT2046_ReadAdc ( XPT2046_CHANNEL_X );
XPT2046_DelayUS ( 1 );
sY_Ad_Temp = XPT2046_ReadAdc ( XPT2046_CHANNEL_Y );
* sX_Ad = sX_Ad_Temp;
* sY_Ad = sY_Ad_Temp;
}
/**
* @brief 在触摸 XPT2046 屏幕时获取一组坐标的AD值,并对该坐标进行滤波
* @param 无
* @retval 滤波之后的坐标AD值
*/
static uint8_t XPT2046_ReadAdc_Smooth_XY ( strType_XPT2046_Coordinate * pScreenCoordinate )
{
uint8_t ucCount = 0, i;
int16_t sAD_X, sAD_Y;
int16_t sBufferArray [ 2 ] [ 10 ] = { { 0 },{ 0 } }; //坐标X和Y进行多次采样
//存储采样中的最小值、最大值
int32_t lX_Min, lX_Max, lY_Min, lY_Max;
/* 循环采样10次 */
do
{
XPT2046_ReadAdc_XY ( & sAD_X, & sAD_Y );
sBufferArray [ 0 ] [ ucCount ] = sAD_X;
sBufferArray [ 1 ] [ ucCount ] = sAD_Y;
ucCount ++;
} while ( ( XPT2046_PENIRQ_Read() == XPT2046_PENIRQ_ActiveLevel ) && ( ucCount < 10 ) );//用户点击触摸屏时即TP_INT_IN信号为低 并且 ucCount<10
/*如果触笔弹起*/
if ( XPT2046_PENIRQ_Read() != XPT2046_PENIRQ_ActiveLevel )
ucXPT2046_TouchFlag = 0; //中断标志复位
/*如果成功采样10个样本*/
if ( ucCount ==10 )
{
lX_Max = lX_Min = sBufferArray [ 0 ] [ 0 ];
lY_Max = lY_Min = sBufferArray [ 1 ] [ 0 ];
for ( i = 1; i < 10; i ++ )
{
if ( sBufferArray[ 0 ] [ i ] < lX_Min )
lX_Min = sBufferArray [ 0 ] [ i ];
else if ( sBufferArray [ 0 ] [ i ] > lX_Max )
lX_Max = sBufferArray [ 0 ] [ i ];
}
for ( i = 1; i < 10; i ++ )
{
if ( sBufferArray [ 1 ] [ i ] < lY_Min )
lY_Min = sBufferArray [ 1 ] [ i ];
else if ( sBufferArray [ 1 ] [ i ] > lY_Max )
lY_Max = sBufferArray [ 1 ] [ i ];
}
/*去除最小值和最大值之后求平均值*/
pScreenCoordinate ->x = ( sBufferArray [ 0 ] [ 0 ] + sBufferArray [ 0 ] [ 1 ] + sBufferArray [ 0 ] [ 2 ] + sBufferArray [ 0 ] [ 3 ] + sBufferArray [ 0 ] [ 4 ] +
sBufferArray [ 0 ] [ 5 ] + sBufferArray [ 0 ] [ 6 ] + sBufferArray [ 0 ] [ 7 ] + sBufferArray [ 0 ] [ 8 ] + sBufferArray [ 0 ] [ 9 ] - lX_Min-lX_Max ) >> 3;
pScreenCoordinate ->y = ( sBufferArray [ 1 ] [ 0 ] + sBufferArray [ 1 ] [ 1 ] + sBufferArray [ 1 ] [ 2 ] + sBufferArray [ 1 ] [ 3 ] + sBufferArray [ 1 ] [ 4 ] +
sBufferArray [ 1 ] [ 5 ] + sBufferArray [ 1 ] [ 6 ] + sBufferArray [ 1 ] [ 7 ] + sBufferArray [ 1 ] [ 8 ] + sBufferArray [ 1 ] [ 9 ] - lY_Min-lY_Max ) >> 3;
return 1;
}
return 0;
}
/**
* @brief 计算 XPT2046 触摸坐标校正系数(注意:只有在LCD和触摸屏间的误差角度非常小时,才能运用下面公式)
* @param pDisplayCoordinate :屏幕人为显示的已知坐标
* @param pstrScreenSample :对已知坐标点触摸时 XPT2046 产生的坐标
* @param pCalibrationFactor :根据人为设定坐标和采样回来的坐标计算出来的屏幕触摸校正系数
* @retval 计算状态
* 该返回值为以下值之一:
* @arg 1 :计算成功
* @arg 0 :计算失败
*/
static uint8_t XPT2046_Calculate_CalibrationFactor ( strType_XPT2046_Coordinate * pDisplayCoordinate, strType_XPT2046_Coordinate * pScreenSample, strType_XPT2046_Calibration * pCalibrationFactor )
{
uint8_t ucRet = 1;
/* K= ( X0-X2 ) ( Y1-Y2 )- ( X1-X2 ) ( Y0-Y2 ) */
pCalibrationFactor -> Divider = ( ( pScreenSample [ 0 ] .x - pScreenSample [ 2 ] .x ) * ( pScreenSample [ 1 ] .y - pScreenSample [ 2 ] .y ) ) -
( ( pScreenSample [ 1 ] .x - pScreenSample [ 2 ] .x ) * ( pScreenSample [ 0 ] .y - pScreenSample [ 2 ] .y ) ) ;
if ( pCalibrationFactor -> Divider == 0 )
ucRet = 0;
else
{
/* A= ( ( XD0-XD2 ) ( Y1-Y2 )- ( XD1-XD2 ) ( Y0-Y2 ) )/K */
pCalibrationFactor -> An = ( ( pDisplayCoordinate [ 0 ] .x - pDisplayCoordinate [ 2 ] .x ) * ( pScreenSample [ 1 ] .y - pScreenSample [ 2 ] .y ) ) -
( ( pDisplayCoordinate [ 1 ] .x - pDisplayCoordinate [ 2 ] .x ) * ( pScreenSample [ 0 ] .y - pScreenSample [ 2 ] .y ) );
/* B= ( ( X0-X2 ) ( XD1-XD2 )- ( XD0-XD2 ) ( X1-X2 ) )/K */
pCalibrationFactor -> Bn = ( ( pScreenSample [ 0 ] .x - pScreenSample [ 2 ] .x ) * ( pDisplayCoordinate [ 1 ] .x - pDisplayCoordinate [ 2 ] .x ) ) -
( ( pDisplayCoordinate [ 0 ] .x - pDisplayCoordinate [ 2 ] .x ) * ( pScreenSample [ 1 ] .x - pScreenSample [ 2 ] .x ) );
/* C= ( Y0 ( X2XD1-X1XD2 )+Y1 ( X0XD2-X2XD0 )+Y2 ( X1XD0-X0XD1 ) )/K */
pCalibrationFactor -> Cn = ( pScreenSample [ 2 ] .x * pDisplayCoordinate [ 1 ] .x - pScreenSample [ 1 ] .x * pDisplayCoordinate [ 2 ] .x ) * pScreenSample [ 0 ] .y +
( pScreenSample [ 0 ] .x * pDisplayCoordinate [ 2 ] .x - pScreenSample [ 2 ] .x * pDisplayCoordinate [ 0 ] .x ) * pScreenSample [ 1 ] .y +
( pScreenSample [ 1 ] .x * pDisplayCoordinate [ 0 ] .x - pScreenSample [ 0 ] .x * pDisplayCoordinate [ 1 ] .x ) * pScreenSample [ 2 ] .y ;
/* D= ( ( YD0-YD2 ) ( Y1-Y2 )- ( YD1-YD2 ) ( Y0-Y2 ) )/K */
pCalibrationFactor -> Dn = ( ( pDisplayCoordinate [ 0 ] .y - pDisplayCoordinate [ 2 ] .y ) * ( pScreenSample [ 1 ] .y - pScreenSample [ 2 ] .y ) ) -
( ( pDisplayCoordinate [ 1 ] .y - pDisplayCoordinate [ 2 ] .y ) * ( pScreenSample [ 0 ] .y - pScreenSample [ 2 ] .y ) ) ;
/* E= ( ( X0-X2 ) ( YD1-YD2 )- ( YD0-YD2 ) ( X1-X2 ) )/K */
pCalibrationFactor -> En = ( ( pScreenSample [ 0 ] .x - pScreenSample [ 2 ] .x ) * ( pDisplayCoordinate [ 1 ] .y - pDisplayCoordinate [ 2 ] .y ) ) -
( ( pDisplayCoordinate [ 0 ] .y - pDisplayCoordinate [ 2 ] .y ) * ( pScreenSample [ 1 ] .x - pScreenSample [ 2 ] .x ) ) ;
/* F= ( Y0 ( X2YD1-X1YD2 )+Y1 ( X0YD2-X2YD0 )+Y2 ( X1YD0-X0YD1 ) )/K */
pCalibrationFactor -> Fn = ( pScreenSample [ 2 ] .x * pDisplayCoordinate [ 1 ] .y - pScreenSample [ 1 ] .x * pDisplayCoordinate [ 2 ] .y ) * pScreenSample [ 0 ] .y +
( pScreenSample [ 0 ] .x * pDisplayCoordinate [ 2 ] .y - pScreenSample [ 2 ] .x * pDisplayCoordinate [ 0 ] .y ) * pScreenSample [ 1 ] .y +
( pScreenSample [ 1 ] .x * pDisplayCoordinate [ 0 ] .y - pScreenSample [ 0 ] .x * pDisplayCoordinate [ 1 ] .y ) * pScreenSample [ 2 ] .y;
}
return ucRet;
}
/**
* @brief 在 ILI9341 上显示校正触摸时需要的十字
* @param usX :在特定扫描方向下十字交叉点的X坐标
* @param usY :在特定扫描方向下十字交叉点的Y坐标
* @retval 无
*/
static void ILI9341_DrawCross ( uint16_t usX, uint16_t usY )
{
ILI9341_DrawLine(usX-10,usY,usX+10,usY);
ILI9341_DrawLine(usX, usY - 10, usX, usY+10);
}
/**
* @brief XPT2046 触摸屏校准
* @param LCD_Mode:指定要校正哪种液晶扫描模式的参数
* @note 本函数调用后会把液晶模式设置为LCD_Mode
* @retval 校准结果
* 该返回值为以下值之一:
* @arg 1 :校准成功
* @arg 0 :校准失败
*/
uint8_t XPT2046_Touch_Calibrate ( uint8_t LCD_Mode )
{
uint8_t i;
char cStr [ 100 ];
uint16_t usTest_x = 0, usTest_y = 0, usGap_x = 0, usGap_y = 0;
char * pStr = 0;
strType_XPT2046_Coordinate strCrossCoordinate[4], strScreenSample[4];
strType_XPT2046_Calibration CalibrationFactor;
LCD_SetFont(&Font8x16);
LCD_SetColors(BLUE,BLACK);
//设置扫描方向,横屏
ILI9341_GramScan ( LCD_Mode );
/* 设定“十”字交叉点的坐标 */
strCrossCoordinate [0].x = LCD_X_LENGTH >> 2;
strCrossCoordinate[0].y = LCD_Y_LENGTH >> 2;
strCrossCoordinate[1].x = strCrossCoordinate[0].x;
strCrossCoordinate[1].y = ( LCD_Y_LENGTH * 3 ) >> 2;
strCrossCoordinate[2].x = ( LCD_X_LENGTH * 3 ) >> 2;
strCrossCoordinate[2].y = strCrossCoordinate[1].y;
strCrossCoordinate[3].x = strCrossCoordinate[2].x;
strCrossCoordinate[3].y = strCrossCoordinate[0].y;
for ( i = 0; i < 4; i ++ )
{
ILI9341_Clear ( 0, 0, LCD_X_LENGTH, LCD_Y_LENGTH );
pStr = "Touch Calibrate ......";
//插入空格,居中显示
sprintf(cStr,"%*c%s",((LCD_X_LENGTH/(((sFONT *)LCD_GetFont())->Width))-strlen(pStr))/2,' ',pStr) ;
ILI9341_DispStringLine_EN (LCD_Y_LENGTH >> 1, cStr );
//插入空格,居中显示
sprintf ( cStr, "%*c%d",((LCD_X_LENGTH/(((sFONT *)LCD_GetFont())->Width)) -1)/2,' ',i + 1 );
ILI9341_DispStringLine_EN (( LCD_Y_LENGTH >> 1 ) - (((sFONT *)LCD_GetFont())->Height), cStr );
XPT2046_DelayUS ( 300000 ); //适当的延时很有必要
ILI9341_DrawCross ( strCrossCoordinate[i] .x, strCrossCoordinate[i].y ); //显示校正用的“十”字
while ( ! XPT2046_ReadAdc_Smooth_XY ( & strScreenSample [i] ) ); //读取XPT2046数据到变量pCoordinate,当ptr为空时表示没有触点被按下
}
XPT2046_Calculate_CalibrationFactor ( strCrossCoordinate, strScreenSample, & CalibrationFactor ) ; //用原始参数计算出 原始参数与坐标的转换系数
if ( CalibrationFactor.Divider == 0 ) goto Failure;
usTest_x = ( ( CalibrationFactor.An * strScreenSample[3].x ) + ( CalibrationFactor.Bn * strScreenSample[3].y ) + CalibrationFactor.Cn ) / CalibrationFactor.Divider; //取一个点计算X值
usTest_y = ( ( CalibrationFactor.Dn * strScreenSample[3].x ) + ( CalibrationFactor.En * strScreenSample[3].y ) + CalibrationFactor.Fn ) / CalibrationFactor.Divider; //取一个点计算Y值
usGap_x = ( usTest_x > strCrossCoordinate[3].x ) ? ( usTest_x - strCrossCoordinate[3].x ) : ( strCrossCoordinate[3].x - usTest_x ); //实际X坐标与计算坐标的绝对差
usGap_y = ( usTest_y > strCrossCoordinate[3].y ) ? ( usTest_y - strCrossCoordinate[3].y ) : ( strCrossCoordinate[3].y - usTest_y ); //实际Y坐标与计算坐标的绝对差
if ( ( usGap_x > 15 ) || ( usGap_y > 15 ) ) goto Failure; //可以通过修改这两个值的大小来调整精度
/* 校准系数为全局变量 */
strXPT2046_TouchPara[LCD_Mode].dX_X = ( CalibrationFactor.An * 1.0 ) / CalibrationFactor.Divider;
strXPT2046_TouchPara[LCD_Mode].dX_Y = ( CalibrationFactor.Bn * 1.0 ) / CalibrationFactor.Divider;
strXPT2046_TouchPara[LCD_Mode].dX = ( CalibrationFactor.Cn * 1.0 ) / CalibrationFactor.Divider;
strXPT2046_TouchPara[LCD_Mode].dY_X = ( CalibrationFactor.Dn * 1.0 ) / CalibrationFactor.Divider;
strXPT2046_TouchPara[LCD_Mode].dY_Y = ( CalibrationFactor.En * 1.0 ) / CalibrationFactor.Divider;
strXPT2046_TouchPara[LCD_Mode].dY = ( CalibrationFactor.Fn * 1.0 ) / CalibrationFactor.Divider;
ILI9341_Clear ( 0, 0, LCD_X_LENGTH, LCD_Y_LENGTH );
LCD_SetTextColor(GREEN);
pStr = "Calibrate Succed";
//插入空格,居中显示
sprintf(cStr,"%*c%s",((LCD_X_LENGTH/(((sFONT *)LCD_GetFont())->Width))-strlen(pStr))/2,' ',pStr) ;
ILI9341_DispStringLine_EN (LCD_Y_LENGTH >> 1, cStr );
XPT2046_DelayUS ( 1000000 );
return 1;
Failure:
ILI9341_Clear ( 0, 0, LCD_X_LENGTH, LCD_Y_LENGTH );
LCD_SetTextColor(RED);
pStr = "Calibrate fail";
//插入空格,居中显示
sprintf(cStr,"%*c%s",((LCD_X_LENGTH/(((sFONT *)LCD_GetFont())->Width))-strlen(pStr))/2,' ',pStr) ;
ILI9341_DispStringLine_EN (LCD_Y_LENGTH >> 1, cStr );
pStr = "try again";
//插入空格,居中显示
sprintf(cStr,"%*c%s",((LCD_X_LENGTH/(((sFONT *)LCD_GetFont())->Width))-strlen(pStr))/2,' ',pStr) ;
ILI9341_DispStringLine_EN ( ( LCD_Y_LENGTH >> 1 ) + (((sFONT *)LCD_GetFont())->Height), cStr );
XPT2046_DelayUS ( 1000000 );
return 0;
}
/**
* @brief 从FLASH中获取 或 重新校正触摸参数(校正后会写入到SPI FLASH中)
* @note 若FLASH中从未写入过触摸参数,
* 会触发校正程序校正LCD_Mode指定模式的触摸参数,此时其它模式写入默认值
*
* 若FLASH中已有触摸参数,且不强制重新校正
* 会直接使用FLASH里的触摸参数值
*
* 每次校正时只会更新指定的LCD_Mode模式的触摸参数,其它模式的不变
* @note 本函数调用后会把液晶模式设置为LCD_Mode
*
* @param LCD_Mode:要校正触摸参数的液晶模式
* @param forceCal:是否强制重新校正参数,可以为以下值:
* @arg 1:强制重新校正
* @arg 0:只有当FLASH中不存在触摸参数标志时才重新校正
* @retval 无
*/
void Calibrate_or_Get_TouchParaWithFlash(uint8_t LCD_Mode,uint8_t forceCal)
{
uint8_t para_flag=0;
//初始化FLASH
SPI_FLASH_Init();
//读取触摸参数标志
W25Q_BufferRead(¶_flag,FLASH_TOUCH_PARA_FLAG_ADDR,1);
//若不存在标志或florceCal=1时,重新校正参数
if(para_flag != FLASH_TOUCH_PARA_FLAG_VALUE | forceCal ==1)
{
//若标志存在,说明原本FLASH内有触摸参数,
//先读回所有LCD模式的参数值,以便稍后强制更新时只更新指定LCD模式的参数,其它模式的不变
if( para_flag == FLASH_TOUCH_PARA_FLAG_VALUE && forceCal == 1)
{
W25Q_BufferRead((uint8_t *)&strXPT2046_TouchPara,FLASH_TOUCH_PARA_ADDR,4*6*8);
}
//等待触摸屏校正完毕,更新指定LCD模式的触摸参数值
while( ! XPT2046_Touch_Calibrate (LCD_Mode) );
//擦除扇区
W25Q_SectorErase(0);
//设置触摸参数标志
para_flag = FLASH_TOUCH_PARA_FLAG_VALUE;
//写入触摸参数标志
W25Q_BufferWrite(¶_flag,FLASH_TOUCH_PARA_FLAG_ADDR,1);
//写入最新的触摸参数
W25Q_BufferWrite((uint8_t *)&strXPT2046_TouchPara,FLASH_TOUCH_PARA_ADDR,4*6*8);
}
else //若标志存在且不强制校正,则直接从FLASH中读取
{
W25Q_BufferRead((uint8_t *)&strXPT2046_TouchPara,FLASH_TOUCH_PARA_ADDR,4*6*8);
}
}
/**
* @brief 获取 XPT2046 触摸点(校准后)的坐标
* @param pDisplayCoordinate :该指针存放获取到的触摸点坐标
* @param pTouchPara:坐标校准系数
* @retval 获取情况
* 该返回值为以下值之一:
* @arg 1 :获取成功
* @arg 0 :获取失败
*/
uint8_t XPT2046_Get_TouchedPoint ( strType_XPT2046_Coordinate * pDisplayCoordinate, strType_XPT2046_TouchPara * pTouchPara )
{
uint8_t ucRet = 1; //若正常,则返回0
strType_XPT2046_Coordinate strScreenCoordinate;
if ( XPT2046_ReadAdc_Smooth_XY ( & strScreenCoordinate ) )
{
pDisplayCoordinate ->x = ( ( pTouchPara[LCD_SCAN_MODE].dX_X * strScreenCoordinate.x ) + ( pTouchPara[LCD_SCAN_MODE].dX_Y * strScreenCoordinate.y ) + pTouchPara[LCD_SCAN_MODE].dX );
pDisplayCoordinate ->y = ( ( pTouchPara[LCD_SCAN_MODE].dY_X * strScreenCoordinate.x ) + ( pTouchPara[LCD_SCAN_MODE].dY_Y * strScreenCoordinate.y ) + pTouchPara[LCD_SCAN_MODE].dY );
}
else ucRet = 0; //如果获取的触点信息有误,则返回0
return ucRet;
}
/**
* @brief 触摸屏检测状态机
* @retval 触摸状态
* 该返回值为以下值之一:
* @arg TOUCH_PRESSED :触摸按下
* @arg TOUCH_NOT_PRESSED :无触摸
*/
uint8_t XPT2046_TouchDetect(void)
{
static enumTouchState touch_state = XPT2046_STATE_RELEASE;
static uint32_t i;
uint8_t detectResult = TOUCH_NOT_PRESSED;
switch(touch_state)
{
case XPT2046_STATE_RELEASE:
if(XPT2046_PENIRQ_Read() == XPT2046_PENIRQ_ActiveLevel) //第一次出现触摸信号
{
touch_state = XPT2046_STATE_WAITING;
detectResult =TOUCH_NOT_PRESSED;
}
else //无触摸
{
touch_state = XPT2046_STATE_RELEASE;
detectResult =TOUCH_NOT_PRESSED;
}
break;
case XPT2046_STATE_WAITING:
if(XPT2046_PENIRQ_Read() == XPT2046_PENIRQ_ActiveLevel)
{
i++;
//等待时间大于阈值则认为触摸被按下
//消抖时间 = DURIATION_TIME * 本函数被调用的时间间隔
//如在定时器中调用,每10ms调用一次,则消抖时间为:DURIATION_TIME*10ms
if(i > DURIATION_TIME)
{
i=0;
touch_state = XPT2046_STATE_PRESSED;
detectResult = TOUCH_PRESSED;
}
else //等待时间累加
{
touch_state = XPT2046_STATE_WAITING;
detectResult = TOUCH_NOT_PRESSED;
}
}
else //等待时间值未达到阈值就为无效电平,当成抖动处理
{
i = 0;
touch_state = XPT2046_STATE_RELEASE;
detectResult = TOUCH_NOT_PRESSED;
}
break;
case XPT2046_STATE_PRESSED:
if(XPT2046_PENIRQ_Read() == XPT2046_PENIRQ_ActiveLevel) //触摸持续按下
{
touch_state = XPT2046_STATE_PRESSED;
detectResult = TOUCH_PRESSED;
}
else //触摸释放
{
touch_state = XPT2046_STATE_RELEASE;
detectResult = TOUCH_NOT_PRESSED;
}
break;
default:
touch_state = XPT2046_STATE_RELEASE;
detectResult = TOUCH_NOT_PRESSED;
break;
}
return detectResult;
}
/**
* @brief 触摸屏被按下的时候会调用本函数
* @param touch包含触摸坐标的结构体
* @note 请在本函数中编写自己的触摸按下处理应用
* @retval 无
*/
void XPT2046_TouchDown(strType_XPT2046_Coordinate * touch)
{
//若为负值表示之前已处理过
if(touch->pre_x == -1 && touch->pre_x == -1)
return;
/***在此处编写自己的触摸按下处理应用***/
/*处理触摸画板的选择按钮*/
Touch_Button_Down(touch->x,touch->y);
/*处理描绘轨迹*/
Draw_Trail(touch->pre_x,touch->pre_y,touch->x,touch->y,&brush);
/***在上面编写自己的触摸按下处理应用***/
}
/**
* @brief 触摸屏释放的时候会调用本函数
* @param touch包含触摸坐标的结构体
* @note 请在本函数中编写自己的触摸释放处理应用
* @retval 无
*/
void XPT2046_TouchUp(strType_XPT2046_Coordinate * touch)
{
//若为负值表示之前已处理过
if(touch->pre_x == -1 && touch->pre_x == -1)
return;
/***在此处编写自己的触摸释放处理应用***/
/*处理触摸画板的选择按钮*/
Touch_Button_Up(touch->pre_x,touch->pre_y);
/***在上面编写自己的触摸释放处理应用***/
}
/**
* @brief 检测到触摸中断时调用的处理函数,通过它调用tp_down 和tp_up汇报触摸点
* @note 本函数需要在while循环里被调用,也可使用定时器定时调用
* 例如,可以每隔5ms调用一次,消抖阈值宏DURIATION_TIME可设置为2,这样每秒最多可以检测100个点。
* 可在XPT2046_TouchDown及XPT2046_TouchUp函数中编写自己的触摸应用
* @param none
* @retval none
*/
void XPT2046_TouchEvenHandler(void )
{
static strType_XPT2046_Coordinate cinfo= {-1,-1,-1,-1};
if(XPT2046_TouchDetect() == TOUCH_PRESSED)
{
//获取触摸坐标
XPT2046_Get_TouchedPoint(&cinfo,strXPT2046_TouchPara);
//调用触摸被按下时的处理函数,可在该函数编写自己的触摸按下处理过程
XPT2046_TouchDown(&cinfo);
/*更新触摸信息到pre xy*/
cinfo.pre_x = cinfo.x;
cinfo.pre_y = cinfo.y;
}
else
{
//调用触摸被释放时的处理函数,可在该函数编写自己的触摸释放处理过程
XPT2046_TouchUp(&cinfo);
/*触笔释放,把 xy 重置为负*/
cinfo.x = -1;
cinfo.y = -1;
cinfo.pre_x = -1;
cinfo.pre_y = -1;
}
}
palette.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifndef _PALETTE_H
#define _PALETTE_H
#include "stm32f10x.h"
#define COLOR_BLOCK_WIDTH 40
#define COLOR_BLOCK_HEIGHT 28
#define BUTTON_NUM 16
#define PALETTE_START_Y 0
#define PALETTE_END_Y LCD_Y_LENGTH
#define BUTTON_START_X 0
#define PALETTE_START_X (COLOR_BLOCK_WIDTH*2+1)
#define PALETTE_END_X LCD_X_LENGTH
/*
LCD 颜色代码,CL_是Color的简写
16Bit由高位至低位, RRRR RGGG GGGB BBBB
下面的RGB 宏将24位的RGB值转换为16位格式。
启动windows的画笔程序,点击编辑颜色,选择自定义颜色,可以获得的RGB值。
推荐使用迷你取色器软件获得你看到的界面颜色。
*/
/*RGB565 颜色转换*/
#define RGB(R,G,B) (((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3)) /* 将8位R,G,B转化为 16位RGB565格式 */
#define RGB565_R(x) ((x >> 8) & 0xF8)
#define RGB565_G(x) ((x >> 3) & 0xFC)
#define RGB565_B(x) ((x << 3) & 0xF8)
enum
{
CL_WHITE = RGB(255,255,255), /* 白色 */
CL_BLACK = RGB( 0, 0, 0), /* 黑色 */
CL_RED = RGB(255, 0, 0), /* 红色 */
CL_GREEN = RGB( 0,255, 0), /* 绿色 */
CL_BLUE = RGB( 0, 0,255), /* 蓝色 */
CL_YELLOW = RGB(255,255, 0), /* 黄色 */
CL_GREY = RGB( 98, 98, 98), /* 深灰色 */
CL_GREY1 = RGB( 150, 150, 150), /* 浅灰色 */
CL_GREY2 = RGB( 180, 180, 180), /* 浅灰色 */
CL_GREY3 = RGB( 200, 200, 200), /* 最浅灰色 */
CL_GREY4 = RGB( 230, 230, 230), /* 最浅灰色 */
CL_BUTTON_GREY = RGB( 195, 195, 195), /* WINDOWS 按钮表面灰色 */
CL_MAGENTA = RGB(255, 0, 255), /* 红紫色,洋红色 */
CL_CYAN = RGB( 0, 255, 255), /* 蓝绿色,青色 */
CL_BLUE1 = RGB( 0, 0, 240), /* 深蓝色 */
CL_BLUE2 = RGB( 0, 0, 128), /* 深蓝色 */
CL_BLUE3 = RGB( 68, 68, 255), /* 浅蓝色1 */
CL_BLUE4 = RGB( 0, 64, 128), /* 浅蓝色1 */
/* UI 界面 Windows控件常用色 */
CL_BTN_FACE = RGB(236, 233, 216), /* 按钮表面颜色(灰) */
CL_BOX_BORDER1 = RGB(172, 168,153), /* 分组框主线颜色 */
CL_BOX_BORDER2 = RGB(255, 255,255), /* 分组框阴影线颜色 */
CL_MASK = 0x7FFF /* RGB565颜色掩码,用于文字背景透明 */
};
typedef struct
{
uint16_t start_x; //按键的x起始坐标
uint16_t start_y; //按键的y起始坐标
uint16_t end_x; //按键的x结束坐标
uint16_t end_y; //按键的y结束坐标
uint32_t para; //颜色按钮中表示选择的颜色,笔迹形状按钮中表示选择的画刷
uint8_t touch_flag; //按键按下的标志
void (*draw_btn)(void * btn); //按键描绘函数
void (*btn_command)(void * btn); //按键功能执行函数,例如切换颜色、画刷
} Touch_Button;
/*画刷形状列表*/
typedef enum
{
LINE_SINGLE_PIXCEL = 0, //单像素线
LINE_2_PIXCEL, //2像素线
LINE_4_PIXCEL, //4像素线
LINE_6_PIXCEL, //6像素线
LINE_8_PIXCEL, //8像素线
LINE_16_PIXCEL, //16像素线
LINE_20_PIXCEL, //20像素线
LINE_WITH_CIRCLE, //珠子连线
RUBBER, //橡皮
} SHAPE;
/*画刷参数*/
typedef struct
{
uint32_t color;
SHAPE shape;
} Brush_Style;
/*brush全局变量在其它文件有使用到*/
extern Brush_Style brush;
void Palette_Init(uint8_t LCD_Mode);
void Touch_Button_Init(void);
void Touch_Button_Down(uint16_t x,uint16_t y);
void Touch_Button_Up(uint16_t x,uint16_t y);
void Draw_Trail(int16_t pre_x,int16_t pre_y,int16_t x,int16_t y,Brush_Style* brush);
#endif //_PALETTE_H
palette.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
#include "palette.h"
#include "my_ILI9341.h"
/*按钮结构体数组*/
Touch_Button button[BUTTON_NUM];
/*画笔参数*/
Brush_Style brush;
static void Draw_Color_Button(void *btn);
static void Draw_Clear_Button(void *btn);
static void Draw_Shape_Button(void *btn);
static void Command_Select_Color(void *btn);
static void Command_Select_Brush(void *btn);
static void Command_Clear_Palette(void *btn);
static void LCD_DrawUniLineCircle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint8_t thick );
/**
* @brief Palette_Init 画板初始化
* @param 无
* @retval 无
*/
void Palette_Init(uint8_t LCD_Mode)
{
uint8_t i;
ILI9341_GramScan ( LCD_Mode );
/* 整屏清为白色 */
LCD_SetBackColor(CL_WHITE);
ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);
/* 初始化按钮 */
Touch_Button_Init();
/* 描绘按钮 */
for(i=0; i<BUTTON_NUM; i++)
{
button[i].draw_btn(&button[i]);
}
/* 初始化画笔 */
brush.color = CL_BLACK;
brush.shape = LINE_SINGLE_PIXCEL;
LCD_SetTextColor(brush.color);
}
/**
* @brief Touch_Button_Init 初始化按钮参数
* @param 无
* @retval 无
*/
void Touch_Button_Init(void)
{
/*第一列,主要为颜色按钮*/
button[0].start_x = BUTTON_START_X;
button[0].start_y = 0;
button[0].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[0].end_y = COLOR_BLOCK_HEIGHT;
button[0].para = CL_BLACK;
button[0].touch_flag = 0;
button[0].draw_btn = Draw_Color_Button ;
button[0].btn_command = Command_Select_Color ;
button[1].start_x = BUTTON_START_X;
button[1].start_y = COLOR_BLOCK_HEIGHT;
button[1].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[1].end_y = COLOR_BLOCK_HEIGHT*2;
button[1].para = CL_GREY;
button[1].touch_flag = 0;
button[1].draw_btn = Draw_Color_Button ;
button[1].btn_command = Command_Select_Color ;
button[2].start_x = BUTTON_START_X;
button[2].start_y = COLOR_BLOCK_HEIGHT*2;
button[2].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[2].end_y = COLOR_BLOCK_HEIGHT*3;
button[2].para = CL_BLUE;
button[2].touch_flag = 0;
button[2].draw_btn = Draw_Color_Button ;
button[2].btn_command = Command_Select_Color ;
button[3].start_x = BUTTON_START_X;
button[3].start_y = COLOR_BLOCK_HEIGHT*3;
button[3].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[3].end_y = COLOR_BLOCK_HEIGHT*4;
button[3].para = CL_CYAN;
button[3].touch_flag = 0;
button[3].draw_btn = Draw_Color_Button ;
button[3].btn_command = Command_Select_Color ;
button[4].start_x = BUTTON_START_X;
button[4].start_y = COLOR_BLOCK_HEIGHT*4;
button[4].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[4].end_y = COLOR_BLOCK_HEIGHT*5;
button[4].para = CL_RED;
button[4].touch_flag = 0;
button[4].draw_btn = Draw_Color_Button ;
button[4].btn_command = Command_Select_Color ;
button[5].start_x = BUTTON_START_X;
button[5].start_y = COLOR_BLOCK_HEIGHT*5;
button[5].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[5].end_y = COLOR_BLOCK_HEIGHT*6;
button[5].para = CL_MAGENTA;
button[5].touch_flag = 0;
button[5].draw_btn = Draw_Color_Button ;
button[5].btn_command = Command_Select_Color ;
button[6].start_x = BUTTON_START_X;
button[6].start_y = COLOR_BLOCK_HEIGHT*6;
button[6].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[6].end_y = COLOR_BLOCK_HEIGHT*7;
button[6].para = CL_GREEN;
button[6].touch_flag = 0;
button[6].draw_btn = Draw_Color_Button ;
button[6].btn_command = Command_Select_Color ;
button[7].start_x = BUTTON_START_X;
button[7].start_y = COLOR_BLOCK_HEIGHT*7;
button[7].end_x = BUTTON_START_X+COLOR_BLOCK_WIDTH ;
button[7].end_y = LCD_Y_LENGTH;
button[7].para = CL_BUTTON_GREY;
button[7].touch_flag = 0;
button[7].draw_btn = Draw_Clear_Button ;
button[7].btn_command = Command_Clear_Palette ;
/*第二列,主要为画刷按钮*/
button[8].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[8].start_y = 0;
button[8].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[8].end_y = COLOR_BLOCK_HEIGHT;
button[8].para = LINE_SINGLE_PIXCEL;
button[8].touch_flag = 0;
button[8].draw_btn = Draw_Shape_Button ;
button[8].btn_command = Command_Select_Brush ;
button[9].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[9].start_y = COLOR_BLOCK_HEIGHT;
button[9].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[9].end_y = COLOR_BLOCK_HEIGHT*2;
button[9].para = LINE_2_PIXCEL;
button[9].touch_flag = 0;
button[9].draw_btn = Draw_Shape_Button ;
button[9].btn_command = Command_Select_Brush ;
button[10].start_x =BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[10].start_y = COLOR_BLOCK_HEIGHT*2;
button[10].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[10].end_y = COLOR_BLOCK_HEIGHT*3;
button[10].para = LINE_4_PIXCEL;
button[10].touch_flag = 0;
button[10].draw_btn = Draw_Shape_Button ;
button[10].btn_command = Command_Select_Brush ;
button[11].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[11].start_y = COLOR_BLOCK_HEIGHT*3;
button[11].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[11].end_y = COLOR_BLOCK_HEIGHT*4;
button[11].para = LINE_6_PIXCEL;
button[11].touch_flag = 0;
button[11].draw_btn = Draw_Shape_Button ;
button[11].btn_command = Command_Select_Brush ;
button[12].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[12].start_y = COLOR_BLOCK_HEIGHT*4;
button[12].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[12].end_y = COLOR_BLOCK_HEIGHT*5;
button[12].para = LINE_8_PIXCEL;
button[12].touch_flag = 0;
button[12].draw_btn = Draw_Shape_Button ;
button[12].btn_command = Command_Select_Brush ;
button[13].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[13].start_y = COLOR_BLOCK_HEIGHT*5;
button[13].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[13].end_y = COLOR_BLOCK_HEIGHT*6;
button[13].para = LINE_16_PIXCEL;
button[13].touch_flag = 0;
button[13].draw_btn = Draw_Shape_Button ;
button[13].btn_command = Command_Select_Brush ;
button[14].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[14].start_y = COLOR_BLOCK_HEIGHT*6;
button[14].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[14].end_y = COLOR_BLOCK_HEIGHT*7;
button[14].para = LINE_20_PIXCEL;
button[14].touch_flag = 0;
button[14].draw_btn = Draw_Shape_Button ;
button[14].btn_command = Command_Select_Brush ;
button[15].start_x = BUTTON_START_X + COLOR_BLOCK_WIDTH;
button[15].start_y = COLOR_BLOCK_HEIGHT*7;
button[15].end_x = BUTTON_START_X + COLOR_BLOCK_WIDTH*2 ;
button[15].end_y = LCD_Y_LENGTH;
button[15].para = RUBBER;
button[15].touch_flag = 0;
button[15].draw_btn = Draw_Shape_Button ;
button[15].btn_command = Command_Select_Brush ;
}
/**
* @brief Touch_Button_Down 按键被按下时调用的函数,由触摸屏调用
* @param x 触摸位置的x坐标
* @param y 触摸位置的y坐标
* @retval 无
*/
void Touch_Button_Down(uint16_t x,uint16_t y)
{
uint8_t i;
for(i=0; i<BUTTON_NUM; i++)
{
/* 触摸到了按钮 */
if(x<=button[i].end_x && y<=button[i].end_y && y>=button[i].start_y && x>=button[i].start_x )
{
if(button[i].touch_flag == 0) /*原本的状态为没有按下,则更新状态*/
{
button[i].touch_flag = 1; /* 记录按下标志 */
button[i].draw_btn(&button[i]); /*重绘按钮*/
}
}
else if(button[i].touch_flag == 1) /* 触摸移出了按键的范围且之前有按下按钮 */
{
button[i].touch_flag = 0; /* 清除按下标志,判断为误操作*/
button[i].draw_btn(&button[i]); /*重绘按钮*/
}
}
}
/**
* @brief Touch_Button_Up 按键被释放时调用的函数,由触摸屏调用
* @param x 触摸最后释放时的x坐标
* @param y 触摸最后释放时的y坐标
* @retval 无
*/
void Touch_Button_Up(uint16_t x,uint16_t y)
{
uint8_t i;
for(i=0; i<BUTTON_NUM; i++)
{
/* 触笔在按钮区域释放 */
if((x<button[i].end_x && x>button[i].start_x && y<button[i].end_y && y>button[i].start_y))
{
button[i].touch_flag = 0; /*释放触摸标志*/
button[i].draw_btn(&button[i]); /*重绘按钮*/
button[i].btn_command(&button[i]); /*执行按键的功能命令*/
break;
}
}
}
/**
* @brief Draw_Trail 在画板区域描绘触摸轨迹
* @param pre_x 上一点的x坐标
* @param pre_y 上一点的y坐标
* @param x 最新一点的x坐标
* @param y 最新一点的y坐标
* @param brush 画刷参数
* @retval 无
*/
void Draw_Trail(int16_t pre_x,int16_t pre_y,int16_t x,int16_t y,Brush_Style* brush)
{
/*设置画板区域为活动窗口,bsp_lcd.c驱动还没有这样的函数,用于限制绘画窗口*/
// RA8875_SetActiveWindow(PALETTE_START_X,PALETTE_START_Y,PALETTE_END_X,PALETTE_END_Y);
/*触摸位置在画板区域*/
if(x>PALETTE_START_X && pre_x>PALETTE_START_X )
{
switch(brush->shape) /*根据画刷参数描绘不同的轨迹*/
{
/* 描绘1像素宽度的轨迹线 */
case LINE_SINGLE_PIXCEL:
if(pre_x< 0 || pre_y < 0) //新的笔迹
{
ILI9341_SetPointPixel(x,y);
}
else //继续上一次的笔迹
{
ILI9341_DrawLine(pre_x,pre_y,x,y);
}
break;
case LINE_2_PIXCEL:
if(x-1<PALETTE_START_X||pre_x-1<PALETTE_START_X) //画板左边界
break;
/* 描绘2像素宽度的轨迹线 */
LCD_DrawUniLineCircle(pre_x,pre_y,x,y,1);
break;
case LINE_4_PIXCEL:
if(x-2<PALETTE_START_X||pre_x-2<PALETTE_START_X) //画板左边界
break;
LCD_DrawUniLineCircle(pre_x,pre_y,x,y,2);
break;
case LINE_6_PIXCEL:
if(x-3<PALETTE_START_X||pre_x-3<PALETTE_START_X) //画板左边界
break;
LCD_DrawUniLineCircle(pre_x,pre_y,x,y,3);
break;
case LINE_8_PIXCEL:
if(x-4<PALETTE_START_X||pre_x-4<PALETTE_START_X) //画板左边界
break;
LCD_DrawUniLineCircle(pre_x,pre_y,x,y,4);
break;
case LINE_16_PIXCEL:
if(x-8<PALETTE_START_X||pre_x-8<PALETTE_START_X) //画板左边界
break;
LCD_DrawUniLineCircle(pre_x,pre_y,x,y,8);
break;
case LINE_20_PIXCEL:
if(x-10<PALETTE_START_X ||pre_x-10<PALETTE_START_X) //画板左边界
break;
LCD_DrawUniLineCircle(pre_x,pre_y,x,y,10);
break;
/*描绘带珠子的单像素线*/
case LINE_WITH_CIRCLE:
if(x-3<PALETTE_START_X||pre_x-3<PALETTE_START_X) //画板左边界
break;
if(pre_x< 0 || pre_y< 0)//新的笔迹
{
ILI9341_SetPointPixel(x,y);
}
else //继续上一次的笔迹
{
ILI9341_DrawLine(pre_x,pre_y,x,y);
ILI9341_DrawCircle(x,y,3,1);
}
break;
/*橡皮功能*/
case RUBBER:
if(x-20<PALETTE_START_X || //画板左边界
x+20>LCD_X_LENGTH || x-20<0 || //液晶左右边界
y+20>LCD_Y_LENGTH || y-20<0) //液晶上下边界
break;
// if(x>PALETTE_START_X+20)
{
LCD_SetColors(CL_WHITE,CL_WHITE);
ILI9341_DrawRectangle( x-40/2,y-40/2,40,40,1);
}
break;
}
}
/*退出局限画板的绘图窗口,bsp_lcd.c驱动还没有这样的函数,用于限制绘画窗口*/
// RA8875_SetActiveWindow(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);
}
/**
* @brief Draw_Color_Button 颜色按钮的描绘函数
* @param btn Touch_Button 类型的按键参数
* @retval 无
*/
static void Draw_Color_Button(void *btn)
{
Touch_Button *ptr = (Touch_Button *)btn;
/*释放按键*/
if(ptr->touch_flag == 0)
{
/*背景为功能键相应的颜色*/
LCD_SetColors(ptr->para,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,1);
}
else /*按键按下*/
{
/*白色背景*/
LCD_SetColors(CL_WHITE,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,1);
}
/*按钮边框*/
LCD_SetColors(CL_BLUE4,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,0);
}
/**
* @brief Draw_Clear_Button 清屏按钮的描绘函数
* @param btn Touch_Button 类型的按键参数
* @retval 无
*/
static void Draw_Clear_Button(void *btn)
{
Touch_Button *ptr = (Touch_Button *)btn;
/*释放按键*/
if(ptr->touch_flag == 0)
{
LCD_SetColors(CL_BUTTON_GREY,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,1);
LCD_SetColors(CL_RED,CL_BUTTON_GREY);
/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
*中文字体大小是16*16的,需要其它字体请自行制作字模*/
/*这个函数只对英文字体起作用*/
LCD_SetFont(&Font8x16);
ILI9341_DispString_EN_CH( ptr->start_x + (ptr->end_x - ptr->start_x - 16*2 )/2,
// ptr->start_y+15,
ptr->start_y+ ((ptr->end_y - ptr->start_y-16)/2),
"清屏");
}
else /*按键按下*/
{
LCD_SetColors(CL_WHITE,CL_WHITE);
ILI9341_DrawRectangle(ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,1);
LCD_SetColors(CL_RED,CL_WHITE);
/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
*中文字体大小是16*16的,需要其它字体请自行制作字模*/
/*这个函数只对英文字体起作用*/
LCD_SetFont(&Font8x16);
ILI9341_DispString_EN_CH( ptr->start_x + (ptr->end_x - ptr->start_x - 16*2 )/2,
// ptr->start_y+15,
ptr->start_y+ ((ptr->end_y - ptr->start_y-16)/2),
"清屏");
}
/*按钮边框*/
LCD_SetColors(CL_BLUE4,CL_WHITE);
ILI9341_DrawRectangle(ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,0);
}
/**
* @brief Draw_Shape_Button 笔刷按钮的描绘函数
* @param btn Touch_Button 类型的按键参数
* @retval 无
*/
static void Draw_Shape_Button(void *btn)
{
Touch_Button *ptr = (Touch_Button *)btn;
uint16_t i;
/* 背景颜色 没按下时为灰色,按下时为白色*/
if(ptr->touch_flag ==0 )
{
LCD_SetColors(CL_BUTTON_GREY,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,1);
/*显示文字时的背景颜色*/
LCD_SetColors(CL_BLUE4,CL_BUTTON_GREY);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,0);
}
else
{
LCD_SetColors(CL_WHITE,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,1);
/*显示文字时的背景颜色*/
LCD_SetColors(CL_BLUE4,CL_WHITE);
ILI9341_DrawRectangle( ptr->start_x,
ptr->start_y,
ptr->end_x - ptr->start_x,
ptr->end_y - ptr->start_y,0);
}
LCD_SetColors(CL_BLACK,CL_WHITE);
/*根据画刷形状描绘按钮图案*/
switch(ptr->para)
{
case LINE_SINGLE_PIXCEL:
LCD_SetColors(CL_BLACK,CL_WHITE);
ILI9341_DrawLine(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2);
break;
case LINE_2_PIXCEL:
LCD_DrawUniLineCircle(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
1);
break;
case LINE_4_PIXCEL:
LCD_DrawUniLineCircle(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
2);
break;
case LINE_6_PIXCEL:
LCD_DrawUniLineCircle(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
3);
break;
case LINE_8_PIXCEL:
LCD_DrawUniLineCircle(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
4);
break;
case LINE_16_PIXCEL:
LCD_DrawUniLineCircle(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
8 );
break;
case LINE_20_PIXCEL:
LCD_DrawUniLineCircle(ptr->start_x+20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,ptr->end_x-20,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
10);
break;
case LINE_WITH_CIRCLE:
LCD_SetColors(CL_BLACK,CL_WHITE);
ILI9341_DrawLine(ptr->start_x+5,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
ptr->end_x-5,
ptr->start_y+(ptr->end_y-ptr->start_y)/2);
for(i=0; i<((ptr->end_x - ptr->start_x-10)/10); i++)
{
ILI9341_DrawCircle( ptr->start_x+5+i*10,
ptr->start_y+(ptr->end_y-ptr->start_y)/2,
3,1);
}
break;
case RUBBER:
LCD_SetColors(CL_WHITE,CL_BLACK);
ILI9341_DrawRectangle( ptr->start_x+((ptr->end_x - ptr->start_x -24)/2),
ptr->start_y+ ((ptr->end_y - ptr->start_y-24 -16)/2),
24,
24,1 );
LCD_SetColors(CL_RED,CL_BUTTON_GREY);
/*选择字体,使用中英文显示时,尽量把英文选择成8*16的字体,
*中文字体大小是24*24的,需要其它字体请自行制作字模*/
/*这个函数只对英文字体起作用*/
LCD_SetFont(&Font8x16);
ILI9341_DispString_EN_CH( ptr->start_x+(ptr->end_x - ptr->start_x -16*2)/2,
ptr->start_y+ ((ptr->end_y - ptr->start_y-24 -16)/2)+24,
"橡皮");
break;
}
}
/**
* @brief Command_Select_Color 切换画刷颜色,颜色按键的功能执行函数
* @param btn Touch_Button 类型的按键参数
* @retval 无
*/
static void Command_Select_Color(void *btn)
{
Touch_Button *ptr = (Touch_Button *)btn;
brush.color = ptr->para;
LCD_SetColors(brush.color,CL_WHITE);
if(brush.shape == RUBBER)
{
brush.shape = LINE_SINGLE_PIXCEL;
}
}
/**
* @brief Command_Select_Brush 切换画刷颜色,画刷按键的功能执行函数
* @param btn Touch_Button 类型的按键参数
* @retval 无
*/
static void Command_Select_Brush(void *btn)
{
Touch_Button *ptr = (Touch_Button *)btn;
brush.shape =(SHAPE) ptr->para;
LCD_SetColors(brush.color,CL_WHITE);
}
/**
* @brief Command_Select_Brush 切换画刷颜色,清屏按键的功能执行函数
* @param btn Touch_Button 类型的按键参数
* @retval 无
*/
static void Command_Clear_Palette(void *btn)
{
LCD_SetColors(CL_WHITE,CL_WHITE);
ILI9341_DrawRectangle( PALETTE_START_X,
PALETTE_START_Y,
PALETTE_END_X-(PALETTE_START_X+1),
PALETTE_END_Y-PALETTE_START_Y ,1);
}
#define ABS(X) ((X) > 0 ? (X) : -(X))
/**
* @brief 在两点之间描绘轨迹
* @param x1: specifies the point 1 x position.
* @param y1: specifies the point 1 y position.
* @param x2: specifies the point 2 x position.
* @param y2: specifies the point 2 y position.
* @retval None
*/
static void LCD_DrawUniLineCircle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint8_t thick )
{
int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
curpixel = 0;
deltax = ABS(x2 - x1); /* The difference between the x's */
deltay = ABS(y2 - y1); /* The difference between the y's */
x = x1; /* Start x off at the first pixel */
y = y1; /* Start y off at the first pixel */
if (x2 >= x1) /* The x-values are increasing */
{
xinc1 = 1;
xinc2 = 1;
}
else /* The x-values are decreasing */
{
xinc1 = -1;
xinc2 = -1;
}
if (y2 >= y1) /* The y-values are increasing */
{
yinc1 = 1;
yinc2 = 1;
}
else /* The y-values are decreasing */
{
yinc1 = -1;
yinc2 = -1;
}
if (deltax >= deltay) /* There is at least one x-value for every y-value */
{
xinc1 = 0; /* Don't change the x when numerator >= denominator */
yinc2 = 0; /* Don't change the y for every iteration */
den = deltax;
num = deltax / 2;
numadd = deltay;
numpixels = deltax; /* There are more x-values than y-values */
}
else /* There is at least one y-value for every x-value */
{
xinc2 = 0; /* Don't change the x for every iteration */
yinc1 = 0; /* Don't change the y when numerator >= denominator */
den = deltay;
num = deltay / 2;
numadd = deltax;
numpixels = deltay; /* There are more y-values than x-values */
}
for (curpixel = 0; curpixel <= numpixels; curpixel++)
{
//判断边界
if(x+thick>LCD_X_LENGTH || x-thick<0 || //液晶左右边界
y+thick>LCD_Y_LENGTH || y-thick<0 ) //液晶上下边界
continue;
ILI9341_DrawCircle(x,y,thick,1); /* Draw the current pixel */
num += numadd; /* Increase the numerator by the top of the fraction */
if (num >= den) /* Check if numerator >= denominator */
{
num -= den; /* Calculate the new numerator value */
x += xinc1; /* Change the x as appropriate */
y += yinc1; /* Change the y as appropriate */
}
x += xinc2; /* Change the x as appropriate */
y += yinc2; /* Change the y as appropriate */
}
}
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "my_gpio.h"
#include "my_usart.h"
#include "my_ILI9341.h"
#include "my_XPT2046.h"
#include "palette.h"
/**
* @brief 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @param 无
* @retval 无
*/
static void BSP_Init(void)
{
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/* LED 初始化 */
LED_GPIO_Config();
/* 串口初始化 */
USART_Config();
}
int main(void)
{
BSP_Init();
ILI9341_Init (); //LCD 初始化
//触摸屏初始化
XPT2046_Init();
//从FLASH里获取校正参数,若FLASH无参数,则使用模式3进行校正
Calibrate_or_Get_TouchParaWithFlash(3,0);
ILI9341_GramScan ( 3 );
//绘制触摸画板界面
Palette_Init(LCD_SCAN_MODE);
while(1)
{
//触摸检测函数,本函数至少10ms调用一次
XPT2046_TouchEvenHandler();
}
}