1.RC充放电电路原理:
RC电路充放电公式:
Vt = V0 + (V1-V0)*[1-exp(-t/RC)]
vo为电容的初始电压值:
v1为电容最终可充到或放到的电压值:
vt为t时刻电容上的电压值
结论:同样的条件下,电容值C跟时间值t成正比关系,
电容越大,充电到达某个临界值的时间越长。
原理:RC电路充放没按键时(cs),有一个电容,测出在该情况下达到某一特定电压需要的时间(t1),按下 按键时,多并联了一个电容(cx),电容变大(cs+cx),这时达到某一电压需要的时间(t2)比第一次长,判断(t2-t1)的值是否大于某个值,就能知晓是否按下按键。
2.检测电容触摸按键过程
①TPAD引脚设置为推挽输出,输出0,实现电容放电到0。
②TPAD引脚设置为浮空输入(I0复位后的状态), 电容开始充电。
③同时开启TPAD引脚的输入捕获开始捕获。
④等待充电完成(充电到底Vx,检测到上升沿)。
⑤计算充电时间。
代码
main.c
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "tpad.h"
int main(void)
{
u8 t=0;
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//ÉèÖÃNVICÖжϷÖ×é2:2λÇÀÕ¼ÓÅÏȼ¶£¬2λÏìÓ¦ÓÅÏȼ¶
uart_init(115200); //´®¿Ú³õʼ»¯Îª115200
LED_Init(); //LED¶Ë¿Ú³õʼ»¯
TPAD_Init(6); //³õʼ»¯´¥Ãþ°´¼ü
while(1)
{
if(TPAD_Scan(0)) //³É¹¦²¶»ñµ½ÁËÒ»´ÎÉÏÉýÑØ(´Ëº¯ÊýÖ´ÐÐʱ¼äÖÁÉÙ15ms)
{
LED1=!LED1; //LED1È¡·´
}
t++;
if(t==15)
{
t=0;
LED0=!LED0; //LED0È¡·´,Ìáʾ³ÌÐòÕýÔÚÔËÐÐ
}
delay_ms(10);
}
}
tpad.c
#include "tpad.h"
#include "delay.h"
#include "usart.h"
#define TPAD_ARR_MAX_VAL 0XFFFF //×î´óµÄARRÖµ
vu16 tpad_default_val=0;//¿ÕÔصÄʱºò(ûÓÐÊÖ°´ÏÂ),¼ÆÊýÆ÷ÐèÒªµÄʱ¼ä
//³õʼ»¯´¥Ãþ°´¼ü
//»ñµÃ¿ÕÔصÄʱºò´¥Ãþ°´¼üµÄÈ¡Öµ.
//·µ»ØÖµ:0,³õʼ»¯³É¹¦;1,³õʼ»¯Ê§°Ü
u8 TPAD_Init(u8 psc)
{
u16 buf[10];
u16 temp;
u8 j,i;
TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//ÒÔ1MhzµÄƵÂʼÆÊý
for(i=0;i<10;i++)//Á¬Ðø¶ÁÈ¡10´Î
{
buf[i]=TPAD_Get_Val();
delay_ms(10);
}
for(i=0;i<9;i++)//ÅÅÐò
{
for(j=i+1;j<10;j++)
{
if(buf[i]>buf[j])//ÉýÐòÅÅÁÐ
{
temp=buf[i];
buf[i]=buf[j];
buf[j]=temp;
}
}
}
temp=0;
for(i=2;i<8;i++)temp+=buf[i];//È¡ÖмäµÄ6¸öÊý¾Ý½øÐÐƽ¾ù
tpad_default_val=temp/6;
printf("tpad_default_val:%d\r\n",tpad_default_val);
if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;//³õʼ»¯Óöµ½³¬¹ýTPAD_ARR_MAX_VAL/2µÄÊýÖµ,²»Õý³£!
return 0;
}
//¸´Î»Ò»´Î
void TPAD_Reset(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜPA¶Ë¿ÚʱÖÓ
//ÉèÖÃGPIOA.1ΪÍÆÍìʹ³ö
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1 ¶Ë¿ÚÅäÖÃ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //ÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_1); //PA.1Êä³ö0,·Åµç
delay_ms(5);
TIM_SetCounter(TIM5,0); //¹é0
TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //Çå³ýÖжϱêÖ¾
//ÉèÖÃGPIOA.1Ϊ¸¡¿ÕÊäÈë
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //¸¡¿ÕÊäÈë
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//µÃµ½¶¨Ê±Æ÷²¶»ñÖµ
//Èç¹û³¬Ê±,ÔòÖ±½Ó·µ»Ø¶¨Ê±Æ÷µÄ¼ÆÊýÖµ.
u16 TPAD_Get_Val(void)
{
TPAD_Reset();
while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET)//µÈ´ý²¶»ñÉÏÉýÑØ
{
if(TIM_GetCounter(TIM5)>TPAD_ARR_MAX_VAL-500)return TIM_GetCounter(TIM5);//³¬Ê±ÁË,Ö±½Ó·µ»ØCNTµÄÖµ
};
return TIM_GetCapture2(TIM5);
}
//¶ÁÈ¡n´Î,È¡×î´óÖµ
//n£ºÁ¬Ðø»ñÈ¡µÄ´ÎÊý
//·µ»ØÖµ£ºn´Î¶ÁÊýÀïÃæ¶Áµ½µÄ×î´ó¶ÁÊýÖµ
u16 TPAD_Get_MaxVal(u8 n)
{
u16 temp=0;
u16 res=0;
while(n--)
{
temp=TPAD_Get_Val();//µÃµ½Ò»´ÎÖµ
if(temp>res)res=temp;
};
return res;
}
//ɨÃè´¥Ãþ°´¼ü
//mode:0,²»Ö§³ÖÁ¬Ðø´¥·¢(°´ÏÂÒ»´Î±ØÐëËÉ¿ª²ÅÄÜ°´ÏÂÒ»´Î);1,Ö§³ÖÁ¬Ðø´¥·¢(¿ÉÒÔÒ»Ö±°´ÏÂ)
//·µ»ØÖµ:0,ûÓа´ÏÂ;1,Óа´ÏÂ;
#define TPAD_GATE_VAL 100 //´¥ÃþµÄÃÅÏÞÖµ,Ò²¾ÍÊDZØÐë´óÓÚtpad_default_val+TPAD_GATE_VAL,²ÅÈÏΪÊÇÓÐЧ´¥Ãþ.
u8 TPAD_Scan(u8 mode)
{
static u8 keyen=0; //0,¿ÉÒÔ¿ªÊ¼¼ì²â;>0,»¹²»ÄÜ¿ªÊ¼¼ì²â
u8 res=0;
u8 sample=3; //ĬÈϲÉÑù´ÎÊýΪ3´Î
u16 rval;
if(mode)
{
sample=6; //Ö§³ÖÁ¬°´µÄʱºò£¬ÉèÖòÉÑù´ÎÊýΪ6´Î
keyen=0; //Ö§³ÖÁ¬°´
}
rval=TPAD_Get_MaxVal(sample);
if(rval>(tpad_default_val+TPAD_GATE_VAL))//´óÓÚtpad_default_val+TPAD_GATE_VAL,ÓÐЧ
{
if(keyen==0)res=1; //keyen==0,ÓÐЧ
//printf("r:%d\r\n",rval);
keyen=3; //ÖÁÉÙÒªÔÙ¹ý3´ÎÖ®ºó²ÅÄÜ°´¼üÓÐЧ
}
if(keyen)keyen--;
return res;
}
//¶¨Ê±Æ÷2ͨµÀ2ÊäÈ벶»ñÅäÖÃ
void TIM5_CH2_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM5_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //ʹÄÜTIM5ʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜPA¶Ë¿ÚʱÖÓ
//ÉèÖÃGPIOA.1Ϊ¸¡¿ÕÊäÈë
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1 ¶Ë¿ÚÅäÖÃ
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //ËÙ¶È50MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //¸¡¿ÕÊäÈë
GPIO_Init(GPIOA, &GPIO_InitStructure); //ÉèÖÃΪ¸¡¿ÕÊäÈë
//³õʼ»¯TIM5
TIM_TimeBaseStructure.TIM_Period = arr; //É趨¼ÆÊýÆ÷×Ô¶¯ÖØ×°Öµ
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Ô¤·ÖƵÆ÷
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //¸ù¾ÝTIM_TimeBaseInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
//³õʼ»¯Í¨µÀ2
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 Ñ¡ÔñÊäÈë¶Ë IC2Ó³Éäµ½TI5ÉÏ
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //ÉÏÉýÑز¶»ñ
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //ÅäÖÃÊäÈë·ÖƵ,²»·ÖƵ
TIM5_ICInitStructure.TIM_ICFilter = 0x03;//IC2F=0011 ÅäÖÃÊäÈëÂ˲¨Æ÷ 8¸ö¶¨Ê±Æ÷ʱÖÓÖÜÆÚÂ˲¨
TIM_ICInit(TIM5, &TIM5_ICInitStructure);//³õʼ»¯I5 IC2
TIM_Cmd(TIM5,ENABLE ); //ʹÄܶ¨Ê±Æ÷5
}
tpad.h
#ifndef __TPAD_H
#define __TPAD_H
#include "sys.h"
extern vu16 tpad_default_val;
void TPAD_Reset(void);
u16 TPAD_Get_Val(void);
u16 TPAD_Get_MaxVal(u8 n);
u8 TPAD_Init(u8 psc);
u8 TPAD_Scan(u8 mode);
void TIM5_CH2_Cap_Init(u16 arr,u16 psc);
#endif