最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429
本章教程为大家讲解LTDC应用之LCD电阻触摸芯片STMPE811的4点和2点触摸校准和电容触摸芯片FT5X06、GT911和GT811的使用。
目录
第5章 ThreadX GUIX上手之电阻触摸和电容触摸
5.1 初学者重要提示
5.2 电阻触摸和电容触摸相关知识
5.3 电阻屏硬件设计
5.4 电容屏硬件设计
5.5 电阻触摸驱动设计
5.5.1 STMPE811的驱动实现
5.5.2 电阻触摸扫描函数TOUCH_Scan
5.5.3 电阻屏触摸校准原理(2点)
5.5.4 电阻屏触摸校准原理(4点)
5.5.5 电阻屏触摸校准的实现
5.5.6 电阻屏触摸ADC值转物理坐标
5.5.7 电阻触摸的使用方法
5.6 电容触摸驱动设计
5.6.1 电容屏触摸IC---FT5X06
5.6.2 电容屏触摸IC---GT911
5.6.3 电容触摸的使用方法
5.7 不同触摸IC的识别
5.8 LCD触摸移植和使用
5.9 实验例程设计框架
5.10 实验例程说明
5.11 总结
这部分知识点在第4章的2.2小节有详细说明,必看。
电阻触摸STMPE811的原理图如下:
通过STMPE811的原理图要了解以下几点:
电容触摸主要有三种:FT5X06,GT911和GT811,其中GT811已经停产。下面是FT5X06和GT911触摸板效果(触摸板和触摸芯片是一体的):
触摸芯片已经集成到柔性PCB上,且已经校准好。用户使用的话,直接通过I2C方式读取数据即可。下面是电容触摸板引出的引脚:
注意I2C_SDK和I2C_SCL的上拉电阻在V7主板上。
下面将电阻触摸程序设计中的相关问题逐一为大家做个说明。
电阻触摸要比电容触摸麻烦很多,因为电阻触摸要做校准,还要做滤波,否则采集回来的触摸值会抖动或者出现飞点,出现这种情况的主要原因是电阻触摸板的线性度不够好。开发板电阻屏使用的触摸芯片是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_ts_touch.c文件里面实现。
下面是清除触摸中断标志函数和X轴,Y轴的ADC值读取函数,这些函数被bsp_touch.c文件所调用,而函数TOUCH_PenInt是在bsp_ts_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. }
下面将程序设计中的关键地方做个阐释:
接下来再来看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. }
下面将程序设计中的关键地方做个阐释:
函数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;
}
}
由于是每2ms进行一次检测,这里就表示延迟30ms后进行触摸数据采集。延迟30ms是为了消除触摸抖动。
由于是每2ms进行一次检测,这里就表示采集够10组数据,即20ms后进行下一步操作。
由于不同电阻触摸板的线性度参差不齐,不能直接采用比例关系将电阻触摸芯片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轴。
后面采集到的ADC数值直接代入上面公式就可以得到校准后的物理坐标值(实际的分辨率坐标)。
4点触摸校准实现,略复杂,实现原理如下(如果理解起来麻烦的话,会用就行,一般情况下2点校准就行):
在LCD的左上角,右上角,左下角和右下角分别标坐标点(LcdX1, LcdY1),(LcdX4, LcdY4),(LcdX3, LcdY3)和(LcdX2, LcdY2)。然后让用户去点击,会得到四组ADC数值(AdcX1, AdcY1),(AdcX4, AdcY4),(AdcX3, AdcY3)和(AdcX2, AdcY2)。
计算X轴:
1、将数值(AdcX1,AdcY1)和(AdcX2, AdcY2)代入方程y = ax + b ,得到一组方程 y = (x - AdcX1)*(AdcY2- AdcY1)/(AdcX2- AdcX1) + AdcY1
2、这里将AdcX2用AdcX3替换,那么坐标方程就变为 y = (x - AdcX1)*(AdcY2- AdcY1)/(AdcX3- AdcX1) + AdcY1。
3、同理,将AdcX1用AdcX4替换,那么坐标方程就变为 y = (x - AdcX4)*(AdcY2- AdcY1)/(AdcX3- AdcX4) + AdcY1。那么将采集的X值代入上面两个方程会得到两个数值,假设数值是x1和x2。
4、再将(x1, LcdX1))和(x2, LcdX2)代入方程y = ax + b得到一组方程 y = (x - x1)*(LcdX2- LcdX1)/(x2- x1) + LcdX1。
将采集的X轴ADC数值再次代入这个方程就得到了最终的物理坐标(实际的分辨率坐标)。
计算Y轴:
1、将数值(AdcX1, AdcY1)和(AdcX2, AdcY2)代入方程y = ax + b得到一组方程 y = (x - AdcX1)*(AdcY2- AdcY1)/(AdcX2- AdcX1) + AdcY1
2、这里将AdcY2用AdcY4替换,那么坐标方程就变为 y = (x - AdcX1)*(AdcY4- AdcY1)/(AdcX2- AdcX1) + AdcY1
3、同理,将AdcX1用AdcX3替换,那么坐标方程就变为 y = (x - AdcX3)*(AdcY2- AdcY1)/(AdcX2- AdcX3) + AdcY1那么将采集的X值代入上面两个方程会得到两个数值,假设数值是x1和x2。
4、再将(x1, LcdY1))和(x2, LcdY2)代入方程y = ax + b得到一组方程 y = (x - x1)*(LcdY2- LcdY1)/(x2- x1) + LcdY1。
将采集的Y轴ADC数值再次代入这个方程就得到了最终的物理坐标(实际的分辨率坐标)。
对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. }
下面将程序设置中的关键地方做个阐释:
电阻屏触摸ADC值转物理坐标的公式就是由前面5.3和5.4小节而来。
1. /*
2. ******************************************************************************************************
3. * 函 数 名: CalTwoPoint
4. * 功能说明: 根据2点直线方程,计算Y值
5. * 形 参: 2个点的坐标和x输入量
6. * 返 回 值: x对应的y值
7. ******************************************************************************************************
8. */
9. static int32_t CalTwoPoint(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x)
10. {
11. return y1 + ((int32_t)(y2 - y1) * (x - x1)) / (x2 - x1);
12. }
13.
14. /*
15. ******************************************************************************************************
16. * 函 数 名: TOUCH_TransX
17. * 功能说明: 将触摸ADC值转换为像素坐标
18. * 形 参: 无
19. * 返 回 值: X 坐标值,允许负值
20. ******************************************************************************************************
21. */
22. static int16_t TOUCH_TransX(uint16_t _usAdcX, uint16_t _usAdcY)
23. {
24. if (g_tTPParam.CalibPointCount == 2)
25. {
26. uint16_t x;
27. int32_t y;
28.
29. if (g_tTPParam.XYChange == 0)
30. {
31. x = _usAdcX;
32. if (x == 0)
33. {
34. y = 0;
35. }
36. else
37. {
38. //y = CalTwoPoint(g_tTPParam.usAdcX1, TP_X1, g_tTPParam.usAdcX2, TP_X2, x);
39. y = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usLcdX1, g_tTPParam.usAdcX2,
40. g_tTPParam.usLcdX2, x);
41. }
42. }
43. else
44. {
45. x = _usAdcY;
46. if (x == 0)
47. {
48. y = 0;
49. }
50. else
51. {
52. //y = CalTwoPoint(g_tTPParam.usAdcY1, TP_X1, g_tTPParam.usAdcY2, TP_X2, x);
53. y = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usLcdX1, g_tTPParam.usAdcY2,
54. g_tTPParam.usLcdX2, x);
55. }
56. }
57. return y;
58. }
59. else /* 4点校准 */
60. {
61. uint16_t x, x1, x2;
62. int32_t y;
63.
64. if (g_tTPParam.XYChange == 0) /* X Y 坐标不交换 */
65. {
66. x = _usAdcX;
67.
68. /* 根据 Y ADC 实时计算直线方程的参考点x1, x2
69. if _usAdcY = usAdcY1 then 取点 = (AdcX1, TP_X1, AdcX4, TP_X4, _usAdcY)
70. if _usAdcY = usAdcY2 then 取点 = (AdcX3, TP_X3, AdcX2, TP_X2, _usAdcY)
71.
72. 其中 TP_X1 = TP_X3; TP_X4 = TP_X1 , 这是程序设定的校准位置的像素坐标, 是固定的。
73. 我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
74. */
75. x1 = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usAdcX1, g_tTPParam.usAdcY2,
76. g_tTPParam.usAdcX3, _usAdcY);
77. x2 = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usAdcX4, g_tTPParam.usAdcY2,
78. g_tTPParam.usAdcX2, _usAdcY);
79. }
80. else /* X Y 坐标交换 */
81. {
82. x = _usAdcY;
83.
84. /* 根据 X ADC 实时计算直线方程的参考点x1, x2
85. if _usAdcX = usAdcX1 then 取点 = (AdcY1, TP_X1, AdcY4, TP_X4, _usAdcX)
86. if _usAdcX = usAdcX2 then 取点 = (AdcY3, TP_X3, AdcY2, TP_X2, _usAdcX)
87.
88. 其中 TP_X1 = TP_X3; TP_X4 = TP_X1 , 这是程序设定的校准位置的像素坐标, 是固定的。
89. 我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
90. */
91. x1 = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY1, g_tTPParam.usAdcX2,
92. g_tTPParam.usAdcY3, _usAdcX);
93. x2 = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY4, g_tTPParam.usAdcX2,
94. g_tTPParam.usAdcY2, _usAdcX);
95. }
96.
97. if (x == 0)
98. {
99. y = 0;
100. }
101. else
102. {
103. /* 根据2点直线方程,计算坐标 */
104. //y = CalTwoPoint(x1, TP_X1, x2, TP_X2, x);
105. y = CalTwoPoint(x1, g_tTPParam.usLcdX1, x2, g_tTPParam.usLcdX2, x);
106. }
107. return y;
108. }
109. }
110.
111. /*
112. ******************************************************************************************************
113. * 函 数 名: TOUCH_TransY
114. * 功能说明: 将触摸ADC值转换为像素坐标
115. * 形 参: 无
116. * 返 回 值: Y 坐标值,允许负值
117. ******************************************************************************************************
118. */
119. static int16_t TOUCH_TransY(uint16_t _usAdcX, uint16_t _usAdcY)
120. {
121. if (g_tTPParam.CalibPointCount == 2) /* 2点校准 */
122. {
123. /* 类似函数TOUCH_TransX,省略未贴出 */
124. }
125. else /* 4点校准 */
126. {
127. /* 类似函数TOUCH_TransX,省略未贴出 */
128. }
129. }
下面将程序设计中几个关键地方做个阐释:
这里注意g_tTPParam.XYChange = 1情况的处理,之所以会有这种情况,详情看此贴:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=93300 。
电阻触摸的使用主要分为三步:
/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/* 省略未写 */
bsp_InitI2C(); /* 初始化I2C总线 */
TOUCH_InitHard(); /* 初始化触摸芯片,LCD面板型号的检查也在此函数,所以要在函数LCD_InitHard前调用 */
LCD_InitHard(); /* 初始化LCD */
}
/*
*********************************************************************************************************
* 函 数 名: bsp_RunPer1ms
* 功能说明: 该函数每隔1ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些需要周期性处理
* 的事务可以放在此函数。比如:触摸坐标扫描。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_RunPer1ms(void)
{
TOUCH_Scan(); /* 触摸屏 */
}
TOUCH_DOWN表示按下消息。
TOUCH_MOVE表示触摸移动消息。
TOUCH_RELEASE表示触摸释放消息。
根据这几个消息,用户可以在程序里面判断当前获取的物理坐标值是否在设置的区域内来执行触摸操作。
int16_t tpX, tpY;
uint8_t ucTouch; /* 触摸事件 */
ucTouch = TOUCH_GetKey(&tpX, &tpY); /* 读取触摸事件 */
if (ucTouch != TOUCH_NONE)
{
switch (ucTouch)
{
case TOUCH_DOWN: /* 触笔按下事件 */
/* 在触笔所在位置显示一个小圈 */
if ((tpX > 0) && (tpY > 0))
{
}
break;
case TOUCH_MOVE: /* 触笔移动事件 */
/* 实时刷新触摸ADC采样值和转换后的坐标 */
{
/* 在触笔所在位置显示一个小圈 */
if ((tpX > 0) && (tpY > 0))
{
}
}
break;
case TOUCH_RELEASE: /* 触笔释放事件 */
/* 在触笔所在位置显示一个小圈 */
if ((tpX > 0) && (tpY > 0))
{
}
break;
}
}
电容触摸相比电阻触摸就要简单很多了,因为电容触摸不需要做触摸校准,而且用的是触摸板和触摸芯片一体的,也不需要做寄存器初始化配置,上电后直接读取参数即可。
由于GT811已经停产,这里重点把GT911和FT5X06做个说明。
电容触摸IC是支持多点触摸的,FT5X06支持多达10点触摸同时按下,并提供了I2C和SPI两种
通信接口方式,开发板使用的是I2C通信接口。更多相关知识学习可以在这里下载FT5X06数据手册和应用手册:http://www.armbbs.cn/forum.php?mod=viewthread&tid=16461 。
注意,这个芯片返回的就是实际的坐标值,比如显示屏的分辨率是800*480,那么返回的就是在这个分辨率范围内的实际坐标,然后通过函数TOUCH_PutKey将FT5X06读出的实际坐标值存储到FIFO中即可,具体实现代码如下:
1. /*
2. ******************************************************************************************************
3. * 函 数 名: FT5X06_Scan
4. * 功能说明: 读取触摸数据。读取全部的数据。放在主程序 bsp_Idle()中执行
5. * 形 参: 无
6. * 返 回 值: 无
7. ******************************************************************************************************
8. */
9. void FT5X06_Scan(void)
10. {
11. uint8_t buf[CFG_POINT_READ_BUF];
12. uint8_t i;
13. static uint8_t s_tp_down = 0;
14. uint16_t x, y;
15. static uint16_t x_save, y_save;
16. static uint8_t s_count = 0;
17.
18. if (g_tFT5X06.Enable == 0)
19. {
20. return;
21. }
22.
23. /* 10ms 执行一次 */
24. if (g_tFT5X06.TimerCount < 10)
25. {
26. return;
27. }
28.
29. g_tFT5X06.TimerCount = 0;
30.
31. #if 1 /* 方案1: 检测INT引脚电平. */
32. if (TOUCH_PenInt() == 0)
33. {
34. #else /* 方案2:不用INT引脚,读状态寄存器 */
35. FT5X06_ReadReg(2, buf, 1);
36. if ((buf[0] & 0x07) == 0)
37. {
38. #endif
39. /* 持续按下时,INT电平是脉冲信号。每隔18ms出现1个宽度4ms的高电平。 */
40. if (s_tp_down == 1)
41. {
42. if (++s_count > 2)
43. {
44. s_count = 0;
45. s_tp_down = 0;
46. TOUCH_PutKey(TOUCH_RELEASE, x_save, y_save);
47. }
48. }
49. return;
50. }
51. s_count = 0;
52.
53. /* 有触摸,读取完整的数据 */
54. FT5X06_ReadReg(0, buf, CFG_POINT_READ_BUF);
55.
56. g_tFT5X06.Count = buf[2] & 0x07;
57. if (g_tFT5X06.Count > FT5X06_TOUCH_POINTS)
58. {
59. g_tFT5X06.Count = FT5X06_TOUCH_POINTS;
60. }
61.
62. g_tFT5X06.Count = 0;
63. for (i = 0; i < FT5X06_TOUCH_POINTS; i++)
64. {
65. uint8_t pointid;
66.
67. pointid = (buf[5 + 6*i]) >> 4;
68. if (pointid >= 0x0f)
69. {
70. break;
71. }
72. else
73. {
74. g_tFT5X06.Count++;
75. g_tFT5X06.X[i] = (int16_t)(buf[3 + 6*i] & 0x0F)<<8 | (int16_t)buf[4 + 6*i];
76. g_tFT5X06.Y[i] = (int16_t)(buf[5 + 6*i] & 0x0F)<<8 | (int16_t)buf[6 + 6*i];
77. g_tFT5X06.Event[i] = buf[0x3 + 6*i] >> 6;
78. g_tFT5X06.id[i] = (buf[5 + 6*i])>>4;
79. }
80. }
81.
82. /* 检测按下 */
83. {
84. if (g_tFT5X06.ChipID == 0x55) /* 4.3寸 480 * 272 */
85. {
86. x = g_tFT5X06.Y[0];
87. y = g_tFT5X06.X[0];
88.
89. /* 判断值域 */
90. if (x > 479)
91. {
92. x = 479;
93. }
94.
95. if (y > 271)
96. {
97. y = 271;
98. }
99. }
100. else if (g_tFT5X06.ChipID == 0x0A) /* 5.0寸 800 * 480 */
101. {
102. x = g_tFT5X06.X[0];
103. y = g_tFT5X06.Y[0];
104.
105. /* 判断值域 */
106. if (x > 799)
107. {
108. x = 799;
109. }
110. if (y > 479)
111. {
112. y = 479;
113. }
114. }
115. else /* id == 0x06 表示7寸电容屏(FT芯片) */
116. {
117. x = g_tFT5X06.X[0];
118. y = g_tFT5X06.Y[0];
119.
120. /* 判断值域 */
121. if (x > 799)
122. {
123. x = 799;
124. }
125. if (y > 479)
126. {
127. y = 479;
128. }
129. }
130. }
131.
132. if (s_tp_down == 0)
133. {
134. s_tp_down = 1;
135.
136. TOUCH_PutKey(TOUCH_DOWN, x, y);
137. }
138. else
139. {
140. TOUCH_PutKey(TOUCH_MOVE, x, y);
141. }
142. x_save = x; /* 保存坐标,用于释放事件 */
143. y_save = y;
144.
145. #if 0
146. for (i = 0; i < CFG_POINT_READ_BUF; i++)
147. {
148. printf("%02X ", buf[i]);
149. }
150. printf("\r\n");
151. #endif
152.
153. #if 0 /* 打印5个坐标点数据 */
154. printf("(%5d,%5d,%3d,%3d) ", g_tFT5X06.X[0], g_tFT5X06.Y[0], g_tFT5X06.Event[0],
155. g_tFT5X06.id[0]);
156. printf("(%5d,%5d,%3d,%3d) ", g_tFT5X06.X[1], g_tFT5X06.Y[1], g_tFT5X06.Event[1],
157. g_tFT5X06.id[1]);
158. printf("(%5d,%5d,%3d,%3d) ", g_tFT5X06.X[2], g_tFT5X06.Y[2], g_tFT5X06.Event[2],
159. g_tFT5X06.id[2]);
160. printf("(%5d,%5d,%3d,%3d) ", g_tFT5X06.X[3], g_tFT5X06.Y[3], g_tFT5X06.Event[3],
161. g_tFT5X06.id[3]);
162. printf("(%5d,%5d,%3d,%3d) ", g_tFT5X06.X[4], g_tFT5X06.Y[4], g_tFT5X06.Event[4],
163. g_tFT5X06.id[4]);
164. printf("\r\n");
165. #endif
166. }
下面将程序设计中几个关键地方做个阐释:
GT911支持多达5点触摸同时按下,并提供了I2C通信接口方式,更多相关知识学习可以在这里下载GT911数据手册:http://www.armbbs.cn/forum.php?mod=viewthread&tid=87205 。
GT911的使用基本跟FT5X06是一样(注意,芯片GT911返回的就是实际的坐标值,比如显示屏的分辨率是800*480,那么返回的就是在这个分辨率范围内的实际坐标,跟FT5X06也是一样的),具体实现代码如下(这里没有使用多点触摸功能,仅存了一个触摸值,一般情况下已经够用):
1. /*
2. ******************************************************************************************************
3. * 函 数 名: GT911_Scan
4. * 功能说明: 读取GT911触摸数据。读取全部的数据,需要 720us左右。放在 bsp_Idle()中执行
5. * 形 参: 无
6. * 返 回 值: 无
7. ******************************************************************************************************
8. */
9. void GT911_Scan(void)
10. {
11. uint8_t buf[48];
12. static uint8_t s_tp_down = 0;
13. uint16_t x, y;
14. static uint16_t x_save, y_save;
15. uint8_t clear_flag = 0;
16. static uint8_t s_count = 0;
17.
18. if (g_GT911.Enable == 0)
19. {
20. return;
21. }
22.
23. /* 10ms 执行一次 */
24. if (g_GT911.TimerCount < 10)
25. {
26. return;
27. }
28.
29. g_GT911.TimerCount = 0;
30.
31. #if 1 /* 方案1: 检测INT引脚电平. */
32. if (TOUCH_PenInt() == 0)
33. {
34. #else /* 方案2:不用INT引脚,读状态寄存器 */
35. GT911_ReadReg(GT911_READ_XY_REG, buf, 1);
36. if (buf[0] == 0)
37. {
38. #endif
39. if (s_tp_down == 1)
40. {
41. if (++s_count > 1)
42. {
43. s_count = 0;
44. s_tp_down = 0;
45. TOUCH_PutKey(TOUCH_RELEASE, x_save, y_save);
46. }
47. }
48. return;
49. }
50. s_count = 0;
51.
52. #if 1 /* 一般应用只读1点 */
53. GT911_ReadReg(GT911_READ_XY_REG, buf, 8);
54. #else /* 读5个触摸点 */
55. GT911_ReadReg(GT911_READ_XY_REG, buf, 40);
56. #endif
57.
58. GT911_WriteReg(GT911_READ_XY_REG, &clear_flag, 1); /* 读完坐标后必须写0清除 */
59.
60. /*
61. 0x814E R/W Bufferstatus Large_Detect number of touch points
62. Bit7: Buffer status,1表示坐标(或按键)已经准备好,主控可以读取;0表示未就绪,数据无效。
63. 当主控读取完坐标后,必须通过I2C将此标志(或整个字节)写为0。
64. Bit4: HaveKey, 1表示有按键,0表示无按键(已经松键)。
65. Bit3~0: Number of touch points, 屏上的坐标点个数
66.
67. 0x814F R Point1 track id
68. 0x8150 R Point1Xl 触摸点 1,X 坐标低 8 位
69. 0x8151 R Point1Xh 触摸点 1,X 坐标高 8 位
70. 0x8152 R Point1Yl 触摸点 1,Y 坐标低 8 位
71. 0x8153 R Point1Yh 触摸点 1,Y 坐标高 8 位
72. 0x8154 R Point1 触摸点 1,触摸面积低 8 位
73. 0x8155 R Point1 触摸点 1,触摸面积高 8 位
74. 0x8156 ----
75.
76. 0x8157 R Point2 track id
77. 0x8158 R Point2Xl 触摸点 2,X 坐标低 8 位
78. 0x8159 R Point2Xh 触摸点 2,X 坐标高 8 位
79. 0x815A R Point2Yl 触摸点 2,Y 坐标低 8 位
80. 0x815B R Point2Yh 触摸点 2,Y 坐标高 8 位
81. 0x815C R Point2 触摸点 2,触摸面积低 8 位
82. 0x815D R Point2 触摸点 2,触摸面积高 8 位
83. 0x815E ----
84.
85. 0x815F R Point3 track id
86. 0x8160 R Point3Xl 触摸点 3,X 坐标低 8 位
87. 0x8161 R Point3Xh 触摸点 3,X 坐标高 8 位
88. 0x8162 R Point3Yl 触摸点 3,Y 坐标低 8 位
89. 0x8163 R Point3Yh 触摸点 3,Y 坐标高 8 位
90. 0x8164 R Point3 触摸点 3,触摸面积低 8 位
91. 0x8165 R Point3 触摸点 3,触摸面积高 8 位
92. 0x8166 ----
93.
94. 0x8167 R Point4 track id
95. 0x8168 R Point4Xl 触摸点 4,X 坐标低 8 位
96. 0x8169 R Point4Xh 触摸点 4,X 坐标高 8 位
97. 0x816A R Point4Yl 触摸点 4,Y 坐标低 8 位
98. 0x816B R Point4Yh 触摸点 4,Y 坐标高 8 位
99. 0x816C R Point4 触摸点 4,触摸面积低 8 位
100. 0x816D R Point4 触摸点 4,触摸面积高 8 位
101. 0x816E ----
102.
103. 0x816F R Point5 track id
104. 0x8170 R Point5Xl 触摸点 5,X 坐标低 8 位
105. 0x8171 R Point5Xh 触摸点 5,X 坐标高 8 位
106. 0x8172 R Point5Yl 触摸点 5,Y 坐标低 8 位
107. 0x8173 R Point5Yh 触摸点 5,Y 坐标高 8 位
108. 0x8174 R Point5 触摸点 5,触摸面积低 8 位
109. 0x8175 R Point5 触摸点 5,触摸面积高 8 位
110. 0x8176 --
111.
112. */
113. g_GT911.TouchpointFlag = buf[0];
114. g_GT911.Touchkeystate = buf[1];
115.
116. g_GT911.X0 = ((uint16_t)buf[3] << 8) + buf[2];
117. g_GT911.Y0 = ((uint16_t)buf[5] << 8) + buf[4];
118. g_GT911.P0 = ((uint16_t)buf[7] << 8) + buf[6];
119.
120. #if 0 /* 其余4点一般不用 */
121. g_GT911.X1 = ((uint16_t)buf[9] << 8) + buf[10];
122. g_GT911.Y1 = ((uint16_t)buf[11] << 8) + buf[12];
123. g_GT911.P1 = ((uint16_t)buf[13] << 8) + buf[14];
124.
125. g_GT911.X2 = ((uint16_t)buf[17] << 8) + buf[16];
126. g_GT911.Y2 = ((uint16_t)buf[19] << 8) + buf[18];
127. g_GT911.P2 = ((uint16_t)buf[21] << 8) + buf[20];
128.
129. g_GT911.X3 = ((uint16_t)buf[24] << 8) + buf[23];
130. g_GT911.Y3 = ((uint16_t)buf[26] << 8) + buf[25];
131. g_GT911.P3 = ((uint16_t)buf[28] << 8) + buf[27];
132.
133. g_GT911.X4 = ((uint16_t)buf[31] << 8) + buf[30];
134. g_GT911.Y4 = ((uint16_t)buf[33] << 8) + buf[32];
135. g_GT911.P4 = ((uint16_t)buf[35] << 8) + buf[34];
136. #endif
137.
138. /* 检测按下 */
139. {
140. /* 坐标转换 :
141. 电容触摸板左下角是 (0,0); 右上角是 (479,799)
142. 需要转到LCD的像素坐标 (左上角是 (0,0), 右下角是 (799,479)
143. */
144. {
145. x = g_GT911.X0;
146. y = g_GT911.Y0;
147.
148. if (x > 799)
149. {
150. x = 799;
151. }
152.
153. if (y > 479)
154. {
155. y = 479;
156. }
157. }
158. }
159.
160. if (s_tp_down == 0)
161. {
162. s_tp_down = 1;
163.
164. TOUCH_PutKey(TOUCH_DOWN, x, y);
165. }
166. else
167. {
168. TOUCH_PutKey(TOUCH_MOVE, x, y);
169. }
170. x_save = x; /* 保存坐标,用于释放事件 */
171. y_save = y;
172.
173. #if 0
174. {
175. uint8_t i;
176.
177. for (i = 0; i < 34; i++)
178. {
179. printf("%02X ", buf[i]);
180. }
181. printf("\r\n");
182.
183. printf("(%5d,%5d,%3d) ", g_GT911.X0, g_GT911.Y0, g_GT911.P0);
184. printf("(%5d,%5d,%3d) ", g_GT911.X1, g_GT911.Y1, g_GT911.P1);
185. printf("(%5d,%5d,%3d) ", g_GT911.X2, g_GT911.Y2, g_GT911.P2);
186. printf("(%5d,%5d,%3d) ", g_GT911.X3, g_GT911.Y3, g_GT911.P3);
187. printf("(%5d,%5d,%3d) ", x, y, g_GT911.P4);
188. printf("\r\n");
189. }
190. #endif
191. }
下面将程序设计中几个关键地方做个阐释:
电容触摸的使用主要分为三步:
/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/* 省略未写 */
bsp_InitI2C(); /* 初始化I2C总线 */
TOUCH_InitHard(); /* 初始化触摸芯片,LCD面板型号的检查也在此函数,所以要在函数LCD_InitHard前调用 */
LCD_InitHard(); /* 初始化LCD */
}
/*
*********************************************************************************************************
* 函 数 名: bsp_RunPer1ms
* 功能说明: 该函数每隔1ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些需要周期性处理
* 的事务可以放在此函数。比如:触摸坐标扫描。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_RunPer1ms(void)
{
TOUCH_Scan(); /* 触摸屏 */
}
/*
*********************************************************************************************************
* 函 数 名: bsp_Idle
* 功能说明: 空闲时执行的函数。一般主程序在for和while循环程序体中需要插入 CPU_IDLE() 宏来调用本函数。
* 本函数缺省为空操作。用户可以添加喂狗、设置CPU进入休眠模式的功能。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Idle(void)
{
/* --- 喂狗 */
/* --- 让CPU进入休眠,由Systick定时中断唤醒或者其他中断唤醒 */
/* 例如 emWin 图形库,可以插入图形库需要的轮询函数 */
//GUI_Exec();
/* 例如 uIP 协议,可以插入uip轮询函数 */
TOUCH_CapScan();
}
TOUCH_DOWN表示按下消息。
TOUCH_MOVE表示触摸移动消息。
TOUCH_RELEASE表示触摸释放消息。
根据这几个消息,用户可以在程序里面判断当前获取的物理坐标值是否在设置的区域内来执行触摸操作。
int16_t tpX, tpY;
uint8_t ucTouch; /* 触摸事件 */
ucTouch = TOUCH_GetKey(&tpX, &tpY); /* 读取触摸事件 */
if (ucTouch != TOUCH_NONE)
{
switch (ucTouch)
{
case TOUCH_DOWN: /* 触笔按下事件 */
/* 在触笔所在位置显示一个小圈 */
if ((tpX > 0) && (tpY > 0))
{
}
break;
case TOUCH_MOVE: /* 触笔移动事件 */
/* 实时刷新触摸ADC采样值和转换后的坐标 */
{
/* 在触笔所在位置显示一个小圈 */
if ((tpX > 0) && (tpY > 0))
{
}
}
break;
case TOUCH_RELEASE: /* 触笔释放事件 */
/* 在触笔所在位置显示一个小圈 */
if ((tpX > 0) && (tpY > 0))
{
}
break;
}
}
由于V6开发板要做不同显示屏的自适应,所以关联了多个文件。自适应方法也比较简单,因为触摸芯片GT911,GT811,FT5X06和STMPE811都是I2C接口,通过I2C地址就区分开了,具体代码如下:
1. /*
2. ******************************************************************************************************
3. * 函 数 名: bsp_DetectLcdType
4. * 功能说明: 通过I2C触摸芯片,识别LCD模组类型。结果存放在全局变量 g_LcdType 和 g_TouchType
5. * 形 参: 无
6. * 返 回 值: 无
7. ******************************************************************************************************
8. */
9. void bsp_DetectLcdType(void)
10. {
11. uint8_t i;
12.
13. g_TouchType = 0xFF;
14. g_LcdType = 0xFF;
15.
16. bsp_DelayUS(5000);
17.
18. touch_printf("正在识别触摸屏型号\r\n");
19.
20. /* 50ms,等待GT811复位就绪,才能探测GT811芯片 ID */
21. for (i = 0; i < 5; i++)
22. {
23. /*
24. GT811电容触摸板和GT911的I2C地址相同
25. 一般就 0x28 、 0xBA 两种。
26. 通过读取触摸IC的芯片ID来识别。
27. */
28. if (i2c_CheckDevice(0x28) == 0)
29. {
30. uint32_t id;
31.
32. bsp_DelayUS(500);
33. g_GT911.i2c_addr = 0x28;
34. id = GT911_ReadID();
35. if (id == 0x00313139)
36. {
37. g_GT911.i2c_addr = 0x28;
38. g_TouchType = CT_GT911;
39. g_LcdType = LCD_70_800X480;
40. touch_printf("检测到7.0寸电容触摸屏GT911(0x28) 800x480\r\n");
41. }
42. else /* GT811 */
43. {
44. g_GT811.i2c_addr = 0x28;
45. g_TouchType = CT_GT811;
46. g_LcdType = LCD_70_800X480;
47. touch_printf("检测到7.0寸电容触摸屏GT811(0x28) 800x480\r\n");
48. }
49. break;
50. }
51.
52. if (i2c_CheckDevice(0xBA) == 0)
53. {
54. uint32_t id;
55.
56. bsp_DelayUS(500);
57. g_GT911.i2c_addr = 0xBA;
58. id = GT911_ReadID();
59. if (id == 0x00313139)
60. {
61. g_GT911.i2c_addr = 0xBA;
62. g_TouchType = CT_GT911;
63. g_LcdType = LCD_70_800X480;
64. touch_printf("检测到7.0寸电容触摸屏GT911(0xBA) 800x480\r\n");
65. }
66. else /* GT811 */
67. {
68. g_GT811.i2c_addr = 0xBA;
69. g_TouchType = CT_GT811;
70. g_LcdType = LCD_70_800X480;
71. touch_printf("检测到7.0寸电容触摸屏GT811(0xBA) 800x480\r\n");
72. }
73. break;
74. }
75.
76. /* FT系列电容触摸: 4.3寸id = 0x55 5.0寸id = 0x0A 7.0寸id = 0x06 */
77. if (i2c_CheckDevice(FT5X06_I2C_ADDR) == 0)
78. {
79. uint8_t id;
80.
81. bsp_DelayUS(50000); /* 延迟50ms */
82. id = FT5X06_ReadID();
83. if (id == 0x55)
84. {
85. g_TouchType = CT_FT5X06;
86. g_LcdType = LCD_43_480X272;
87. touch_printf("检测到4.3寸电容触摸屏\r\n");
88. }
89. else if (id == 0x0A)
90. {
91. g_TouchType = CT_FT5X06;
92. g_LcdType = LCD_50_800X480;
93. touch_printf("检测到5.0寸电容触摸屏\r\n");
94. }
95. else /* id == 0x06 表示7寸电容屏(FT芯片) */
96. {
97. g_TouchType = CT_FT5X06;
98. g_LcdType = LCD_70_800X480;
99. touch_printf("检测到7.0寸电容触摸屏FT\r\n");
100. }
101. break;
102. }
103.
104. /* 电阻触摸板 */
105. if (i2c_CheckDevice(STMPE811_I2C_ADDRESS) == 0)
106. {
107. /*
108. 0 = 4.3寸屏(480X272)
109. 1 = 5.0寸屏(480X272)
110. 2 = 5.0寸屏(800X480)
111. 3 = 7.0寸屏(800X480)
112. 4 = 7.0寸屏(1024X600)
113. 5 = 3.5寸屏(480X320)
114. */
115. uint8_t id;
116.
117. g_TouchType = CT_STMPE811; /* 触摸类型 */
118.
119. STMPE811_InitHard(); /* 必须先配置才能读取ID */
120.
121. id = STMPE811_ReadIO(); /* 识别LCD硬件类型 */
122.
123. touch_printf("检测到电阻触摸屏, id = %d\r\n", id);
124. switch (id)
125. {
126. case 0:
127. g_LcdType = LCD_43_480X272;
128. break;
129.
130. case 1:
131. g_LcdType = LCD_50_480X272;
132. break;
133.
134. case 2:
135. g_LcdType = LCD_50_800X480;
136. break;
137.
138. case 3:
139. g_LcdType = LCD_70_800X480;
140. break;
141.
142. case 4:
143. g_LcdType = LCD_70_1024X600;
144. break;
145.
146. case 5:
147. g_LcdType = LCD_35_480X320;
148. break;
149.
150. default:
151. g_LcdType = LCD_35_480X320;
152. break;
153. }
154. break;
155. }
156.
157. bsp_DelayMS(10);
158. }
159.
160. if (i == 5)
161. {
162. touch_printf("未识别出显示模块\r\n");
163. }
164. }
165.
下面将程序设计中几个关键地方做个阐释:
LCD驱动的移植与第4章4.7小节相同,这里重点说下触摸部分的移植。
通过前面的讲解,移植触摸驱动到自己的板子上,最简单的办法是将开发板上与触摸相关的文件全部移植过来,然后在这些文件的基础上进行修改。下面分两种情况进行说明:
当然,如果大家不想用开发板实现的方案,想自己重新实现一个,也是没问题的。
通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:
第1阶段,上电启动阶段:
第2阶段,进入main函数:
配套例子:
V6-2002_LCD Touch
实验目的:
实验内容:
LCD界面显示效果如下:
本章节为大家讲解的电阻触摸方案和电容触摸方案都是经过实战总结的,实际项目中比较实用。