24_电容触摸按键实验
目录
RC充电放电电路原理
电容触摸按键原理
检测电容触摸按键过程
硬件连接
实验源码:
RC充电放电电路原理

V1电源当V1没有接通的时候很显然是没有电流经过的,当接通后会给CX电容充电。
RC电路充电放电公式:
Vt = V0+(V1-V0)*[1-exp(-t/RC)]
V0为电容上的初始电压值;
V1为电容最终可充到或放到的电压值;
Vt为t时刻电容上的电压值。
通常情况下 V0都是等于0,如果V0为0,也就是从0V开始充电。那么公式简化为:
Vt = V1*[1-exp(-t/RC)]
同样的条件下,电容值C跟时间值t成正比关系,电容越大,充电到达某个临界值得时间越长。

电容触摸按键原理

R:外接电容充放电电阻。
Cs:TPAD和PCB间的杂散电容
Cx:手指按下时,手指和TPAD之间点电容。
开关:电容放电开关,由STM32IO口代替。
检测电容触摸按键过程
1.TPAD引脚设置为推挽输出,输出0,,实现电容放电到0。
2.TPAD引脚设置为浮空输入(IO复位后的状态),电容开始充电。
3.同时开启TPAD引脚的输入捕获开始捕获
4.等待完成(充电到Vx,检测到上升沿)
5.计算充电时间。
没有按下的时候,充电时间为T1。按下TPAD,电容变大,所以充电时间为T2。我们可以通过检测充电放电时间,来判断是否按下。如果T2-T1大于某个值,就可以判断有按键按下。
TPAD连接的是芯片的引脚, 设置成推挽输出0的时候芯片内部是接地的所以电流是直接通过引脚接地电容就没有电流充电相当于电容在放电,放电完成后,把引脚配成浮空输入,并开启输入捕获,同时开启定时器计数,引脚没接地了,电流会给电容充电,假设我们没有按下的时候是500ms会高电平,当按下后相当于并连了一个电容会充电时间更久假设是1000ms才会有一个高电平,不断计算判断捕获时间就可以判断是否按键按下。
硬件连接

实验源码:
电容触摸按下打印提示语句仅支持单击。
/********************************************************************************* @file : user_rcc_config.c* @brief : V1.00******************************************************************************* @attention********************************************************************************//* Include 包含---------------------------------------------------------------*/
#include "user_rcc_config.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*//*!\brief 定时器初始化\param[in] none\param[in] none\retval none
*/
void Rcc_config(void)
{ /*使能GPIOA时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);/*使能UART1时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);/*使能定时器5时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);}/************************************************************** END OF FILE ****/
/********************************************************************************* @file : user_gpio.c* @brief : V1.00******************************************************************************* @attention********************************************************************************//* Include 包含---------------------------------------------------------------*/
#include "user_gpio.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*//*!\brief GPIO初始化函数\param[in] none\param[out] none\retval none
*/
void Gpio_Init(void)
{ /*GPIO结构体*/GPIO_InitTypeDef GPIO_InitTypeDefstruct;/*UART1发送引脚配置*/GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_9;GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_10MHz;/*写入结构体到GPIOA*/GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);/*UART1接收引脚配置*/GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_10;GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_10MHz;/*写入结构体到GPIOA*/ GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);/*初始化PA1*/GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_1; /*写入结构体到GPIOA*/GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);}/************************************************************** END OF FILE ****/
/********************************************************************************* @file : user_uart.c* @brief : V1.00******************************************************************************* @attention********************************************************************************//* Include 包含---------------------------------------------------------------*/
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/extern uint16_t USART_RX_STA;
extern uint8_t USART_RX_BUF[200];/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/#if 1
#pragma import(__use_no_semihosting)
/*实现Printf代码*/
struct __FILE
{ int handle; };
FILE __stdout; void _sys_exit(int x)
{ x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{ while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;
}
#endif /*!\brief UART1初始化\param[in] none\param[out] none\retval none
*/void Uart1_Init(u32 bound)
{/*UART结构体*/USART_InitTypeDef USART_InitTypeDefstruct;/*UART结构体配置*/USART_InitTypeDefstruct.USART_BaudRate = bound; //波特率USART_InitTypeDefstruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None; //不使用硬件流USART_InitTypeDefstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送接收使能USART_InitTypeDefstruct.USART_Parity = USART_Parity_No; //不使用奇偶校验USART_InitTypeDefstruct.USART_StopBits = USART_StopBits_1; //1个停止位USART_InitTypeDefstruct.USART_WordLength = USART_WordLength_8b; //8个数据位/*写入USART1*/USART_Init(USART1,&USART_InitTypeDefstruct);/*使能串口1*/USART_Cmd(USART1,ENABLE);}/*!\brief UART1中断服务函数\param[in] none\param[out] none\retval none
*/void USART1_IRQHandler(void)
{}/************************************************************** END OF FILE ****/
/********************************************************************************* @file : user_touch_key.c* @brief : V1.00******************************************************************************* @attention********************************************************************************//* Include 包含---------------------------------------------------------------*/
#include "user_touch_key.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
#define TPAD_GATE_VAL 100 //触摸的门限值,大于Touch_Average_Value(电容充电时间)+TPAD_GATE_VAL(触摸按键按下定时器时间),才认为是有效触摸.
/* Variables 变量--------------------------------------------------------------*/
uint16_t Touch_Average_Value = 0; //程序开始,按键没按下的平均值/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*//*!
\brief 复位一次,电容放电\param[in] none\param[in] none\retval none
*/void Touch_Rset(void)
{/*GPIO结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*初始化PA1*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //频率50MHz/*写入GPIOA*/GPIO_Init(GPIOA, &GPIO_InitStructure);/*设置输出为低电平,推挽输出芯片内部接地*/GPIO_ResetBits(GPIOA,GPIO_Pin_1); //PA.1输出0,电容开始放电/*持续5毫秒等待电容放电完成*/delay_ms(5);/*定时器计数归零准备开始计数*/TIM_SetCounter(TIM5,0); /*虽然没开中断但是事件发生标志位是会变化的*/TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志/*此时设成浮空输入,电容充电,定时器在上面开始计数了会有点误差可忽律不记,欧姆定律 P功率 = U电压I电流,电压和电流是成反比,当电容充电的时候电流大,电压小,低电平,充电完成高电平输入捕获高电平*/GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入/*写入GPIOA*/GPIO_Init(GPIOA, &GPIO_InitStructure);
}/*!\brief 获取一次触摸按键按下定时器时间\param[in] none\param[in] none\retval
*/
uint16_t Touch_Get_Value(void)
{/*先复位获取准确的值*/Touch_Rset();/*等待捕获到上升沿*/while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET)//等待捕获上升沿{ /*判断是否超时预留500us*/if(TIM_GetCounter(TIM5)>0xFFFF-500){return TIM_GetCounter(TIM5);}} /*没超时返回捕获比较器2的值*/return TIM_GetCapture2(TIM5);
}/*!\brief 初始化触摸按键\param[in] 装载值\param[in] 分频系数\retval 0初始化成功,1初始化失败
*/
uint8_t Touch_Key_Init(uint8_t psc)
{/*初始化取10次没有按下电容充电时间值buf*/uint16_t Touch_Value[10];/*冒泡排序变量*/uint16_t i ,j,temp;/*初始化定时器5计数值为0xffff,1MHz计数以个时钟周期为1us*/Tim5_Input2_Init(0xFFFF,psc-1);/*程序初始化先获取10电容时间,后求平均值,作为没有按下的时间标准*/for(i=0;i<10;i++){ Touch_Value[i]=Touch_Get_Value();delay_ms(10); }/*冒泡排序*/for(i=0;i<9;i++){for(j=i+1;j<10;j++){if(Touch_Value[i]>Touch_Value[j])//升序排列{temp=Touch_Value[i];Touch_Value[i]=Touch_Value[j];Touch_Value[j]=temp;}}}temp = 0;/*取中间的6个数据进行平均*/for(i=2;i<8;i++){temp+=Touch_Value[i];}/*平均值获取*/Touch_Average_Value = temp/6;/*打印平均值*/printf("电容充电时间Touch_Average_Value:%dus\r\n",Touch_Average_Value); /*判断是不是有超时,除2是电容充电不会辣么长*/if(Touch_Average_Value>0xFFFF/2){return 1;//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常!}return 0; //初始化成功}/*!\brief 读取n次,取最大值\param[in] 读取次数\param[in] none\retval 最大值
*/
uint16_t Touch_Get_Value_Max(uint8_t n)
{u16 temp=0;u16 res=0;while(n--){temp=Touch_Get_Value();//得到一次值if(temp>res){res=temp;}};return res;
} /*!\brief 扫描触摸按键\param[in] none\param[in] none\retval 返回1证明有按键按下
*/uint8_t Touch_Scan(void)
{static u8 keyen=0; //0,可以开始检测;>0,还不能开始检测 u8 res=0;u8 sample=3; //默认采样次数为3次 u16 rval;/*取3次中最大的值*/rval=Touch_Get_Value_Max(sample); /*Touch_Average_Value+TPAD_GATE_VAL,有效*/if(rval>(Touch_Average_Value+TPAD_GATE_VAL)){ if(keyen==0){res=1; //keyen==0,有效} /*1次有效后进入扫描2次之后才能按键有效 因为程序是一直轮迅的,当我们一直长按的时候,第一个if一直会成立keyen=2,继续执行-1,下次进来keyen还是等于1就判断还是一直按下去的如此反复,只支持单按*/keyen=2; } if(keyen)keyen--; return res;
} /************************************************************** END OF FILE ****/
/********************************************************************************* @file : user_mian.h* @brief : V1.00******************************************************************************* @attention********************************************************************************//* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_timer.h"
#include "user_touch_key.h"/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
//最多一次接收200个字节
uint8_t USART_RX_BUF[200];
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
uint16_t USART_RX_STA=0; //接收状态标记 /* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/int main(void){ /*延时函数初始化*/delay_init();/*RCC配置*/Rcc_config();/*GPIO初始化*/ Gpio_Init();/*USART1初始化*/Uart1_Init(9600);/*定时器5初始化*/Touch_Key_Init(7-1); //以1Mhz的频率计数 计数器从0计数到FFFF才会溢出 一个时钟周期就是1us/*死循环*/ while(1){/*扫描按键是否按下*/if(Touch_Scan()){printf("按键按下\r\n"); }} }/************************************************************** END OF FILE ****/
实验现象

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
