第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 初学者重要提示
- 本章是为emWin的触摸部分做准备。
- 电阻触摸支持2点和4点校准,而电容屏无需校准。
- 电阻触摸校准解决的是触摸板的线性度问题,而飞点要另外处理,当前程序已经做了支持。总的来说,V7配套的电阻触摸方案已经比较成熟,可以放心用于项目。
- 屏蔽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. }
下面将程序设置中的关键地方做个阐释:
- 第18-25行,用于标记是4点触摸校准还是2点触摸校准。
- 第31行,显示触摸校准点,2点触摸校准的话,显示左上角和右下角的校准点位置。4点触摸校准的话,显示左上角,右上角,左下角和右下角的校准点位置。
- 第33行,用于等待触摸笔释放,当校准完毕1个点后,等待释放时使用。
- 第35-79行,读取500次X轴和Y轴的ADC数值,每10ms读取1次,每个触摸点的最大读取时间就是5秒。如果5秒内还没有
以上是关于第3版emWin教程第5章 emWin上手之电阻触摸和电容触摸的主要内容,如果未能解决你的问题,请参考以下文章
第3版emWin教程第2章 初学emWin的准备工作及其快速上手
第3版emWin教程第4章 emWin上手之STM32H7 LTDC基础知识
第3版emWin教程第4章 emWin上手之STM32H7 LTDC基础知识
第3版emWin教程第6章 emWin上手之STM32H7 DMA2D加速