16.电容触摸按键

news2024/11/27 8:32:21

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;    //触摸无效
   
}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/722190.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu 22.04.2 LTS LTS x86_64 安装 stable-diffusion-webui 【2】基本版本完结。

前篇 Ubuntu 20.04 LTS x86_64 安装 stable-diffusion-webui_hkNaruto的博客-CSDN博客 内容太多&#xff0c;分第二篇继续 中途重装了机器&#xff0c;20.04 &#xff0c;apt upgrade后自动升级到22.04.2 现状&#xff1a;起来了&#xff0c;又没完全起来 启动日志 (stab…

如何在 Linux 中将本地网络 IP 设置为静态的

文章目录 对于普通的 Linux 操作系统对于 Red Hat Enterprise Linux 9 笔者的运行环境&#xff1a; CentOS 8 Red Hat Enterprise Linux 9 在 Linux 中将本地网络 IP 设置为静态的&#xff0c;只需要在那台 Linux 上设置即可。为了方便&#xff0c;这里笔者使用了 Xshell 来远…

手写操作系统--主引导扇区以及内核加载器

在CPU上电后&#xff0c;会自动将cs:ip置为f000:fff0,下图就是一个计算机刚上电的模拟&#xff1a; ffff00这里开始的代码是BIOS自检&#xff0c;检查计算机的硬件完备性&#xff0c;做完这一切后将第一个扇区的内容复制到0x7c00的位置&#xff0c;并从0x7c00位置执行代码&…

第五章 逻辑回归

第五章 逻辑回归 Logistic回归的⼀般过程 收集数据&#xff1a;采⽤任意⽅法收集数据。准备数据&#xff1a;由于需要进⾏距离计算&#xff0c;因此要求数据类型为数值型。另外&#xff0c;结构化数据格式则最佳。分析数据&#xff1a;采⽤任意⽅法对数据进⾏分析。训练算法&…

Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分

目录 341. 扁平化嵌套列表迭代器 Flatten Nested List Iterator &#x1f31f;&#x1f31f; 343. 整数拆分 Integer Break &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/…

vscode工作区实现机制

工作区是编辑器的重要部分&#xff0c;它承载着编辑器和本地文件的连接&#xff0c;对文件增、删、改、查。下面我会介绍vscode工作区的创建。同样我们知道vscode软件打开的时候没有默认工作区&#xff0c;这里我对它进行了改造&#xff0c;软件启动时指向默认工作区。 工作区目…

提高腾讯QQ(电脑版)语音通话、视频聊天和远程协助的稳定性的方法

一、背景说明 腾讯QQ默认使用的通讯协议是UDP。但是各大运营商将UDP的优先级设置为最低&#xff0c;导致UDP数据包经常被丢弃。导致腾讯QQ在语音通话、视频聊天和远程协助的时候&#xff0c;会出现连接不上、卡顿和断线&#xff0c;非常不稳定。我们可以手动将通讯协议调整为TC…

用Python实现自动化交易:从趋势到收益

在现代金融市场中&#xff0c;自动化交易已经成为越来越流行的一种方式。相比于传统的手工交易方式&#xff0c;自动化交易更加高效、精准、快速且免除了人为因素的影响。而Python作为一种高级编程语言&#xff0c;凭借其简单易学、灵活性强的优势逐渐成为自动化交易中最受欢迎…

Ubuntu下Go语言TCP广播服务器实现

最近在学习Go语言网络编程&#xff0c;突然想到很久以前的用C语言写过的TCP广播聊天程序&#xff0c;然后就用Go尝试写了一遍&#xff0c;在此做个记录。 目录 1.广播结构 2.实现效果 3.源码 4.Go语言学习参考网站 1.广播结构 2.实现效果 服务器&#xff1a; 客户端1&…

小程序 web-view h5页面背景音乐自动播放

/*** 年度账单-登录首页*/ import React,{useEffect} from react import swiper/swiper-bundle.min.css import styles from ./styles.less import bgm from ./bgm2.mp3 // 主体 const annualAccountLoginIndex (props) > {const goAnnualAccount ()>{const {location: …

Java Web Tomcat 23.7.5

Tomcat 1, Tomcat 1.1 简介 1.1.1 什么是Web服务器 Web服务器是一个应用程序&#xff08;软件&#xff09;&#xff0c;对HTTP协议的操作进行封装&#xff0c;使得程序员不必直接对协议进行操作&#xff0c;让Web开发更加便捷。主要功能是"提供网上信息浏览服务"…

[Python系列] Python虚拟环境Virtualenv

1. 什么是Virtualenv Python virtualenv 是一个用于创建和管理虚拟环境的工具。它可以帮助开发者在不同的项目中使用不同的 Python 版本和包&#xff0c;而不会相互干扰。使用 virtualenv&#xff0c;可以轻松地创建一个独立的 Python 环境&#xff0c;在其中安装所需的包和版本…

【网络】思科网络vlan配置+单臂路由

文章目录 前言一、vlan&#xff08;虚拟局域网&#xff09;二、配置vlan配置交换机0配置交换机1&#xff08;和交换机0相同&#xff09;配置计算机&#xff1a;测试联通性 三、单臂路由配置R0配置交换机1测试配置&#xff1a; 前言 VLAN&#xff08;Virtual Local Area Networ…

力扣 491. 递增子序列

题目来源&#xff1a;https://leetcode.cn/problems/non-decreasing-subsequences/description/ 回溯三部曲&#xff08;来源代码随想录&#xff09;&#xff1a; 递归函数参数&#xff1a;求子序列&#xff0c;很明显一个元素不能重复使用&#xff0c;所以需要startIndex&…

2023年 vue使用腾讯地图搜索、关键字输入提示、地点显示

先看结果 vue 在public文件下的index.html文件中引入&#xff1a; <script src"//map.qq.com/api/js?v2.exp&key你自己的key"></script><script src"https://map.qq.com/api/gljs?v1.exp&librariesservice&key你自己的key"&…

【保姆级教程】PyCharm通过SSH远程连接ModelArts

文章目录 一、创建Notebook二、配置SSH三、配置远程Python解释器四、成果展示 一、创建Notebook 首先&#xff0c;找到云资源下面的 ModelArts&#xff0c;然后点击并进入 ModelArts控制台。 在ModelArts控制台中&#xff0c;点击开发环境下的 Notebook 。然后点击创建&#x…

记录一次Nginx日志偶现499的排查

背景 查看到nginx日志在整点整分的时候频繁出现 499&#xff0c;因为配置了存活检查和就绪检查&#xff0c;担心业务会出现大面积重建导致现网故障&#xff0c;所以对出现499的原因进行排查&#xff0c;记录下排查思路&#xff0c;方便以后查看。 业务链路&#xff1a; 负载均…

B/S版手术麻醉系统源码,基于php、mysql和vue2开发

手术麻醉系统是一套以数字形式与医院信息系统&#xff08;如HIS、EMR、LIS、PACS等&#xff09;和医疗设备等软、硬件集成并获取围手术期相关信息的计算机系统&#xff0c;其核心是对围手术期患者信息自动采集、储存、分析并呈现。该系统通过整合围手术期中病人信息、人员信息、…

Packet Tracer – 研究 NAT 操作

Packet Tracer – 研究 NAT 操作 目标 第 1 部分&#xff1a;通过内联网研究 NAT 操作 第 2 部分&#xff1a;研究互联网中的 NAT 操作 第 3 部分&#xff1a;执行进一步研究 拓扑图 场景 帧通过网络时&#xff0c;MAC 地址可能更改。 当数据包由配置了 NAT 的设备转发时&…

转录组和蛋白组如何关联分析?先从绘制九象限图开始

转录组和蛋白组如何关联分析&#xff1f;先从绘制九象限图开始 五种常用蛋白质组学定量分析方法对比 - 知乎 (zhihu.com) 九象限图在多组学关联分析中非常重要&#xff0c;例如我们可以用九象限图展示“转录组蛋白组”、“转录组翻译组”等关联分析中不同基因的差异表达情况。…