xwkm 发表于 2013-2-13 00:54:16

用LGT的普通IO成功实现电容触摸

本帖最后由 xwkm 于 2013-2-13 00:55 编辑

上电路图:

这个覆铜我在面包板上没法实现,暂时用根杜邦线代替好了……
后面上面盖了层双面覆铜板,照样实现触摸。滤波和均衡算法参见的是这位仁兄的帖子:
http://www.amobbs.com/forum.php?mod=viewthread&tid=1392884&highlight=%E8%A7%A6%E6%91%B8%2B%E7%94%B5%E5%AE%B9%E8%A7%A6%E6%91%B8
临界状态没有处理,完善的时候会多测几次。大于某个数值证明真的按下了。
上正在调试语句一打的代码:#include <avr/io.h>                  // GCC的标准io.h
#include <avr/wdt.h>

#include <util/delay.h>
#include <avr/interrupt.h>
#include <iolgt8f0xa.h>          // LGT的头文件


#define Set_Bit(val, bitn)    (val |=(1<<(bitn)))
#define Clr_Bit(val, bitn)   (val&=~(1<<(bitn)))
#define Get_Bit(val, bitn)    (val &(1<<(bitn)) )
#define LED 5
#define CAP 7//电容按键

unsigned char x;
#define DEBUG        1
#if DEBUG==1
#include <stdio.h>
unsigned char buf;
#define dbg(fmt, args...) sprintf(buf,fmt,## args);putstr(buf);
#else
#define dbg()
#define Serial_Init()
#endif

#if DEBUG==1
void Serial_Init()
{//串口初始化,8MHz,9600bps
                #warning debug on
                CLKPR=0x80;
                CLKPR=0x01;
                x=OSCCAL;
                OSCCAL=0x06;//OSCCAL
      UCSR0A=0x00;
      UBRR0H=0x00;
      UBRR0L=0x33;   //9600bps
      UCSR0B = 0x18; //0b00011000    允许:发送、接收
      UCSR0C = 0x0E; //0b00001110    数据帧格式:8,N,1
}

void _putchar(char c)
{
      while((UCSR0A & (1 << UDRE0)) == 0);
      UDR0 = c;

}

void putstr(unsigned char* buf)
{
      while (*buf)
      {
                _putchar(*buf);
                buf++;
      }
}
#endif
void Discharge()
{
        Clr_Bit(PORTA,CAP);//放光电
        Set_Bit(DDRA,CAP);//输出模式
        _delay_ms(1);
}
unsigned char rcMeter()
{//测量
        unsigned char i;//--,j;
        Discharge();
        Clr_Bit(DDRA,CAP);//输入模式,靠外部上拉电阻以及内部电容上拉到Vh
        i=0;
        while(!(PINA & _BV(CAP)))
        {//等待CAP口被上拉到Vh来判断电容
                i++;
                //8MHz
                if(i>250){//如果大于31.25uS的话就无效处理
                break;}
        }
        return i;
}
//*******************************************************************
//函数名字; DataAdd(*buffer, size);
//输入参数; 缓冲区首址, 大小
//输出参数; 数据总和
//功能描述; 缓冲区所有数据相加
//建造日期; 2008年08月09日
//*******************************************************************   
unsigned int DataAdd(unsigned char *buffer, unsigned char size)
{
        unsigned int add;
   unsigned char i;
   
   add = 0;                                              //数据清零

   for (i = 0; i < size; i++)
      {
       add += *buffer;                                 //数据相加
       buffer++;
      }

   return add;                                           //返回总和                  
}

//*******************************************************************
//函数名字; DataMax(*buffer, size);
//输入参数; 缓冲区首址, 大小
//输出参数; 数据最大值
//功能描述; 选出缓冲区最大值
//建造日期; 2008年08月09日
//*******************************************************************
unsigned char DataMax(unsigned char *buffer, unsigned char size)
{
   unsigned char max, i;
   
   max = buffer;                                    //假设最大
   
   for (i = 1; i < size; i++)
      {
       if (max < *buffer) max = *buffer;               //对比最大
       buffer++;
      }

   return max;                                           //最大数据                  
}

//*******************************************************************
//函数名字; DataMin(*buffer, size);
//输入参数; 缓冲区首址, 大小
//输出参数; 数据最小大值
//功能描述; 选出缓冲区最小值
//建造日期; 2008年08月09日
//*******************************************************************
unsigned char DataMin(unsigned char *buffer, unsigned char size)
{
   unsigned char min, i;
   
   min = buffer;                                    //假设最小
   
   for (i = 1; i < size; i++)
      {
       if (min > *buffer) min = *buffer;               //对比最小
       buffer++;
      }

   return min;                                           //最小数据
}
unsigned char getData()
{
        unsigned char rcbuf,max,min,avg;
        unsigned int sum;
        for(avg=0;avg<10;avg++)
        {
                rcbuf=rcMeter();//测量
        }
        sum=DataAdd(rcbuf,10);
   max = DataMax(rcbuf, 10);                              //取最大值
   min = DataMin(rcbuf, 10);                              //取最小值
        return ((sum-max-min)/8);//去掉最大值最小值后平均
}
int main()
{            
    unsigned char regular;//基准点                                                                                                                                                   
        //电容按键测试
        //DDRA=0xFF;
        MCUCR=MCUCR|(1<<PUD);
        DDRA=0xFF;
        Clr_Bit(PORTA,1);
        Serial_Init();
        dbg("system ok.OSCCAL old is :%d\n",x);
        regular=getData();//设定基准点
        regular +=4;//消除抖动,可能你的硬件设备需要调整一下也说不定
        //建议在空闲时刻多测几次,换了环境干扰很容易导致值不确定
        dbg("Regular RC value is %d",regular);
        while(1)
        {

                //dbg("RC value=%d\n",getData());
                //_delay_ms(1000);
                if(getData()>regular) //消除抖动
                {
                        Clr_Bit(PORTA,2);
                        Set_Bit(PORTA,0);
                }
                else
                {
                        Set_Bit(PORTA,2);
                        Clr_Bit(PORTA,0);                       
                }
                /*for(i=0;i<255;i++)
                {//变亮
                        PWM(i/2,i,20);
                }
                for(i=255;i>0;i--)
                {//变暗
                        PWM(i/2,i,25);
                }*/
                /*for(i=0;i<6;i++)
                {
                        Set_Bit(PORTA,PA2);
                        _delay_ms(80);
                        Clr_Bit(PORTA,PA2);
                        _delay_ms(50);
                }*/
                /*for(i=0;i<255;i++)
                {
                        PWM(0,i,20);
                }
                for(i=0;i<255;i++)
                {
                        PWM(0,255-i,20);
                }
                for(i=0;i<3;i++)
                {
                        Set_Bit(PORTA,PA0);
                        Clr_Bit(PORTA,PA2);
                        _delay_ms(50);
                        Clr_Bit(PORTA,PA0);
                        Clr_Bit(PORTA,PA2);
                        _delay_ms(100);
                        Set_Bit(PORTA,PA2);
                        Clr_Bit(PORTA,PA0);
                        _delay_ms(50);
                        Clr_Bit(PORTA,PA2);
                        Clr_Bit(PORTA,PA0);
                        _delay_ms(100);                       
                }               
                for(i=0;i<255;i++)
                {
                        PWM(i,0,20);
                }*/
        }       
}


双色LED直接插在PA0~PA2上。如果按下亮红灯。松开亮绿灯。面包板做的,我懒得去自己动手做板子了。

测试ing
PS:1M的电阻找不到,就只好用两个470K的串联替代了。

测试ing

工作台一览,还爆照了……

刚开始用杜邦线做实验

按住红灯

松开绿灯

xwkm 发表于 2013-2-13 00:58:29

本帖最后由 xwkm 于 2013-2-13 01:05 编辑

上一下串口的输出信息。我的硬件输出的,可能布板不同也会有影响,不过我这个是自动校准的算法,移植可能问题不大。

2MM厚的玻纤是实验成功了。不知道巨大干扰会不会引起问题

logicgreen 发表于 2013-2-17 13:47:46

电容触摸式按键检测关键的是抗干扰设计,就目前来说稳定可靠的大多还是采用电荷转移法,具体做法是用脉冲充电再用ADC采样。

我们即将推出的LGT8F88A的触摸按键设计就是用这个方法,可以应用在电磁炉等复杂干扰环境的家电或工业控制产品当中。

fantasywlh 发表于 2013-2-26 22:26:17

楼主说有自动校准的算法,但是在是看不到自动校准的那一块。

按照你的程序,如果你一开始的时候就把手指压在触摸板上, regular=getData(),你得到了一个值22,这个值是触摸的值,并且假设是这个环境下的最高值。 然后你 regular += 4;那么你一开始 regular = 26。 这个值在后面都没有被更新过。

按照这样的话,那么你做出来的结果有可能稳定吗?会不会有连响应都没有情况吗?{:shocked:}

leon11hk 发表于 2013-2-27 10:16:23

主楼的程序是可以跑,可能要自已调整一下修改一下。
我觉得楼主说空闲时多做几次校正是指叫我们自已添加几次像初始时采集的regular 值。而不是程序有已经有自动校正。
昨天画了块板子改了一下程序,如输入部分是没有按照lgt的ic 做处理的我改了一下,不然会死机的,我想你们懂的。
还有时钟改成16M的,把key数目做成12个而且每个是有自已的校准值。
然後我把程序的debug语句去掉了,我用winavr 时发现刚开始没问题可是最後发现对PORTA.0有影响,因为我是用循环方式采集数据,我试了很多方式,如果独立做处理没问题的,後来我程序不改只把这些语句去掉後就正常了。
还有我改了采集时的处理加了按键滤波,其它还没有改。

这个设计主要问题是如何校正跟滤波吧...

正在把它做成库可以随意加KEY 到不同PIN上,(LGT我是要把JTAG接口那两个SWD SWC功能关掉)用中断处理。

上面图那个是昨天做的所有KEY都测过了,也做了水滴的测试,现在要加入自动校正比较一下,可是正在想什麽时候才校正...哈哈

xwkm 发表于 2013-2-27 16:14:02

谢谢楼上!您的想法比我成熟。

leon11hk 发表于 2013-2-28 09:50:57

xwkm 发表于 2013-2-27 16:14 static/image/common/back.gif
谢谢楼上!您的想法比我成熟。

我也只是惨考你上面的程序做,做出来效果用语言未必能表逹出来的,打算用在一个项目上,返正那个项目的这部分任我发挥... 就算有问题乜没所谓(一年也用不了几次按键),也当作测试性质哈...
我把10次采集改成8次, 把最大最小数值去掉了,还有充放电的固定10ms我也改了...这个最影响速度的延时,有一个想法的,就是在充放电一个pin 时检测上一个键,利用检测的时间放下一个pin的电。
偷偷问下楼主是在用lgt做开发工作吗?感觉只有你在坛上发表关於lgt的,哈哈...

清雨影 发表于 2013-2-28 12:31:38

leon11hk 发表于 2013-2-28 09:50 static/image/common/back.gif
我也只是惨考你上面的程序做,做出来效果用语言未必能表逹出来的,打算用在一个项目上,返正那个项目的这 ...

像惨考这种错别字是要"沙头"的

leon11hk 发表于 2013-2-28 16:14:49

哦... 不断惨烈调试和考量^^" 嗯,我意思是我是打错了

xwkm 发表于 2013-3-2 14:32:11

我只是学生而已。不是专门搞LGT的。原来我是玩51和上位机的。可以搜rgwan的帖子。那个号现在我已经找不到了……

lyyyuna 发表于 2013-3-3 10:03:51

楼主是97年的。。。。

inkfish321 发表于 2013-3-3 11:18:38

谁搞过这个低功耗的应用,最少用多大电流实现?

xwkm 发表于 2013-3-3 12:02:52

inkfish321 发表于 2013-3-3 11:18 static/image/common/back.gif
谁搞过这个低功耗的应用,最少用多大电流实现?

2mA @ 3V 2MHz

xwkm 发表于 2013-3-20 17:34:56

leon11hk 发表于 2013-2-28 16:14 static/image/common/back.gif
哦... 不断惨烈调试和考量^^" 嗯,我意思是我是打错了

对了,你开源了没?

huy666 发表于 2013-4-23 12:50:57

leon11hk 发表于 2013-2-27 10:16 static/image/common/back.gif
主楼的程序是可以跑,可能要自已调整一下修改一下。
我觉得楼主说空闲时多做几次校正是指叫我们自已添加几 ...

楼主这种按键怎么做的,bmp转的?
能否将封装共享下?谢谢!

进口小开关 发表于 2013-4-23 13:03:03

楼主用的是哪个发行版本的linux?感觉不错。

leon11hk 发表于 2013-4-26 18:05:55

huy666 发表于 2013-4-23 12:50 static/image/common/back.gif
楼主这种按键怎么做的,bmp转的?
能否将封装共享下?谢谢!

这个按键模样并不是库,也不是用BMP 导入的。
我是在YOUTUBE 里看到国外的一个教你在POLYGON上做空心字学的。
在EAGLE上,首先画一个POLYGON,
然後把POLYGON线宽设为最小,把ISOLATE 设为最小,
然後打一个文字在BOTTON层,然後把这个文字设成VECTOR 字型,
然後选择大小後放在POLYGON上就可以了!
也可以用BMP导入到库里做成完件,SKYFUN 里本身就有两种TOUCH按键库的。

leon11hk 发表于 2013-4-26 18:10:35

打错了,要把文字放在BRESTRICT 层而不是 BOTTON层。
这个是点, 那层的意思就是禁正覆铜。

skynet 发表于 2013-4-26 19:35:25

leon11hk 发表于 2013-4-26 18:10 static/image/common/back.gif
打错了,要把文字放在BRESTRICT 层而不是 BOTTON层。
这个是点, 那层的意思就是禁正覆铜。 ...

能不能分享1下封装哈,最好是AD的嘿嘿

dgtg 发表于 2013-8-17 20:34:29

leon11hk 发表于 2013-2-27 10:16 static/image/common/back.gif
主楼的程序是可以跑,可能要自已调整一下修改一下。
我觉得楼主说空闲时多做几次校正是指叫我们自已添加几 ...

高手~!

fjourdev 发表于 2013-8-18 07:44:45

高手~!
页: [1]
查看完整版本: 用LGT的普通IO成功实现电容触摸