16.电容触摸按键

1.电容触摸按键介绍:

  • R是外接的充电电阻, Cs是没有触摸按下的触摸感应区和四周覆铜区域的一个杂散的电容;当使用手指去触摸感应区时,手指和感应区形成一个电容Cx,开关是电容放电的一个开关,在实际设计中是利用单片机IO口来替代这个开关,实现放电的功能;
  • 当开关闭合时,有触摸按下时,Cx和Cs的值通过开关形成了一个回路,将上面的电释放掉。然后再断开开关,断开开关后Cs不能放电,通过Vcc经过R给Cs或Cx电容进行充电,当没有手指时只有Cs这个电容,充电曲线如图A所示;
  • 当充电完成到达Vth时,所花费的时间为Tcs,如果当有手触摸时,此时充电的时间曲线为B,B充满电所需的时间是Tcs+Tcx的时间,可以利用充电时间来判断有没有触摸按下,有触摸按下时间大于Tcs;
  • 定时器有输入捕获功能,可以通过捕获它的上升沿,当充电完成就来了一个高电平,从低一直慢慢充到满,捕获到上升沿有一段时间,当捕获到的时间与现在(Tcs+Tcx)时间进行比较,如果按键没有按下,它有一个充电时间,当有手触摸到感应区,手指跟感应区会形成一个电容,根据电容的并联关系它的两个值是累加的,电容变大则充电时间变大;
  • Vc:电容的电压、V0:充电的电压、R:充电的电阻、T:充电的时间;
  • 使用定时器5通道2,对于PA1管脚配置为推挽输出模式,让PA1输出为低电平,输出低电平相当于这个开关闭合,闭合的时候Cx+Cs两个电容的并联值,就会形成一个放电的回路,把电释放干净,当释放干净之后的一段时间再让PA1配置为浮空输入模式,相当于开关断开,利用外部的电源经过充电电阻,给电容充电,可以利用定时器的输入捕获功能来捕获上升沿的时间,根据这个时间和手按下和没有按下的时间进行对比,首先得到手没有按下时捕获到一次上升沿时间,这是一个参考有没有按下的基准,当手按下再次捕获则时间大于Tcs,在软件设计时,通常设置一个检测的阀值,假设为t,该值可以根据实际调试。

2.电容触摸按键实验:

通过TIM5的通道2(PA1)捕获电容触摸按键输入信号的高电平脉宽,根据捕获到高电平时间大小控制LED1指示灯开关,通过LED0指示灯不断闪烁表示系统正常运行。 

(1)原理图:      

 

(2)主函数:

#include "delay.h"
#include "led.h"
#include "usart1.h"
#include "touch.h"



int main(){
    
    u8 i=0;                                          
    u32 indata=0;                                        //累计整个从上升沿到下降沿的次数
   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //设置分组
    delay_init();                                        //延时初始化
    LED_Init();  
    usart1_Init(9600);                                   //串口通信初始化
    Touch_Key_Init(6);                                   //电容按键进行初始化->12MHz
   
    while(1){
       if(Touch_Key_Scan(0)==1)
       {
          LED1=!LED1;      //检测到有触摸按键按下
       }
       
       i++;
       if(i%20==0)
       {
          LED0=!LED0;
       }

        delay_ms(20);
    }       
}

(3)头文件:

#ifndef __TOUCH_H
#define __TOUCH_H

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int  u32;

void TIM5_CH2_Input_Init(u16 arr,u16 psc);  //定时器5通道2,输入捕获初始化
void Touch_Reset(void);                     //将电容上的电释放
u16 Touch_Get_Val(void);                    //读取输入捕获上升沿的值
u8 Touch_Key_Init(u8 psc);                  //对电容按键进行初始化
u16 Touch_Get_MaxVal(u8 n);                 //得到最大采集值
u8 Touch_Key_Scan(u8 mode);                 //检测触摸按键是否按下


#endif

(4)电容触摸按键功能函数:

#include "stm32f10x.h"
#include "stdio.h"
#include "delay.h"
#include "touch.h"



/*
   功能:定时器5通道2,配置输入捕获
   变量:arr:自动重装载值  psc:预分频系数
   返回值:无
*/
void TIM5_CH2_Input_Init(u16 arr,u16 psc)
{
   GPIO_InitTypeDef GPIO_InitStruct;
   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
   TIM_ICInitTypeDef TIM_ICInitStruct;
   
   
   //1.使能定时器时钟和端口时钟,并设置引脚模式;
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   
   //配置端口参数
   GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;      //浮空输入
   GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;                  //PA1
   GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;         
   GPIO_Init(GPIOA,&GPIO_InitStruct);
   
   //2.初始化定时器参数;
   TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;         //1分频
   TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;     //向上计数模式
   TIM_TimeBaseInitStruct.TIM_Period=arr;                         //自动重装载值
   TIM_TimeBaseInitStruct.TIM_Prescaler=psc;                      //预分频系数
   TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);
   
   //3.设置通用定时器的输入捕获参数,开启输入捕获功能;
   TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;                    //通道2
   TIM_ICInitStruct.TIM_ICFilter=0x00;                            //不使用滤波
   TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;         //捕获极性为上升沿捕获
   TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;               //1分频             
   TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;     //直接映射
   TIM_ICInit(TIM5,&TIM_ICInitStruct);
   
   //4.开启定时器
   TIM_Cmd(TIM5,ENABLE);
   
}


/*
   功能:将电容上的电释放 
   变量:无
   返回值:无
*/
void Touch_Reset(void)
{
   //1.设置端口模式
   GPIO_InitTypeDef GPIO_InitStruct;
   GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     //推挽输出
   GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;            //PA1
   GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
   GPIO_Init(GPIOA,&GPIO_InitStruct);
   
   //2.放电
   GPIO_ResetBits(GPIOA,GPIO_Pin_1);
   delay_ms(20);
   
   //3.清除标志位
   TIM_ClearFlag(TIM5,TIM_FLAG_Update|TIM_FLAG_CC2);     
   
   //4.当放电完成时,将定时器的cnt(计数值)进行清零
   TIM_SetCounter(TIM5,0);
   
   //5.等待充电过程,将PA1配置为浮空输入模式,等待充电电阻进行充电
   GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;      //浮空输入模式
   GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;                  //PA1
   GPIO_Init(GPIOA,&GPIO_InitStruct);     
    
}


/*
   功能:读取输入捕获上升沿的值,一般不会有溢出事件
   变量:无
   返回值:输入捕获的值
*/

#define TOUCH_ARR_MAX_VAL 0xffff      //定义计数器的最大值
#define TOUCH_GATA_VAL  100           //设置的阀值标志
u16 Touch_Get_Val(void)
{
   //1.对电容进行放电
   Touch_Reset();
   
   //2.获取输入捕获的值
   while(TIM_GetFlagStatus(TIM5,TIM_FLAG_CC2)==0)     //捕获中->捕获未完成
   {
      if(TIM_GetCounter(TIM5)>(TOUCH_ARR_MAX_VAL-TOUCH_GATA_VAL)) //获取到输入捕获的值是否大于阀值->这里表示超过了阀值
      {
         return TIM_GetCounter(TIM5);                 //返回当前计数器的值 
         
      } 
   }
   return TIM_GetCapture2(TIM5);                      //返回通道2的捕获值
   
}


/*
   功能:对电容按键进行初始化
   变量:psc:预分频系数
   返回值:返回1:不正常    返回0:正常
*/

u16 TOUCH_DEFAULT_VAL=0;
u8 Touch_Key_Init(u8 psc)
{
   u8 i=0,j=0;
   u16 buf[10];
   u32 sum=0;
   
   TIM5_CH2_Input_Init(TOUCH_ARR_MAX_VAL,psc);        //对输入捕获进行初始化
   
   for(i=0;i<10;i++)
   {
      buf[i]=TOUCH_GATA_VAL;                          //进行十次输入捕获,将每次输入捕获到的值存放在buf数组中
      delay_ms(10);
   }
   
   //进行滤波防止干扰,去掉最大和最小值
   for(i=0;i<10-1;i++)
   {
      for(j=0;j<10-i-1;j++)
      {
         if(buf[j]>buf[j+1])
         {
            u8 temp=0;
            temp=buf[j];
            buf[j]=buf[j+1];
            buf[j+1]=temp;
            
         } 
      }
   }
   
   for(i=1;i<9;i++)
   {
     sum+=buf[i];
   }
   
   //得到平均的输入捕获值
   TOUCH_DEFAULT_VAL=sum/8;
   
   printf("输入捕获滤波后的值:%d\r\n",TOUCH_DEFAULT_VAL);
   
   //判断捕获是否正常
   if(TOUCH_DEFAULT_VAL>TOUCH_ARR_MAX_VAL/2)       //不正常
   {
      return 1;
   }
   
   return 0;                                       //正常
   
}


/*
   功能:获取最大采集值
   变量:n:采集次数
   返回值:最大采集值
*/
u16 Touch_Get_MaxVal(u8 n)
{
   u16 temp=0;
   u16 result=0;     //存储最大采集值
   
   while(n--)     //采集的次数
   {
      temp=Touch_Get_Val();
      if(temp>result)
      {
         result=temp;
      } 
   }
   return result;
   
}


/*
   功能:检测触摸按键是否按下
   变量:mode=0:单次扫描    mode=1:连续扫描
   返回值:返回1:触摸有效   返回0:触摸无效
*/
u8 Touch_Key_Scan(u8 mode)
{
   u8 sample=5;         //设置采样次数
   u16 rval=0;          //存储最大值
   static u8 key=0;     //设置单次和连续按下的标志
   u8 result=0;
   
   if(mode==1)          //当设置为连续按下时,将key一直处于没有被按下的标志
   {
      key=0;
   }
   
   rval=Touch_Get_MaxVal(sample);    //获取最大采集值
   
   //采集的最大值与默认值相比较
   if(rval>(TOUCH_DEFAULT_VAL+TOUCH_GATA_VAL)&&(10*TOUCH_DEFAULT_VAL))     //触摸有效
   {
      if((key==0)&&(rval>(TOUCH_DEFAULT_VAL+TOUCH_GATA_VAL)))
      {
         result=1;
      }
   }
   else     //触摸无效
   {
      key=0;
   }
   
   return result;    //触摸无效
   
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jhan&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值