硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2717|回复: 4
收起左侧

[LTDC] 【已更新完毕】关于电阻触摸的4点校准和2点校准使用原理说明,适用于裸机和GUI

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107034
QQ
发表于 2019-4-15 12:12:36 | 显示全部楼层 |阅读模式
2点触摸校准的实现
测试条件:
800*480分辨率显示屏,物理坐标值X轴范围0-799,Y轴0-479。
STMP811电阻触摸范围0 - 4095,其实就是一个差分ADC芯片。

实现思路:
点击了触摸板上的一点,会得到一个ADC采样值,含X轴和Y轴,那么如何将其转换为实际的物理坐标值?  实际上最简单的方法,建立一个比例关系即可:
采集的X轴ADC值乘以 799/4095,就是X物理坐标值。
采集的Y轴ADC值乘以 479/4095,就是Y物理坐标值。

考虑到触摸板的线性度差一点,坐标关系y = ax扩展为y = ax + b。

实现原理:
在左上角和右下角分别设置两个坐标点(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数值直接代入上面公式就可以得到校准后的物理坐标值。





回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107034
QQ
 楼主| 发表于 2019-4-15 15:31:14 | 显示全部楼层
4点触摸校准实现,略复杂
实现原理:
在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数值再次代入这个方程就得到了最终的物理坐标。


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107034
QQ
 楼主| 发表于 2019-4-15 16:46:41 | 显示全部楼层
  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. *        函 数 名: TOUCH_TransX
  16. *        功能说明: 将触摸ADC值转换为像素坐标
  17. *        形    参:  无
  18. *        返 回 值: X 坐标值,允许负值
  19. *********************************************************************************************************
  20. */
  21. static int16_t TOUCH_TransX(uint16_t _usAdcX, uint16_t _usAdcY)
  22. {
  23.         if (g_tTPParam.CalibPointCount == 2)
  24.         {
  25.                 uint16_t x;
  26.                 int32_t y;

  27.                 if (g_tTPParam.XYChange == 0)
  28.                 {
  29.                         x = _usAdcX;
  30.                         if (x == 0)
  31.                         {
  32.                                 y = 0;
  33.                         }
  34.                         else
  35.                         {
  36.                                 //y = CalTwoPoint(g_tTPParam.usAdcX1, TP_X1, g_tTPParam.usAdcX2, TP_X2, x);
  37.                                 y = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usLcdX1, g_tTPParam.usAdcX2, g_tTPParam.usLcdX2, x);
  38.                         }
  39.                 }
  40.                 else
  41.                 {
  42.                         x = _usAdcY;
  43.                         if (x == 0)
  44.                         {
  45.                                 y = 0;
  46.                         }
  47.                         else
  48.                         {
  49.                                 //y = CalTwoPoint(g_tTPParam.usAdcY1, TP_X1, g_tTPParam.usAdcY2, TP_X2, x);
  50.                                 y = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usLcdX1, g_tTPParam.usAdcY2, g_tTPParam.usLcdX2, x);
  51.                         }
  52.                 }
  53.                 return y;
  54.         }
  55.         else        /* 4点校准 */
  56.         {
  57.                 uint16_t x, x1, x2;
  58.                 int32_t y;

  59.                 if (g_tTPParam.XYChange == 0)        /* X Y 坐标不交换 */
  60.                 {
  61.                         x = _usAdcX;

  62.                         /* 根据 Y ADC 实时计算直线方程的参考点x1, x2
  63.                                 if  _usAdcY = usAdcY1 then  取点 = (AdcX1, TP_X1, AdcX4, TP_X4, _usAdcY)
  64.                                 if  _usAdcY = usAdcY2 then  取点 = (AdcX3, TP_X3, AdcX2, TP_X2, _usAdcY)

  65.                                 其中 TP_X1 = TP_X3;  TP_X4 = TP_X1 , 这是程序设定的校准位置的像素坐标, 是固定的。
  66.                                 我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
  67.                         */
  68.                         x1 = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usAdcX1, g_tTPParam.usAdcY2,  g_tTPParam.usAdcX3, _usAdcY);
  69.                         x2 = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usAdcX4, g_tTPParam.usAdcY2,  g_tTPParam.usAdcX2, _usAdcY);
  70.                 }
  71.                 else                                                /* X Y 坐标交换 */
  72.                 {
  73.                         x = _usAdcY;

  74.                         /* 根据 X ADC 实时计算直线方程的参考点x1, x2
  75.                                 if  _usAdcX = usAdcX1 then  取点 = (AdcY1, TP_X1, AdcY4, TP_X4, _usAdcX)
  76.                                 if  _usAdcX = usAdcX2 then  取点 = (AdcY3, TP_X3, AdcY2, TP_X2, _usAdcX)

  77.                                 其中 TP_X1 = TP_X3;  TP_X4 = TP_X1 , 这是程序设定的校准位置的像素坐标, 是固定的。
  78.                                 我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
  79.                         */
  80.                         x1 = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY1, g_tTPParam.usAdcX2,  g_tTPParam.usAdcY3, _usAdcX);
  81.                         x2 = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY4, g_tTPParam.usAdcX2,  g_tTPParam.usAdcY2, _usAdcX);
  82.                 }

  83.                 if (x == 0)
  84.                 {
  85.                         y = 0;
  86.                 }
  87.                 else
  88.                 {
  89.                         /* 根据2点直线方程,计算坐标 */
  90.                         //y = CalTwoPoint(x1, TP_X1, x2, TP_X2, x);
  91.                         y = CalTwoPoint(x1, g_tTPParam.usLcdX1, x2, g_tTPParam.usLcdX2, x);
  92.                 }
  93.                 return y;
  94.         }
  95. }

  96. /*
  97. *********************************************************************************************************
  98. *        函 数 名: TOUCH_TransY
  99. *        功能说明: 将触摸ADC值转换为像素坐标
  100. *        形    参:  无
  101. *        返 回 值: Y 坐标值,允许负值
  102. *********************************************************************************************************
  103. */
  104. static int16_t TOUCH_TransY(uint16_t _usAdcX, uint16_t _usAdcY)
  105. {
  106.         if (g_tTPParam.CalibPointCount == 2)        /* 2点校准 */
  107.         {
  108.                 int32_t x;
  109.                 int32_t y;

  110.                 if (g_tTPParam.XYChange == 0)
  111.                 {
  112.                         x = _usAdcY;
  113.                         if (x == 0)
  114.                         {
  115.                                 y = 0;
  116.                         }
  117.                         else
  118.                         {
  119.                                 //y = CalTwoPoint(g_tTPParam.usAdcY1, TP_Y1, g_tTPParam.usAdcY2, TP_Y2, x);
  120.                                 y = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usLcdY1, g_tTPParam.usAdcY2, g_tTPParam.usLcdY2, x);
  121.                         }
  122.                 }
  123.                 else
  124.                 {
  125.                         x = _usAdcX;
  126.                         if (x == 0)
  127.                         {
  128.                                 y = 0;
  129.                         }
  130.                         else
  131.                         {
  132.                                 //y = CalTwoPoint(g_tTPParam.usAdcX1, TP_Y1, g_tTPParam.usAdcX2, TP_Y2, x);
  133.                                 y = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY1, g_tTPParam.usAdcX2, g_tTPParam.usLcdY2, x);
  134.                         }
  135.                 }
  136.                 return y;
  137.         }
  138.         else /* 4点校准 */
  139.         {
  140.                 int32_t x, x1, x2;
  141.                 int32_t y;

  142.                 if (g_tTPParam.XYChange == 0)        /* X Y 坐标不交换 */
  143.                 {
  144.                         x = _usAdcY;

  145.                         /* 根据 X ADC 实时计算直线方程的参考点x1, x2
  146.                                 if  _usAdcX = usAdcX1 then  取点 = (AdcY1, TP_Y1, AdcY3, TP_Y3, _usAdcX)
  147.                                 if  _usAdcX = usAdcX2 then  取点 = (AdcY4, TP_Y4, AdcY2, TP_Y2, _usAdcX)

  148.                                 其中 TP_Y1 = TP_Y4;  TP_Y3 = TP_Y2 , 这是程序设定的校准位置的像素坐标, 是固定的。
  149.                                 我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
  150.                         */
  151.                         x1 = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY1, g_tTPParam.usAdcX2,  g_tTPParam.usAdcY4, _usAdcX);
  152.                         x2 = CalTwoPoint(g_tTPParam.usAdcX1, g_tTPParam.usAdcY3, g_tTPParam.usAdcX2,  g_tTPParam.usAdcY2, _usAdcX);
  153.                 }
  154.                 else                                                /* X Y 坐标交换 */
  155.                 {
  156.                         x = _usAdcX;

  157.                         /* 根据 X ADC 实时计算直线方程的参考点x1, x2
  158.                                 if  _usAdcY = usAdcY1 then  取点 = (AdcX1, TP_Y1, AdcX3, TP_Y3, _usAdcY)
  159.                                 if  _usAdcY = usAdcY2 then  取点 = (AdcX4, TP_Y4, AdcX2, TP_Y2, _usAdcY)

  160.                                 其中 TP_Y1 = TP_Y3;  TP_Y4 = TP_Y2 , 这是程序设定的校准位置的像素坐标, 是固定的。
  161.                                 我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
  162.                         */
  163.                         x1 = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usAdcX1, g_tTPParam.usAdcY2,  g_tTPParam.usAdcX4, _usAdcY);
  164.                         x2 = CalTwoPoint(g_tTPParam.usAdcY1, g_tTPParam.usAdcX3, g_tTPParam.usAdcY2,  g_tTPParam.usAdcX2, _usAdcY);
  165.                 }

  166.                 if (x == 0)
  167.                 {
  168.                         y = 0;
  169.                 }
  170.                 else
  171.                 {
  172.                         /* 根据2点直线方程,计算坐标 */
  173.                         //y = CalTwoPoint(x1, TP_Y1, x2, TP_Y2, x);
  174.                         y = CalTwoPoint(x1, g_tTPParam.usLcdY1, x2, g_tTPParam.usLcdY2, x);
  175.                 }
  176.                 return y;
  177.         }
  178. }
复制代码


回复

使用道具 举报

17

主题

248

回帖

299

积分

高级会员

积分
299
发表于 2019-4-15 21:55:37 | 显示全部楼层
采集的X轴ADC值乘以 799/4095,就是X物理坐标值。 采集的X轴ADC值乘以 479/4095,就是X物理坐标值。这个是笔误吧?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107034
QQ
 楼主| 发表于 2019-4-16 02:02:01 | 显示全部楼层
xieyang__ 发表于 2019-4-15 21:55
采集的X轴ADC值乘以 799/4095,就是X物理坐标值。 采集的X轴ADC值乘以 479/4095,就是X物理坐标值。这个是 ...

写错了,已经更正,谢谢指出
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-15 04:49 , Processed in 0.156042 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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