winnie 发表于 2009-5-5 16:05:53

PIC16F84A实现非接触式电容触摸感应试验成功

说到电容非接触摸技术相信大家并不陌生......
   由于人体就是导体,通过大地回路形成一个很小的电容.在人体接近感应区域时,人体电容和IO口内部的电容并联,可以通过RC充电方式测量出这个电容,在人体没有接近时,只有IO口内部电容,通过软件处理后可识别是否有人体接近... 由于电容很小,所以电阻要很大才行,现在这里用4M7的电阻.......

那就费话少说.....直接上图...上源代码.....

//引入头文件*********************************************************
#include   "delay.h"
#include   "delay.c"
#include      <pic1684.h>
//感应输入***********************************************************
#define       RcIn      RA3                              //感应输入
//输出定义***********************************************************
#define       RcSu      TRISA3                           //方向输出设置   
//公用变量***********************************************************
   unsigned char follow;                                 //跟踪校准

//*******************************************************************
//函数名字; PortInit();
//输入参数; 无
//输出参数; 无
//功能描述; 端口设置
//建造日期; 2008年08月14日
//*******************************************************************
void PortInit(void)
{
   PORTA = 0x00;                                       //   
   PORTB = 0x00;                                       //
   TRISA = 0xff;                                       //A 口设置   
   TRISB = 0x00;                                       //B 口设置
}

//*******************************************************************
//函数名字; DischargeOut();
//输入参数; 无
//输出参数; 无
//功能描述; 电容放电
//建造日期; 2008年08月14日
//*******************************************************************
void DischargeOut(void)
{
   RcIn = 1;                                             //置高电平
   RcSu = 0;                                             //开始放电
   asm("nop");                                           //放电时间
asm("nop");                                           //精确 5uS
asm("nop");
asm("nop");
asm("nop");
}

//*******************************************************************
//函数名字; SurveyRc();
//输入参数; 无
//输出参数; 无
//功能描述; 测量充电时间
//建造日期; 2008年08月14日
//*******************************************************************
unsigned char SurveyRc(void)
{
   unsigned char time = 0;                               //时间计数
   
DischargeOut();                                       //电容放电
   
RcSu = 1;                                             //高阻输入
   
while (RcIn)                                          //充电计时
   {
    time++;                                             //计时增加
    asm("nop");                                       //精确10uS
   
    if (time > 250) break;                              //最大限时                  
      }
   
   return time;                                          //返回时间
}

//*******************************************************************
//函数名字; DataAdd(*buffer, size);
//输入参数; 缓冲区首址, 大小
//输出参数; 数据总和
//功能描述; 缓冲区所有数据相加
//建造日期; 2008年08月14日
//*******************************************************************   
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;                                 //数据相加
      }

   return add;                                           //返回总和                  
}
//*******************************************************************
//函数名字; DataMax(*buffer, size);
//输入参数; 缓冲区首址, 大小
//输出参数; 数据最大值
//功能描述; 选出缓冲区最大值
//建造日期; 2008年08月14日
//*******************************************************************
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;               //对比最大
      }

   return max;                                           //最大数据                  
}
//*******************************************************************
//函数名字; DataMin(*buffer, size);
//输入参数; 缓冲区首址, 大小
//输出参数; 数据最小大值
//功能描述; 选出缓冲区最小值
//建造日期; 2008年08月14日
//*******************************************************************
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;               //对比最小
      }

   return min;                                           //最小数据
}
//*******************************************************************
//函数名字; DataEqually(idend, isor);
//输入参数; 被除数,除数
//输出参数; 平均值
//功能描述; 数据平均
//建造日期; 2008年08月14日
//*******************************************************************
unsigned char DataEqually(unsigned int idend, unsigned char isor)
{
   return (idend / isor);                              //数据平均
}

//*******************************************************************
//函数名字; FilterData();
//输入参数; 无
//输出参数; 平均值
//功能描述; 取样平均滤波
//建造日期; 2008年08月14日
//*******************************************************************
unsigned char FilterData(void)
{
   unsigned char i, max, min, data;
   unsigned int sum;

   for (i = 0; i < 5; i++)
   {
    data = SurveyRc();                               //收集数据
      }
   
   sum = DataAdd(data, 5);                               //数据相加
   max = DataMax(data, 5);                               //取最大值
   min = DataMin(data, 5);                               //取最小值
   return (DataEqually((sum - max - min), 3));         //取平均值               
}   

//*******************************************************************
//函数名字; KeyState();
//输入参数; 无
//输出参数; 无
//功能描述; 按键处理
//建造日期; 2008年08月14日
//*******************************************************************
void KeyState(void)
{
   static unsigned char release = 0;                     //释放记数
   static unsigned char count = 0;                     //按下记数
static unsigned char valid = 0;                     //有效标志
static unsigned char reach = 0;                     //长按标志
static unsigned char trail = 0;                     //跟踪记数

if (valid == 1)                                       //是否有效
   {
    if (FilterData() > follow)                        //按键按下
   {
   release = 0;                                    //释放清零
   
   if (reach == 0)                                 //长按无效
    {
   if (++count > 5)                              //防误处理
      {
    reach = 1;                                    //长按置位
    PORTB ^= (1 << 7);                            //取反输出
   }
    }
}

    else if (++release > 5)                           //释放记数
{
   valid = 0;                                        //有效清零
   reach = 0;                                        //长按清零
   count = 0;                                        //记数清零
}
   }

else
   {
    if (FilterData() > follow)
   {
   trail = 0;                                        //数据清零
      valid = 1;                                        //有效置位   
   }
   
    else
   {
      if (++trail > 200)                              //漂移跟踪
    {
   follow = FilterData();                        //更新误差
   PORTB ^= (1 << 6);                              //跟踪指示
   trail = 0;                                    //数据清零
    }
   }
   }   
}
   
//*******************************************************************
//函数名字; main();
//输入参数; 无
//输出参数; 无
//功能描述; 主程序
//建造日期; 2008年08月14日
//*******************************************************************
void main(void)
{      
PortInit();                                           //端口设置
follow = FilterData();                              //读取误差
         
   while (1)
      {
    KeyState();                                       //按键处理
    DelayMs(5);                                       //定时扫描
      }   
}


    该版本软件对按键按下,释放的时间进行优化,响应时间更快,在试验时没有出现误动作.......在连续2S没有检测到按键,就自动更新校准参数...实现自动跟踪漂移...在宽电压范围内都可正常工作....欢迎大家进行公测试验.....提供改进建议...
页: [1]
查看完整版本: PIC16F84A实现非接触式电容触摸感应试验成功