第3版emWin教程第5章 emWin上手之电阻触摸和电容触摸

Posted 安富莱电子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第3版emWin教程第5章 emWin上手之电阻触摸和电容触摸相关的知识,希望对你有一定的参考价值。

教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

第5章   emWin上手之电阻触摸和电容触摸

本章教程为大家讲解LTDC应用之LCD电阻触摸芯片STMPE811的4点和2点触摸校准和电容触摸芯片FT5X06、GT911和GT811的使用。

5.1 初学者重要提示

5.2 电阻触摸和电容触摸相关知识

5.3 电阻屏硬件设计

5.4 电容屏硬件设计

5.5 电阻触摸驱动设计

5.6 电容触摸驱动设计

5.7 不同触摸IC的识别

5.8 LCD触摸移植和使用

5.9 实验例程设计框架

5.10 实验例程说明

5.12 总结

 

 

5.1   初学者重要提示

  1.   本章是为emWin的触摸部分做准备。
  2.   电阻触摸支持2点和4点校准,而电容屏无需校准。
  3.   电阻触摸校准解决的是触摸板的线性度问题,而飞点要另外处理,当前程序已经做了支持。总的来说,V7配套的电阻触摸方案已经比较成熟,可以放心用于项目。
  4.   屏蔽MDK AC6使用中文GBK编码的警告方法,让大家可以继续使用GBK编码汉字:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98670

5.2   电阻触摸和电容触摸相关知识

这部分知识点在本教程第4章的2.2小节有详细说明,必看。

5.3   电阻屏硬件设计

电阻触摸STMPE811的原理图如下:

 

通过STMPE811的原理图要了解以下几点:

  •   I2C的两根通信线I2C_SCL和I2C_SDA的上拉电阻在V7的主板上。
  •   原理图右侧的GPIO-0到GPIO-7可以作为扩展IO使用,支持输入和输出。其中GPIO-4到GPIO-7用于电阻触摸校准(使用那个IO是可以配置的)。
  •   对于X-,X+,Y-和Y+,只要不是X和Y进行组合,其它组合方式可以随意接,配套的触摸校准算法都可以正常识别。

5.4   电容屏硬件设计

电容触摸主要有三种:FT5X06,GT911和GT811,其中GT811已经停产。下面是FT5X06和GT911触摸板效果(触摸板和触摸芯片是一体的):

 

触摸芯片已经集成到柔性PCB上,且已经校准好。用户使用的话,直接通过I2C方式读取数据即可。下面是电容触摸板引出的引脚:

 

注意I2C_SDK和I2C_SCL的上拉电阻在V7主板上。

5.5   电阻触摸驱动设计

下面将电阻触摸程序设计中的相关问题逐一为大家做个说明。

5.5.1  STMPE811的驱动实现

电阻触摸要比电容触摸麻烦很多,因为电阻触摸要做校准,还要做滤波,否则采集回来的触摸值会抖动或者出现飞点,出现这种情况的主要原因是电阻触摸板的线性度不够好。开发板电阻屏使用的触摸芯片是STMPE811,这个芯片其实就是12位分辨率的ADC,用来采集电阻触摸板的X轴ADC值和Y轴ADC值,然后按照一定的线性关系将ADC值转换为实际的坐标值。其中这个线性关系是通过触摸校准建立起来的,每次采集的X轴和Y轴ADC就可以代入这个线性关系,从而获得实际的坐标值。

总的来说,STMPE811的驱动不难实现,可以结合STMPE811的数据手册:http://www.armbbs.cn/forum.php?mod=viewthread&tid=23306 研究开发板提供的驱动配置。配置好后仅需要提供读取的X轴,Y轴的ADC值以及触摸按下状态(判断STMPE811的中断输出引脚就可以了,如果有触摸,这个引脚输出低电平,反之,输出高电平。通过判断这个引脚就可以选择是否读取X轴,Y轴的ADC值,避免不必要的操作)。这些函数在bsp_ts_stmpe811.c文件实现。而触摸值滤波,触摸扫描和触摸校准是在bsp_touch.c文件里面实现。

下面是清除触摸中断标志函数和X轴,Y轴的ADC值读取函数,这些函数被bsp_touch.c文件所调用,而函数TOUCH_PenInt是在bsp_touch.c文件,这里也贴出来。

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: TOUCH_PenInt
4.    *    功能说明: 判断触摸按下
5.    *    形    参: 无
6.    *    返 回 值: 0表示无触笔按下,1表示有触笔按下
7.    ******************************************************************************************************
8.    */
9.    uint8_t TOUCH_PenInt(void)
10.    {
11.        if ((TP_INT_GPIO_PORT->IDR & TP_INT_PIN) == 0)
12.        {
13.            return 1;
14.        }
15.        return 0;
16.    }
17.    
18.    /*
19.    ******************************************************************************************************
20.    *    函 数 名: STMPE811_ClearInt
21.    *    功能说明: 清楚触笔中断
22.    *    形    参: 无
23.    *    返 回 值: 无
24.    ******************************************************************************************************
25.    */
26.    void STMPE811_ClearInt(void)
27.    {
28.        STMPE811_WriteReg1(REG811_INT_STA, 0xFF); 
29.    }
30.    
31.    /*
32.    ******************************************************************************************************
33.    *    函 数 名: STMPE811_ReadX
34.    *    功能说明: 读取X坐标adc
35.    *    形    参: 无
36.    *    返 回 值: X坐标值adc
37.    ******************************************************************************************************
38.    */
39.    uint16_t STMPE811_ReadX(void)
40.    {
41.        /* 按照 XY 读取模式,连续读取3字节数据,然后分解出X,Y     
42.         |  byte0   |     byte1      |   byte2  |  
43.         | X[11:4], | X[3:0],Y[11:8] | Y[7:0]   |
44.        */
45.        uint8_t buf[3];
46.        
47.    #if 0
48.        STMPE811_ReadBytes(buf, REG811_TSC_DATA1, 3);
49.        
50.        s_AdcX = ((uint16_t)buf[0] << 4) | (buf[1] >> 4);
51.        s_AdcY = ((uint16_t)(buf[1] & 0xF) << 8) | buf[2];    
52.    #else
53.        if (STMPE811_ReadReg1(REG811_TSC_CTRL) & 0x80)
54.        {    
55.            STMPE811_ReadBytes(buf, REG811_TSC_DATA1, 3);
56.            
57.            s_AdcX = ((uint16_t)buf[0] << 4) | (buf[1] >> 4);
58.            s_AdcY = ((uint16_t)(buf[1] & 0xF) << 8) | buf[2];
59.            
60.            #if 0
61.            /* for debug */
62.            {
63.                static int32_t s_t1 = 0;
64.                int32_t tt;
65.                            
66.                tt = bsp_GetRunTime();
67.                if (tt - s_t1 > 1000)
68.                {
69.                    printf("\\r\\n");
70.                    s_t1 = tt;
71.                }
72.                printf("(%7d) %5d %5d\\r\\n", tt, s_AdcX, s_AdcY);
73.            }
74.            #endif
75.        }
76.        else
77.        {
78.            s_AdcX = 0;
79.            s_AdcY = 0;
80.        }
81.    #endif
82.        
83.        return s_AdcX;
84.    }
85.    
86.    /*
87.    ******************************************************************************************************
88.    *    函 数 名: STMPE811_ReadX
89.    *    功能说明: 读取Y坐标adc
90.    *    形    参: 无
91.    *    返 回 值: Y坐标值adc
92.    ******************************************************************************************************
93.    */
94.    uint16_t STMPE811_ReadY(void)
95.    {
96.        return  s_AdcY;
97.    }

下面将程序设计中的关键地方做个阐释:

  •   第9-16行,通过判断STMPE811的中断输出引脚的高低电平来判断触摸板是否被按下,如果有触摸,这个引脚输出低电平,反之,输出高电平。通过判断这个引脚就可以选择是否读取X轴,Y轴的ADC值,避免不必要的操作。
  •   第26-29行,清除触摸中断标志,检测到触摸屏未被按下时,要做清除。
  •   第39-84行,读取X轴ADC数值。
  •   第94-97行,读取Y轴ADC数值。

5.5.2  电阻触摸扫描函数TOUCH_Scan

接下来再来看bsp_touch.c文件中STMPE811触摸扫描函数TOUCH_Scan的实现:

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: TOUCH_Scan
4.    *    功能说明: 触摸板事件检测程序。该函数被周期性调用,每ms调用1次. 见 bsp_Timer.c
5.    *    形    参:  无
6.    *    返 回 值: 无
7.    ******************************************************************************************************
8.    */
9.    void TOUCH_Scan(void)
10.    {
11.        uint16_t usAdcX;
12.        uint16_t usAdcY;
13.        static uint16_t s_usXBuf[SAMPLE_COUNT];
14.        static uint16_t s_usYBuf[SAMPLE_COUNT];
15.        static uint8_t s_ucPos = 0;
16.        static uint8_t s_count = 0;
17.        static uint8_t s_down = 0;
18.        static uint16_t s_usSaveAdcX, s_usSaveAdcY; /* 用于触笔抬起事件,保存按下和移动的最后采样值 */
19.        static uint8_t s_ms = 0;
20.    
21.        if (g_GT811.Enable == 1)
22.        {
23.            GT811_Timer1ms();    /* 电容触摸屏程序计数器 */
24.            return;
25.        }
26.    
27.        if (g_GT911.Enable == 1)
28.        {
29.            GT911_Timer1ms();    /* 电容触摸屏程序计数器 */
30.            return;
31.        }    
32.        
33.        if (g_tFT5X06.Enable == 1)
34.        {
35.            FT5X06_Timer1ms();    /* 电容触摸屏程序计数器 */
36.            return;
37.        }
38.        
39.        /* 下面用于电阻触摸 */
40.        
41.        if (g_tTP.Enable == 0)    
42.        {
43.            return;
44.        }
45.        
46.        if (++s_ms >= 2)
47.        {
48.            return;
49.        }
50.        
51.        /* 2ms进入一次 */
52.        s_ms = 0;
53.        
54.        /* 触笔中断发生 */
55.        if (TOUCH_PenInt())
56.        {
57.            /* 获得原始的ADC值,未滤波 */
58.            usAdcX = STMPE811_ReadX();
59.            usAdcY = STMPE811_ReadY();
60.    
61.            if (TOUCH_PressValid(usAdcX, usAdcY))
62.            {
63.                /* 按压30ms之后才开始采集数据 */
64.                if (s_count >= DOWN_VALID / 2)
65.                {
66.                    s_usXBuf[s_ucPos] = usAdcX;
67.                    s_usYBuf[s_ucPos] = usAdcY;
68.    
69.                    /* 采集20ms数据进行滤波 */
70.                    if (++s_ucPos >= SAMPLE_COUNT / 2)
71.                    {
72.                        s_ucPos = 0;
73.    
74.                        /* 对ADC采样值进行软件滤波 */
75.                        g_tTP.usAdcNowX = TOUCH_DataFilter(s_usXBuf, SAMPLE_COUNT / 2);
76.                        g_tTP.usAdcNowY = TOUCH_DataFilter(s_usYBuf, SAMPLE_COUNT / 2);
77.    
78.                        if (s_down == 0)
79.                        {
80.                            s_down = 1;
81.                            /* 触摸按下事件 */
82.                            TOUCH_PutKey(TOUCH_DOWN, g_tTP.usAdcNowX, g_tTP.usAdcNowY);
83.                            
84.                            s_usSaveAdcX = g_tTP.usAdcNowX;
85.                            s_usSaveAdcY = g_tTP.usAdcNowY;
86.                        }
87.                        else
88.                        {
89.                    if (TOUCH_MoveValid(s_usSaveAdcX, s_usSaveAdcY, g_tTP.usAdcNowX, g_tTP.usAdcNowY))
90.                            {
91.                                /* 触摸移动事件 */
92.                                TOUCH_PutKey(TOUCH_MOVE, g_tTP.usAdcNowX, g_tTP.usAdcNowY);
93.                                
94.                                s_usSaveAdcX = g_tTP.usAdcNowX;
95.                                s_usSaveAdcY = g_tTP.usAdcNowY;
96.                            }
97.                            else
98.                            {
99.                                g_tTP.usAdcNowX = 0; /* for debug stop */
100.                            }
101.                        }
102.                    }
103.                }
104.                else
105.                {
106.                    s_count++;
107.                }
108.            }
109.            else
110.            {
111.                if (s_count > 0)
112.                {
113.                    if (--s_count == 0)
114.                    {
115.                        /* 触摸释放事件 */
116.                        //TOUCH_PutKey(TOUCH_RELEASE, g_tTP.usAdcNowX, g_tTP.usAdcNowY);
117.                        TOUCH_PutKey(TOUCH_RELEASE, s_usSaveAdcX, s_usSaveAdcY);
118.    
119.                        g_tTP.usAdcNowX = 0;
120.                        g_tTP.usAdcNowY = 0;
121.    
122.                        s_count = 0;
123.                        s_down = 0;
124.                        
125.                        STMPE811_ClearInt();        /* 清触笔中断标志 */
126.                    }
127.                }
128.                s_ucPos = 0;
129.            }
130.        }
131.    }

下面将程序设计中的关键地方做个阐释:

  •   第9行,此函数要每1ms被调用一次。
  •   第21-37行,用于GT811,GT911和FT5X06的程序计数器。
  •   第46-52行,设置每2ms进行一次STMPE811检测。
  •   第55行,这个就是本章前面小节说的利用STMPE811的中断输出引脚的高低电平来判断触摸板是否被按下。
  •   第58-59行,读取X轴ADC数值和Y轴ADC数值。
  •   第61行,通过函数TOUCH_PressValid检测刚刚读取的X轴,Y轴数值是否在有效的范围内。

函数TOUCH_PressValid的具体实现如下,其中全局变量g_tTP.usMaxAdc = 4095,因为电阻触摸芯片STMPE811是12位ADC,最大触摸值就是2^12 – 1 = 4095。

/* 有效ADC值的判断门限. 太接近ADC临界值的坐标认为无效 */
#define ADC_VALID_OFFSET    2

/*
*********************************************************************************************************
*    函 数 名: TOUCH_PressValid
*    功能说明: 判断按压是否有效,根据X, Y的ADC值进行大致判断
*    形    参:  无
*    返 回 值: 1 表示有效; 0 表示无效
*********************************************************************************************************
*/
static uint8_t    TOUCH_PressValid(uint16_t _usX, uint16_t _usY)
{
    if ((_usX <= ADC_VALID_OFFSET) || (_usY <= ADC_VALID_OFFSET)
        || (_usX >= g_tTP.usMaxAdc - ADC_VALID_OFFSET)
        || (_usY >= g_tTP.usMaxAdc - ADC_VALID_OFFSET))
    {
        return 0;
    }
    else
    {
        return 1;
    }
}
  •   第64行,DOWN_VALID的宏定义是

#define DOWN_VALID             30

由于是每2ms进行一次检测,这里就表示延迟30ms后进行触摸数据采集。延迟30ms是为了消除触摸抖动。

  •  第70行,SAMPLE_COUNT 的宏定义是

#define SAMPLE_COUNT 20  

由于是每2ms进行一次检测,这里就表示采集够10组数据,即20ms后进行下一步操作。

  •   第75-76行,对X轴和Y轴的ADC数值都进行软件滤波。软件滤波函数TOUCH_DataFilter的实现方法是对10组数值由小到大进行排序,对第3个,第4个和第5个数值求和,然后求平均,将平均值作为最终的ADC数值。
  •   第78-86行,变量标识s_down = 0表示触摸之前是未按下状态,在此条件里面设置s_down = 1表示触摸已经按下,并通过函数TOUCH_TransX(这个函数比较关键,是通过触摸校准函数得到的一个线性关系)将当前的X轴和Y轴ADC数值转换成实际的坐标值,然后调用函数TOUCH_PutKey将当前的坐标信息存储到FIFO里面。
  •   第89-100行设置变量标识s_down = 1后会进入此条件里面,在这个条件里面通过函数TOUCH_MoveValid判断当前是否是有效的移动,如果是,就继续调用函数TOUCH_PutKey将当前的坐标信息存储到FIFO里面,如果不是,就设置全局变量g_tTP.usAdcNowX = 0。
  •   第111-128行,如果通过STMPE811的中断输出引脚检测到触摸未按下,然后判断变量s_count是否大于0,如果大于0的话,做减减运算,算是做了一个松手延迟,防止抖动。减到0的时候,将触摸未按下或者说触摸释放消息通过函数TOUCH_PutKey存储到FIFO里面。

5.5.3  电阻屏触摸校准原理(2点)

由于不同电阻触摸板的线性度参差不齐,不能直接采用比例关系将电阻触摸芯片STMPE811的返回

值转换成实际的坐标。比如我们操作的显示屏分辨率是800*480,电阻触摸芯片采用STMPE811(12位ADC,触摸值范围0-4095),获得当前的触摸值是(1024, 2048),按照比例关系转换成坐标值就是(1024*800/4096,2048*800/4096),即(200,400)。采用这种方法效果不好,容易出现点击不准确的问题。

鉴于此原因,需要通过触摸校准在ADC数值和显示屏分辨率之间建立一个新的线性关系,简单的说就是由比例关系y = ax升级为y = ax + b。如果有了新的触摸ADC数值,代入这个线性关系里面就可以得到当前实际的坐标值,触摸校准的作用就在这里了。

具体实现原理图如下:

在左上角和右下角分别设置两个坐标点(LcdX0,  LcdY0)和(LcdX1,  LcdY1),然后让用户去点击,会得到两组ADC数值(AdcX0,AdcY0)和(AdcX1,  AdcY1)。

 

根据这四个坐标点,可以建立两组方程,一个X轴的,一个Y轴。

  •   将数值(AdcX0, LcdX0)和(AdcX1,  LcdX1)代入方程y = ax + b得到X轴方程 :y = (x - AdcX0)*(LcdX1 - LcdX0)/(AdcX1 - AdcX0) + LcdX0。
  •   将数值(AdcY0, LcdY0)和(AdcY1,  LcdY1)代入方程y = ax + b得到Y轴方程:y = (x - AdcY0)*(LcdY1 - LcdY0)/(AdcY1 - AdcX0) + LcdY0。

 

后面采集到的ADC数值直接代入上面公式就可以得到校准后的物理坐标值(实际的分辨率坐标)。

5.5.4  电阻屏触摸校准原理(4点)

4点触摸校准实现,略复杂,实现原理如下(如果理解起来麻烦的话,会用就行,一般情况下2点校准就行):

在LCD的左上角,右上角,左下角和右下角分别标坐标点(LcdX1,  LcdY1),(LcdX4, LcdY4),(LcdX3,  LcdY3)和(LcdX2, LcdY2)。然后让用户去点击,会得到四组ADC数值(AdcX1, AdcY1),(AdcX4,  AdcY4),(AdcX3, AdcY3)和(AdcX2, AdcY2)。

 

计算X轴:

  • 将数值(AdcX1,AdcY1)和(AdcX2, AdcY2)代入方程y = ax + b得到一组方程y = (x - AdcX1)*(AdcY2- AdcY1)/(AdcX2- AdcX1) + AdcY1
  • 这里将AdcX2用AdcX3替换,那么坐标方程就变为y = (x - AdcX1)*(AdcY2- AdcY1)/(AdcX3- AdcX1) + AdcY1。
  • 同理,将AdcX1用AdcX4替换,那么坐标方程就变为y = (x - AdcX4)*(AdcY2- AdcY1)/(AdcX3- AdcX4) + AdcY1。那么将采集的X值代入上面两个方程会得到两个数值,假设数值是x1和x2。
  • 再将(x1,  LcdX1))和(x2,  LcdX2)代入方程y = ax + b得到一组方程y = (x - x1)*(LcdX2- LcdX1)/(x2- x1) + LcdX1。

将采集的X轴ADC数值再次代入这个方程就得到了最终的物理坐标(实际的分辨率坐标)。

 

计算Y轴:

  • 将数值(AdcX1, AdcY1)和(AdcX2,  AdcY2)代入方程y = ax + b得到一组方程y = (x - AdcX1)*(AdcY2- AdcY1)/(AdcX2- AdcX1) + AdcY1
  • 这里将AdcY2用AdcY4替换,那么坐标方程就变为y = (x - AdcX1)*(AdcY4- AdcY1)/(AdcX2- AdcX1) + AdcY1
  • 同理,将AdcX1用AdcX3替换,那么坐标方程就变为y = (x - AdcX3)*(AdcY2- AdcY1)/(AdcX2- AdcX3) + AdcY1     那么将采集的X值代入上面两个方程会得到两个数值,假设数值是x1和x2。
  • 再将(x1, LcdY1))和(x2,  LcdY2)代入方程y = ax + b得到一组方程y = (x - x1)*(LcdY2- LcdY1)/(x2- x1) + LcdY1。

将采集的Y轴ADC数值再次代入这个方程就得到了最终的物理坐标(实际的分辨率坐标)。

5.5.5  电阻屏触摸校准的实现

对2点和4点触摸校准原理有所了解后,再看代码部分就比较好理解了:

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: TOUCH_Calibration
4.    *    功能说明: 触摸屏校准
5.    *    形    参: _PointCount : 校准点数,2 或 4.
6.    *    返 回 值: 无
7.    ******************************************************************************************************
8.    */
9.    void TOUCH_Calibration(uint8_t _PointCount)
10.    {
11.        uint16_t usAdcX;
12.        uint16_t usAdcY;
13.        uint8_t usCount;
14.        uint8_t I;
15.        uint32_t n;
16.    
17.        /* 校准点数,2点或4点 */
18.        if (_PointCount == 4)
19.        {
20.            g_tTPParam.CalibPointCount = 4;
21.        }
22.        else
23.        {
24.            g_tTPParam.CalibPointCount = 2;
25.        }    
26.        
27.        TOUCH_CelarFIFO();        /* 清除无效的触摸事件 */
28.    
29.        for (I = 0; I < g_tTPParam.CalibPointCount; i++)
30.        {
31.            TOUCH_DispPoint(i);        /* 显示校准点 */
32.    
33.            TOUCH_WaitRelease();     /* 等待触笔释放 */
34.    
35.            usCount = 0;
36.            for (n = 0; n < 500; n++)
37.            {
38.                usAdcX = TOUCH_ReadAdcX();
39.                usAdcY = TOUCH_ReadAdcY();
40.    
41.                if (TOUCH_PressValid(usAdcX, usAdcY))
42.                {
43.                    if (++usCount > 5)
44.                    {
45.                        /* 按压有效, 保存校准点ADC采样值 */
46.                        if (I == 0)
47.                        {
48.                            g_tTPParam.usAdcX1 = usAdcX;
49.                            g_tTPParam.usAdcY1 = usAdcY;
50.                        }
51.                        else if (I == 1)
52.                        {
53.                            g_tTPParam.usAdcX2 = usAdcX;
54.                            g_tTPParam.usAdcY2 = usAdcY;
55.                        }
56.                        else if (I == 2)
57.                        {
58.                            g_tTPParam.usAdcX3 = usAdcX;
59.                            g_tTPParam.usAdcY3 = usAdcY;
60.                        }
61.                        else
62.                        {
63.                            g_tTPParam.usAdcX4 = usAdcX;
64.                            g_tTPParam.usAdcY4 = usAdcY;
65.                        }
66.                        break;
67.                    }
68.                }
69.                else
70.                {
71.                    usCount = 0;
72.                }
73.                bsp_DelayMS(10);
74.            }
75.            if (n == 500)
76.            {
77.                return;
78.            }
79.        }
80.    
81.        TOUCH_WaitRelease();     /* 等待触笔释放 */
82.    
83.        /* 识别触摸的 X, Y 和 显示面板的 X,Y 是否需要交换 */
84.        g_tTPParam.XYChange = 0;        /* 1表示X Y需要交换 */
85.        if (LCD_GetHeight() < LCD_GetWidth())
86.        {
87.            if (TOUCH_Abs(g_tTPParam.usAdcX1 – g_tTPParam.usAdcX2) < 
88.                 TOUCH_Abs(g_tTPParam.usAdcY1 – g_tTPParam.usAdcY2))
89.            {
90.                g_tTPParam.XYChange = 1;
91.            }
92.        }
93.        else
94.        {
95.            if (TOUCH_Abs(g_tTPParam.usAdcX1 – g_tTPParam.usAdcX2) > 
96.                  TOUCH_Abs(g_tTPParam.usAdcY1 – g_tTPParam.usAdcY2))
97.            {
98.                g_tTPParam.XYChange = 1;
99.            }
100.        }
101.    
102.        g_tTPParam.usLcdX1 = TP_X1;
103.        g_tTPParam.usLcdY1 = TP_Y1;
104.        g_tTPParam.usLcdX2 = TP_X2;
105.        g_tTPParam.usLcdY2 = TP_Y2;
106.        g_tTPParam.usLcdX3 = TP_X3;
107.        g_tTPParam.usLcdY3 = TP_Y3;
108.        g_tTPParam.usLcdX4 = TP_X4;
109.        g_tTPParam.usLcdY4 = TP_Y4;
110.    
111.        /* 在最后一步,将校准参数保存入Flash 或者EEPROM */
112.        TOUCH_SaveParam();
113.    }

下面将程序设置中的关键地方做个阐释: