找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 35633|回复: 16
收起左侧

XPT2046触摸屏实验过程详解与STM32代码解析

  [复制链接]
ID:161768 发表于 2017-8-19 00:09 | 显示全部楼层 |阅读模式
学习目标:
1.复习 STM32 的硬件 SPI
2.学习触摸屏的原理
触摸屏实验

16.1 触摸屏的简介
现在的液晶屏大部分都带触摸了,一般我们使用比较多的是电阻式触摸屏(多点触摸属 于电容式触摸屏,比如几乎所有智能机都支持多点触摸,它们所用的屏就是电容式的触摸屏) 我们彩屏上面带的也是电阻式的触摸屏。
电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,它是一种多层的复 合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电 阻)导电层,上面再盖有一层外表面硬化处理、光滑防擦的塑料层、它的内表面也涂有一层 涂层、在他们之间有许多细小的(小于1/1000 英寸)的透明隔离点把两层导电层隔开绝缘。
1.001.jpg
当手指触摸屏幕时,两层导电层在触摸点位置就有了接触,电阻发生变化,在 X 和 Y 两个方向上的电压发生变化,产生信号,然后控制器读取信号,并计算出手指触摸的位置, 这就是电阻式触摸屏的原理。

1.002.jpg

16.2触摸屏的控制 XPT2046芯片简介
从上面的简介,我们知道触摸屏都需要一个 AD 转换器,也就是要将电压变化读取出 来,供主机求出触摸的位置。而我们彩屏上面使用的触摸芯片是XPT2046。
XPT2046 的特点主要有
1)              一款 4 导线制触摸屏控制器,采用 SPI 模式进行通信。
2)              内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。
3)              支持从 1.5V 到 5.25V 的低电压 I/O 接口。
XPT2046 应该有 16 个引脚,如图:

1.003.jpg
其引脚说明如下:

1.004.jpg

从上面的引脚图,我们知道,XPT2046 跟单片机的主要引脚主要有:BUSY、DIN(单 片机 SPI 输出端)、CS、DCLK(单片机 SPI 时钟端)、PEN(笔触中断)、DOUT(单片机 SPI 输入端)
16.3PZ6808L触摸屏的原理图

1.005.jpg

1.006.jpg

16.4XPT2046的操作
1.              XPT2046 的初始化
XPT2046 说起来其实就是一个 AD 转换器,所以它适合不需要什么初始化设置的, 而具体的初始化其实也就是单片机 IO 的初始化和 SPI 的初始化。
这次 STM32 是使用 SPI1 来进行操作,SPI 的设置其实在前几节课已经讲过了,这 里就不重复讲了,初始化的具体代码如下:
  1. /**********************************************************************
  2. * Function Name              : TOUCH_Init
  3. * Description              : 初始化触摸屏
  4. * Input              : None
  5. * Output              : None
  6. * Return              : None
  7. **********************************************************************/
  8. void TOUCH_Init(void)
  9. {
  10. GPIO_InitTypeDef GPIO_InitStructure;
  11. /* SPI 的 IO 口和 SPI 外设打开时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
  12. /* TOUCH-CS 的 IO 口设置 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13. GPIO_Init(GPIOD, &GPIO_InitStructure);
  14. /* TOUCH-PEN 的 IO 口设置 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;
  15. GPIO_Init(GPIOD, &GPIO_InitStructure); SPI1_Config();
  16. /* 要使用 FLASH 来存储校正参数,所以注意之前要初始化 */
  17. /* 检测是否有校正参数 */
  18. FLASH_ReadData(&TouchAdj.posState,              TOUCH_ADJ_ADDR, sizeof(TouchAdj));
  19. if(TouchAdj.posState != TOUCH_ADJ_OK)
  20. {
  21. TOUCH_Adjust(); //校正
  22. }
  23. }
复制代码
在这个函数中,调用了 SPI1 的初始化函数,和触摸屏的校正程序,下面是 SPI1 的


初始化程序,校正原理我们在后面在讲述。
  1. /**********************************************************************
  2. * Function Name              : SPI1_Config
  3. * Description              : 初始化 SPI2
  4. * Input              : None
  5. * Output              : None
  6. * Return              : None
  7. *********************************************************************/
  8. void SPI1_Config(void)
  9. {
  10. GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef              SPI_InitStructure;

  11. /* SPI 的 IO 口和 SPI 外设打开时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

  12. /* SPI 的 IO 口设置 */
  13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  14. GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //PA5.6.7 上拉
  15. /********************************************************************/
  16. /******************* 设置 SPI 的参数 ***********************************/
  17. /*********************************************************************/ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//选择全双
  18. 工 SPI 模式
  19. SPI_InitStructure.SPI_Mode = SPI_Mode_Master;              //主机模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8 位 SPI SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                              //时钟悬空高电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;              //在第二个时钟采集数据 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                            //Nss 使用软件控制
  20. /* 选择波特率预分频为 256 */
  21. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//从最高位开始传输
  22. SPI_InitStructure.SPI_CRCPolynomial = 7;


  23. SPI_Cmd(SPI1, ENABLE); SPI_Init(SPI1, &SPI_InitStructure);
  24. }
复制代码




2.              XPT2046 读取 X、Y 值


我们知道,触摸屏根据方向,分为 X 轴和 Y 轴两个部分,通过读取 X 轴和 Y 轴的 数据,我们就可以知道触摸屏触摸的位置了,就像数学上面的,知道了 x 坐标和 y 坐标, 那么就可以确定在坐标轴上面一个点的位置。
1.007.jpg
如何读取 XPT2046 的数据呢?接下来我们来看一个时序图:

8 位总线接口,无 DCLK 时钟延迟,24 时钟周期转换时序
XPT2046 完成一个完整的转换需要 24 个串行时钟,也就是需要 3 个字节的 SPI 时 钟。对照上图,XPT2046 前 8 个串行时钟,是接收 1 个字节的转换命令,接收到转换 命令了之后,然后使用 1 个串行时钟的时间来完成数据转换(当然在编写程序的时候, 为了得到精确的数据,你可以适当的延时一下),然后返回 12 个字节长度(12 个字节 长度也计时 12 个串行时钟)的转换结果。然后最后 3 个串行时钟返回三个无效数据。
所以读取一个完整转换过程为:
1)              发送 1 个 8 字节的控制命令
2)              在这里可以小延时一下,如果你 SPI 时钟周期比 XPT2046 转换周期慢许多,不 用延时也可以。
3)              读取 2 个字节的返回数据。
4)              进行数据处理。也就是丢弃最后读取到的 3 位数据。 我们需要读取两个数据,一个 X 轴数据和一个 Y 轴数据,所以我们这里需要两个控
制命令。一个完整的控制命令的结构为:

1.008.jpg

1.009.jpg


从上图,我们可以得到两个命令,读取 X 轴的命令为:0xD0。而读取 Y 轴的命令 为:0x90。
程序实现为:
  1. /**************************************************************************
  2. * Function Name              : TOUCH_ReadData
  3. * Description              : 采样物理坐标值
  4. * Input              : cmd:选择要读取是 X 轴还是 Y 轴的命令
  5. * Output              : None
  6. * Return              : 读取到的物理坐标值
  7. **************************************************************************/
  8. static uint16_t TOUCH_ReadData(uint8_t cmd)
  9. {
  10. uint8_t i, j;
  11. uint16_t readValue[TOUCH_READ_TIMES], value;
  12. uint32_t totalValue;


  13. /* SPI 的速度不宜过快 */ SPI2_SetSpeed(SPI_BaudRatePrescaler_16);
  14. /* 读取 TOUCH_READ_TIMES 次触摸值 */
  15. for(i=0; i<touch_read_times; i++)
  16. {              /* 打开片选 */ TOUCH_CS_CLR;
  17. /* 在差分模式下,XPT2046 转换需要 24 个时钟,8 个时钟输入命令,之后 1
  18. 个时钟去除 */
  19. /* 忙信号,接着输出 12 位转换结果,剩下 3 个时钟是忽略位 */ SPI1_WriteReadData(cmd); // 发送命令,选择 X 轴或者 Y 轴



  20. /* 读取数据 */
  21. readValue[i] = SPI1_WriteReadData(0xFF);
  22. readValue[i] <<= 8;
  23. readValue[i] |= SPI1_WriteReadData(0xFF);
复制代码

读取数据部分

  1. /* 将数据处理,读取到的 AD 值的只有 12 位,最低三位无用 */
  2. readValue[i] >>= 3; TOUCH_CS_SET;
  3. }


  4. /* 滤波处理 */
  5. /* 首先从大到小排序 */
  6. for(i=0; i<(TOUCH_READ_TIMES - 1); i++)
  7. {
  8. for(j=i+1; j<touch_read_times; j++)
  9. {
  10. /* 采样值从大到小排序排序 */

  11. if(readValue[i] < readValue[j])
  12. {
  13. value = readValue[i]; readValue[i] = readValue[j]; readValue[j] = value;
  14. }
  15. }
  16. }


  17. /* 去掉最大值,去掉最小值,求平均值 */
  18. j = TOUCH_READ_TIMES - 1;
  19. totalValue = 0;
  20. for(i=1; i<j; i++)="" 求="" y="" 的全部值
  21. {
  22. totalValue += readValue[i];
  23. }
  24. value = totalValue / (TOUCH_READ_TIMES - 2);


  25. return value;
  26. }
复制代码

在这个读取函数的程序中,为了获取数据值的准确性,进行多次读取,然后除去最大最 小值,求出平均值。这个就是所谓的程序滤波,接下来,再详细讲述程序滤波。

3.              物理坐标值的数据处理
在读取 X 轴和 Y 轴的物理坐标值,也就是 AD 值的时候,需要进行一些必要的数据处 理,这也是为了获取更准确的数据值,否则就会出现飞点等误差。
比较常用的程序滤波的方法为平均值法。也就是多次读取结果,然后去掉它们的最大值 和最小值,最后求取它们的平均值。这种方法读取的次数越多,得到的数据就更准确。而上 面我们读取数据程序里面使用的滤波方法也是这种方法。
不过为了更好的滤波,还使用了另外一种方式进行滤波。也就是当读取到两次数据之后, 然后检查两个数据之间的差值,如果超过理想的误差,那么丢弃数据。这种方法也是很多的 处理飞点的程序方法。
我们来看一下我例程中的程序数据处理:
  1. /**************************************************************************
  2. * Function Name              : TOUCH_ReadXY
  3. * Description              : 读取触摸屏的 X 轴 Y 轴的物理坐标值
  4. * Input              : *xValue:保存读取到 X 轴物理坐标值的地址
  5. *              * *yValue:保存读取到 Y 轴物理坐标值的地址
  6. * Output              : None
  7. * Return              : 0:读取成功;0xFF:读取失败
  8. **************************************************************************/


  9. static uint8_t TOUCH_ReadXY(uint16_t *xValue, uint16_t *yValue)
  10. {

  11. uint16_t xValue1, yValue1, xValue2, yValue2;


  12. xValue1 = TOUCH_ReadData(TOUCH_X_CMD); yValue1 = TOUCH_ReadData(TOUCH_Y_CMD); xValue2 = TOUCH_ReadData(TOUCH_X_CMD); yValue2 = TOUCH_ReadData(TOUCH_Y_CMD);

  13. /* 查看两个点之间的只采样值差距 */
  14. if(xValue1 > xValue2)
  15. {



  16. }
  17. else
  18. {


  19. }

  20. *xValue = xValue1 - xValue2;





  21. *xValue = xValue2 - xValue1;



  22. if(yValue1 > yValue2)
  23. {



  24. }
  25. else
  26. {


  27. }

  28. *yValue = yValue1 - yValue2;





  29. *yValue = yValue2 - yValue1;



  30. /* 判断采样差值是否在可控范围内 */
  31. if((*xValue > TOUCH_MAX) || (*yValue > TOUCH_MAX))
  32. {
  33. return 0xFF;
  34. }


  35. /* 求平均值 */
  36. *xValue = (xValue1 + xValue2) / 2;
  37. *yValue = (yValue1 + yValue2) / 2;


  38. /* 判断得到的值,是否在取值范围之内 */
  39. if((*xValue > TOUCH_X_MAX) || (*xValue < TOUCH_X_MIN)
  40. || (*yValue > TOUCH_Y_MAX) || (*yValue < TOUCH_Y_MIN))
  41. {
  42. return 0xFF;
  43. }


  44. return 0;

  45. }
复制代码
该程序就如上述所说,调用上一小节的 TOUCH_ReadData()读两次 X 轴和 Y 轴(如果 把 XY 轴,交叉来读,效果更好)。然后求取它们差值(求平均值在TOUCH_ReadData()函 数中已经使用了),判断是否超过理想误差,然后求出它们两个的平均值,最后查看是否超 过 X 轴和 Y 轴的数据上限和数据下限。

4.              触摸物理坐标值转换成 LCD 彩屏坐标
我们使用 XPT2046 读取到了触摸屏的触摸位置之后,想要在 LCD 屏相对应的位置上进 行操作,我们还要将它转换成 LCD 屏的坐标值。比如说,我们在LCD 屏(0, 0)坐标位置 按下,而读取到的物理坐标值(也就是 AD 值)为(100,200),那么我们想要在 LCD 屏(0, 0) 位置进行处理,将要将物理坐标(100,200)转换成 LCD 屏坐标。
那如何转换呢?我们知道,XPT2046 的分辨率为 12 位,也就是说我们读取 X 轴的物理 坐标值(这里我们假设为:Px)和 Y 轴的物理坐标值(这里我们假设为:Py)的值肯定是 在 0~4096 之间。但是我们 LCD 彩屏 X 轴和 Y 轴的像素坐标确是 240X400。(这个值是 PZ6908L 开发板配的 3.5 寸彩屏像素,不过不管多少,我们明白原理就行,为了更好的表示, 在这里我们 LCD 彩屏 X 轴像素坐标我们假设为:Lcdx, LCD 彩屏 Y 轴像素坐标我们假设 为:Lcdy。)那么我们假设当(Px, Py) = (0, 0)时,正好 LCD 彩屏像素坐标的起始坐标(0, 0), 当(Px, Py) = (4096, 4096)时,正好 LCD 彩屏像素坐标的终止坐标(239, 399)。难么我们不难 看出触摸屏的物理坐标跟 LCD 彩屏像素坐标的对应关系为:
Factorx = Lcdx / Px;
Factory = Lcdy / Py;
那么我们就可以求出 Factorx 和 Factory,然后每次读取到 Px 和 Py 之后就可以讲它很轻 松的转换为 Lcdx 和 Lcdy。这是一个很简单的数学关系。
不过呢,事情没有那么理想化,我们在 LCD 像素坐标为(0, 0)读取的触摸屏物理坐标 值不一定是(0,0),在 LCD 像素坐标为最大时,也不一定读取到的是触摸屏的物理坐标最 大值。所以我们要进行一些数据校正,这也是屏幕校正的原因。
什么意思呢?那我们在来解一个数学问题: 我们都知道每个触摸屏物理坐标值都能一一对应一个 LCD 彩屏上面的像素坐标值,也
就是它们是成比例关系的。现在我们知道 LCD 彩屏的 X 轴像素坐标最小值为 Lcdx1,我们 能显示的 LCD 彩屏的 X 轴像素坐标最大值为 Lcdx2。而我们在LCD 彩屏像素坐标 X 轴最 小值处读取的触摸屏 X 轴物理坐标为 Px1,在 LCD 彩屏 X 轴像素坐标最大值处读取的触摸 屏 X 轴的物理坐标为 Px2。那么现在我们知道有一个触摸屏物理坐标值在 Px1 到 Px2 之间 的坐标值为 Px,那么和它对应的 Lcdx 的值是多少呢?
那么我们可以这么解:
Factorx = (Lcdx2 – Lcdx1) / (Px2 – Px1); Lcdx = (Px – Px1) * Factorx; 那么就求得出 Lcdx 是多少了,对吧? 现在我们把它分解出来:
Lcdx = Px * Factorx – Px1 * Factorx;
然后将 Px1*Factorx 替换成一个变量 Offsetx。那么我们现在就可以得到 Lcdx 和 Px 之间 的对应关系式了。而关于 Y 轴也是同理,所以它们从物理坐标到像素坐标的转换关系式:
Lcdx = Px * Factorx – Offsetx;
Lcdy = Py * Factory – Offsety;
而求出 Factor 和 Offset 这两个数的过程就是校正程序应该做的工作了。现在我们理解了
屏幕校正的原因和原理,并懂得了物理坐标转换成像素坐标之后,我们来看一下我们例程的 校正程序和触摸屏读取像素坐标程序。
  1. /**************************************************************************
  2. * Function Name              : TOUCH_Adjust
  3. * Description              : 检测屏幕是否校正,没有的话进行校正,将校正值放置到 FLASH 中
  4. * Input              : None
  5. * Output              : None
  6. * Return              : None
  7. **************************************************************************/


  8. static void TOUCH_Adjust(void)
  9. {
  10. uint16_t px[2], py[2], xPot[4], yPot[4];
  11. float xFactor, yFactor;


  12. /* 读取第一个点 */
  13. if(TOUCH_ReadAdjust(LCD_ADJX_MIN, LCD_ADJY_MIN, &xPot[0], &yPot[0]))
  14. {
  15. return;
  16. }
  17. TOUCH_AdjDelay500ms();


  18. /* 读取第二个点 */
  19. if(TOUCH_ReadAdjust(LCD_ADJX_MIN, LCD_ADJY_MAX, &xPot[1], &yPot[1]))
  20. {
  21. return;
  22. }
  23. TOUCH_AdjDelay500ms();


  24. /* 读取第三个点 */
  25. if(TOUCH_ReadAdjust(LCD_ADJX_MAX, LCD_ADJY_MIN, &xPot[2], &yPot[2]))
  26. {
  27. return;
  28. }
  29. TOUCH_AdjDelay500ms();


  30. /* 读取第四个点 */
  31. if(TOUCH_ReadAdjust(LCD_ADJX_MAX, LCD_ADJY_MAX, &xPot[3], &yPot[3]))
  32. {
  33. return;
  34. }
  35. TOUCH_AdjDelay500ms();


  36. /* 处理读取到的四个点的数据,整合成对角的两个点 */

  37. px[0] = (xPot[0] + xPot[1]) / 2; py[0] = (yPot[0] + yPot[2]) / 2; px[1] = (xPot[3] + xPot[2]) / 2; py[1] =(yPot[3] + yPot[1]) / 2;

  38. /* 求出比例因数 */
  39. xFactor = (float)LCD_ADJ_X / (px[1] - px[0]);
  40. yFactor = (float)LCD_ADJ_Y / (py[1] - py[0]);


  41. /* 求出偏移量 */
  42. TouchAdj.xOffset = (int16_t)LCD_ADJX_MAX - ((float)px[1] * xFactor); TouchAdj.yOffset = (int16_t)LCD_ADJY_MAX - ((float)py[1] *yFactor);

  43. /* 将比例因数进行数据处理,然后保存 */ TouchAdj.xFactor = xFactor ;
  44. TouchAdj.yFactor = yFactor ;


  45. TouchAdj.posState = TOUCH_ADJ_OK;
  46. FLASH_WriteData(&TouchAdj.posState, TOUCH_ADJ_ADDR, sizeof(TouchAdj));
  47. }
  48. /*************************************************************************
  49. * Function Name              : TOUCH_Scan
  50. * Description              : 扫描是否有触摸按下
  51. * Input              : None
  52. * Output              : TouchData:读取到的物理坐标值和对应的彩屏坐标值
  53. * Return              : 0:读取成功;0xFF:没有触摸
  54. **************************************************************************/


  55. uint8_t TOUCH_Scan(void)
  56. {


  57. if(TOUCH_PEN == 0)              //查看是否有触摸
  58. {
  59. if(TOUCH_ReadXY(&TouchData.x, &TouchData.y)) //没有触摸
  60. {
  61. return 0xFF;
  62. }
  63. /* 根据物理坐标值,计算出彩屏坐标值 */
  64. TouchData.lcdx = TouchData.x * TouchAdj.xFactor + TouchAdj.xOffset; TouchData.lcdy = TouchData.y * TouchAdj.yFactor +TouchAdj.yOffset;

  65. /* 查看彩屏坐标值是否超过彩屏大小 */
  66. if(TouchData.lcdx > TFT_XMAX)
  67. {

  68. TouchData.lcdx = TFT_XMAX;
  69. }
  70. if(TouchData.lcdy > TFT_YMAX)
  71. {
  72. TouchData.lcdy = TFT_YMAX;
  73. }
  74. return 0;
  75. }
  76. return 0xFF;
  77. }
复制代码

231455pdd2r7qzg71dwq2q.png
完整源码+资料等内容下载地址:
http://www.51hei.com/bbs/dpj-92931-1.html


回复

使用道具 举报

ID:371460 发表于 2018-7-14 14:37 | 显示全部楼层
学习了,谢谢!
回复

使用道具 举报

ID:427437 发表于 2018-11-16 13:42 | 显示全部楼层
本帖最后由 linppp000 于 2018-11-16 13:50 编辑

      /* 在差分模式下,XPT2046 转换需要 24 个时钟,8 个时钟输入命令,之后 1
      个时钟去除 */
      /* 忙信号,接着输出 12 位转换结果,剩下 3 个时钟是忽略位 */
      SPI1_WriteReadData(cmd); // 发送命令,选择 X 轴或者 Y 轴   

      /* 读取数据 */
      readValue = SPI1_WriteReadData(0xFF);
      readValue <<= 8;
      readValue |= SPI1_WriteReadData(0xFF);

这里如果发送SPI1_WriteReadData(0xFF);接收到的数据异常,SPI1_WriteReadData(0);才正常,不知道其他人有没有遇到这种情况。
回复

使用道具 举报

ID:91445 发表于 2019-3-10 10:25 | 显示全部楼层
讲得很清楚,感谢分享
回复

使用道具 举报

ID:493925 发表于 2019-3-19 14:24 | 显示全部楼层
感谢分享
回复

使用道具 举报

ID:98985 发表于 2019-4-16 09:31 | 显示全部楼层
多谢分享,好东西
回复

使用道具 举报

ID:384489 发表于 2019-6-10 17:03 | 显示全部楼层
很有参考意义,感谢分享。
回复

使用道具 举报

ID:490991 发表于 2019-7-25 16:43 | 显示全部楼层
linppp000 发表于 2018-11-16 13:42
/* 在差分模式下,XPT2046 转换需要 24 个时钟,8 个时钟输入命令,之后 1
      个时钟去除 */
   ...

是的,最近刚调试了XPT2046,这儿连续读两个数据,要发送SPI1_WriteReadData(0x00);,这样才能多读取几组数据;SPI1_WriteReadData(0xff);会让XPT2046关闭AD转换,后面就读不到数据了
回复

使用道具 举报

ID:412641 发表于 2019-9-25 15:39 | 显示全部楼层
时序讲解的很好理解,测试一下看效果如何,多谢。
回复

使用道具 举报

ID:229407 发表于 2019-10-25 15:19 | 显示全部楼层
多谢分享!
回复

使用道具 举报

ID:403336 发表于 2020-2-14 22:25 | 显示全部楼层
谢谢,非常好的资料
回复

使用道具 举报

ID:290373 发表于 2020-2-15 10:10 | 显示全部楼层
正好最近在做一个带有XPT2046的项目,很有参考价值,感谢经验分享
回复

使用道具 举报

ID:561907 发表于 2020-3-5 11:26 | 显示全部楼层
不错,学习了。
回复

使用道具 举报

ID:399799 发表于 2022-11-6 18:29 | 显示全部楼层
论坛就是个宝库,每次逛都有收获
回复

使用道具 举报

ID:1062719 发表于 2023-3-20 16:24 | 显示全部楼层
为什么是配置时钟高电平,第二个时钟采集?不是低电平,第一个采集吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表