EFM32片内外设--ADC之四线制触摸屏

不知道大家有没有发现GG/LG 的DK上是附带了一个4线制触摸屏的。如果大家手头有DK的话,不妨载入Touch的demo,来试用一下。

这里就不说4线制的触摸屏的原理了,但是为了后续说明方便,我把这部分的硬件连接,以及软硬件处理方式单独提了出来,做了一个简要的说明。

1.硬件连接

如下图所示,触摸屏的四根信号线是直接连接到了MCU的AD脚。DISPLAY_TOUCH_xx以及EFM32_Bxx信号,是原理图上的Net(网络标号). 因为DK上的MCU是单独的一块小班,触摸屏在主板上,两者是通过插座连接在一起的,这些个Net就是是插座上的或则多路开关上的标识.

 

相对应的原理图的设计也比较简单,如下图所示:

R457下面标识了一个NM,表示No mount,不焊接的意思。但是从我个人角度来讲,这样的电路是有些简单了。因为触摸屏信号是直接到MCU的IO口,而且触摸屏是人直接接触的。大家应该都有冬天被静电打的过的经验吧,那可不仅仅只有2Kv哦。另外一个方面就是现在产品的安规等级越来越高了,甚至有客户接触需要过10Kv,12Kv的。。如果仅仅是通过阻容来保护的话,是不够的,建议在接口处加低漏电流的TVS管。因此改进之后的原理图大约如下:

2.软件实现:

软件部分,可以分为三个部分,一个是触摸屏校正,一个是检测是否有触摸动作,还有一个就是检测触摸的位置。

触摸屏的校正,还没有整理完毕,放在下节说明。

2.1 触摸动作的检测

2.1 GG/LG Touch demo中的触摸检测:

在软件中,调用了Touch()函数来判断是否有触摸的动作发生,具体检测的流程如下:

1. 将X1设置成输出0,X2设置成输出1,Y1配制成输入,Y2配制成推挽输出1,等待10uS,再切换成上拉输入。等待10uS

2.在Y2上进行一次ADC转换,并检查ADC的结果。

但是这样做虽然简单,但是效率却是不高。因为MCU仅仅是被动的检测是否有触摸发生。

整个代码如下:

static bool touched( void )
{
  uint32_t adcValue;

  GPIO_PinModeSet(LCD_TOUCH_X1, gpioModePushPull, 0);
  GPIO_PinModeSet(LCD_TOUCH_X2, gpioModePushPull, 1);
  GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModeInput, 0);

  GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModePushPull, 1);
  delayUs( 10 );
  GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModeInputPull, 1);
  delayUs( 10 );

  sInit.input = ADC_Y;
  ADC_InitSingle(ADC0, &sInit);

  adcValue = readAdc();

  GPIO_PinModeSet(LCD_TOUCH_X1, gpioModeInput, 0);
  GPIO_PinModeSet(LCD_TOUCH_X2, gpioModeInput, 0);
  GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModeInput, 0);

  return ( adcValue < 3800 ) ? true : false;
}

ADC检测的是Y2引脚,即PD1。目前还不理解为什么ADC在Y2引脚上做。而且是使用先充电,在检测的方式。感觉在Y1引脚上也是可以做的。

另外一种检测的方式,就是使用GPIO口中断的方式来进行。检测的步骤如下:

1. X1,X2配置为输出0.Y1配置为开漏带上拉输出。Y2配置为输入。

2.如果没有触摸,则Y2上的电平为高。因为Y1上有上拉。

3.如果有触摸,由于X1,X2上对地的电阻很小,因此被X1,X2上的电阻拉低。此时可以产生一个下降沿中断。

这个部分的原理,是因为电阻屏的阻值一般在几百ohm左右,再加上X1,X2对地电阻并联效应,相对于40kohm的上下拉来说,暂时可以忽略不记。虽未被实际验证过,但是理论上应该是没有问题。

如上仅仅是一种方式,由于屏本身的阻值较小,因此还有好几种方式可以实现触摸的中断检测。

2.2 触摸位置的检测:

这里先只讨论如何获得ADC值。如果要则算坐标,则需要先校正才能折算。

检测的步骤:

1.Y1输出0,Y2输出1,X1,X2输入。等待10us

2.开启ADC转换,取得Y的ADC值。

3.Y1,Y2输入,X1输出1,X2输出0,等待10us

4.开启ADC转换,取得X的ADC值。

5.配置所有的IO口为输入口。

之所以等待10us,相当于用10us的时间给外部充电。除了如上的操作之前,我们还带了最大值,最小值检测,平均算法等来增加触摸检测的精度。

函数的整体调用关系如下:

static uint32_t getTouchChSample12bit( ADC_SingleInput_TypeDef ch )
{
  int i;
  uint32_t value, min, max, acc;

  if ( ch == ADC_X )
  {
    GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModePushPull, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModePushPull, 1);
    GPIO_PinModeSet(LCD_TOUCH_X1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_X2, gpioModeInput, 0);
  }
  else
  {
    GPIO_PinModeSet(LCD_TOUCH_X1, gpioModePushPull, 1);
    GPIO_PinModeSet(LCD_TOUCH_X2, gpioModePushPull, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModeInput, 0);
  }

  sInit.input = ch;
  ADC_InitSingle(ADC0, &sInit);

  delayUs( 10 );
  acc = 0;
  max = 0;
  min = 4096;
  for ( i=0; i<5; i++ )
  {
    value = readAdc();
    acc += value;
    min = EFM32_MIN( min, value );
    max = EFM32_MAX( max, value );
  }
  /* Throw away largest and smallest sample */
  acc = acc - min - max;
  /* Average */
  acc = acc / 3;

  if ( ch == ADC_X )
  {
    GPIO_PinModeSet(LCD_TOUCH_Y1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_Y2, gpioModeInput, 0);
  }
  else
  {
    GPIO_PinModeSet(LCD_TOUCH_X1, gpioModeInput, 0);
    GPIO_PinModeSet(LCD_TOUCH_X2, gpioModeInput, 0);
  }

  return acc;
}

如上是目前电阻式触摸屏在GG/LG DK上的实现。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值