STM32学习和实践笔记(32):电容触摸按键实验

1.电容触摸按键原理介绍

  触摸按键与传统的机械按键相比,不仅美观而且耐用、寿命长,它颠覆了传统意义上的机械按键控制,只要轻轻触摸,就可以实现按键开关的控制、量化调节甚至方向控制。触摸按键已广泛应用于手机、DVD、洗衣机等消费类电子产品中。本章我们就介绍一种简单的触摸按键:电容式触摸按键。

我们PZ6806D开发板上的电容触摸按键其实就是一小块覆铜区域,也称之为触摸感应区。

  通常我们会将四周的铜片与电路板地信号连通,触摸感应区设计成方便手指触摸大小,并将其连接在输入捕获通道上。  

触摸感应区与四周的铜片区域就形成了一个电容,通过检测电容充放

电时间即可判断是否有触摸。实现原理

电容充放电公式:Vc=V0*(1-e^(-t/RC))

在上图中,R是外接电阻,开关就是STM32管脚的内部开关。CS是触摸感应区与电路板GND之间的杂散电容。当手指按到触摸区时,等于增加了一个CX电容并到CS上,所以电源通过RC对电容的充电时间就会变长。

本实验中,使用TIM5的通道2(PA1管脚)来检测触摸按键是否按下。具体步骤是:

1)在每次检测前,我们需要先将电容Cs(或 Cs+Cx)放电,即配置PA1引脚为推挽输出模式,输出一个低电平,才能使电容放电。这等效于上图中的开关闭合。

2)然后配置PA1 为浮空输入模式,利用外部上拉电阻给电容 Cs(Cs+Cx)充电,同时开启TIM5_CH2的输入捕获,配置极性为上升沿,当检测到上升沿的时候,就认为电容充电完

成了,完成一次捕获检测  每次系统重启时,我们执行一次捕获检测(可认为没有触摸),记录此时捕获到上升沿时,需要多少时间即TCS的值。

3)在后续的捕获检测中,即不断重复上面的第1步和第2步,我们就可以通过与记录的值进行对比,判断是否发生触摸。很明显,如果没有发生触摸,每次捕获发生的时间是基本上相等的,如果有触摸,那么时间必然明显延长。这样,就知道了是否发生触摸了

这就是电容触摸工作的原理!搞清楚了就很简单。

2.编写电容触摸按键控制程序

  本实验所要实现的功能是:通过TIM5的通道2(PA1)捕获电容触摸按键输入信号的高电平脉宽,根据捕获到的高电平时间长短,来判断是否有按键按下,如果有按下,则翻转D2指示灯的状态以提示检测到了一次按下。同时D1指示灯不断闪烁表示系统正常运行。程序框架如下:

(1)初始化PA1管脚为TIM5通道2输入捕获功能,设置上升沿捕获等

(2)读取一次捕获高电平的值

(3)电容触摸按键初始化

(4)检测电容触摸按键是否按下

(5)编写主函数

main.c

#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "usart.h"
#include "input.h"
#include "touch_key.h"int main()
{u8 i=0;SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组LED_Init();USART1_Init(9600);Touch_Key_Init(6);//72M 6分频后12Mwhile(1){if((Touch_Key_Scan(0)==1))//判断触摸是否有效{led2=led2;//有效则翻转指示灯}i++;if(i%20 ==0){led1=!led1;//LED1闪,用来指示主程序循环是否运行}delay_ms(50);}
}

touch_key.c

#include "touch_key.h"
#include "SysTick.h"
#include "usart.h"#define Touch_ARR_MAX_Value 0xffff
u16 touch_default_value =0;void TIM5_CH2_Input_Init(u16 period,u16 prescaler)
{GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//结构体变量声明TIM_ICInitTypeDef TIM_ICInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5时钟GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	//GPIO_Init(GPIOA,&GPIO_InitStructure);TIM_TimeBaseInitStructure.TIM_Period=period;   //装入函数传过来的自动装载值TIM_TimeBaseInitStructure.TIM_Prescaler=prescaler; //装入函数传过来的分频系数TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//1分频(没有分频)TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式:从0开始计数到自动重载值后溢出产生中断TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);//初始化TIM5各参数:自动重装值、分频系统、计数方式等TIM_ICInitStructure.TIM_Channel=TIM_Channel_2; //通道2TIM_ICInitStructure.TIM_ICFilter=0x00; //无滤波TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性设为上升沿TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1TIM_ICInit(TIM5,&TIM_ICInitStructure);TIM_Cmd(TIM5,ENABLE );//使能定时器}void Touch_Reset()
{GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; 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);//将IO口输出低电平以将触摸按键的电容放电delay_ms(5);TIM_ClearFlag(TIM5,TIM_FLAG_Update|TIM_FLAG_CC2);//清除定时器的状态标志TIM_SetCounter(TIM5,0); //设定定时器初值为0以重新计数GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//重新改为浮空模式以对电容充电GPIO_Init(GPIOA,&GPIO_InitStructure);}u16 Touch_Get_Value()
{Touch_Reset();while(TIM_GetFlagStatus(TIM5,TIM_FLAG_CC2)==0)//{if(TIM_GetCounter(TIM5)>Touch_ARR_MAX_Value-500){return TIM_GetCounter(TIM5);//如果没有发生捕获事件,计数器计到最大值-500后返回当前计数器的值}}return TIM_GetCapture2(TIM5);//如果发生了捕获事件,则返回捕获发生时的计数器值}u8 Touch_Key_Init(u8 psc)
{u8 i,j;u16 buf[10];u16 temp;TIM5_CH2_Input_Init(Touch_ARR_MAX_Value,psc);//定时器5通道2输入捕获初始化for (i=0; i<10;i++){buf[i]= Touch_Get_Value();//得到10个值delay_ms(10);}//将得到的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;}}//去掉最小的两个,去掉最大的两个,余下的6个取平均值temp=0;for(i=2; i<8;i++){temp+=buf[i];}touch_default_value = temp/6;printf("touch_default_value=%d\r\n",touch_default_value);if(touch_default_value>touch_default_value/2)//这个判断条件是通过实际调试测试决定的return 1;//如果这个值大于最大值的一半,也就对应前面的没有发生捕获的情况,那么认为初始化失败//返回1 表明初始化失败return 0; //返回0表示初始化成功,得到了没有触摸时的缺省充电时间}u16 Touch_Get_MaxVal(u8 n)//得到n次捕获中的最大值
{u16 temp=0;u16 max=0;while(n--){temp=Touch_Get_Value();if(temp>max)max=temp;}return max;}//mode =0 单次扫描,mode =1,连续扫描
//返回Touch_Status,其值为1则表示触摸有效
#define TOUCH_GATE_VAL 100
u8 Touch_Key_Scan(u8 mode)
{u8 Touch_Status;u8 sample =3;u16 MaxVal =0;static u8 keyen =0;if(mode)//mode如为1,则表示连续扫描,因此,每次调用Touch_Key_Scan时都将keyen=0,所以每次都能得到触摸值{				//反之,因为keyen后续=3,所以需要三次之后,才能降为0,才能得到触摸值sample =6;keyen=0;}MaxVal=Touch_Get_MaxVal(sample);//得到三次采样中的最大值if(MaxVal>(touch_default_value+TOUCH_GATE_VAL)&&MaxVal<(10*touch_default_value)){if((keyen==0)&&(touch_default_value+TOUCH_GATE_VAL)){Touch_Status=1;}}printf("触摸后捕获高电平值为:%d\r\n",MaxVal);keyen=3;if(keyen) keyen--;return Touch_Status;}

   touch_key.h

#ifndef _touch_key_H
#define _touch_key_H#include "system.h"void TIM5_CH2_Input_Init(u16 period,u16 prescaler);
u8 Touch_Key_Init(u8 psc);
u8 Touch_Key_Scan(u8 mode);#endif

这个程序因为只能在PZ6806D开发板上才可以运行,而我手上的是PZ6806L,所以没有实际烧录测试,但原理我是完全理解的。

因此,如果在PZ6806L上接出一块小的触摸板,这实验是可以做成功的,这没有什么疑问。

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

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

相关文章

宿舍管理系统带文档java项目基于springboot+vue的宿舍管理系统

文章目录 宿舍管理系统一、项目演示二、项目介绍三、八千字项目文档四、部分功能截图五、部分代码展示六、底部获取项目源码和8000字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 宿舍管理系统 一、项目演示 宿舍管理系统 二、项目介绍 基于springbootvue的前后端分…

MVC、MVP 和 MVVM 架构总结

MVC、MVP 和 MVVM 是常见的软件架构模式&#xff0c;主要用于组织应用程序的结构&#xff0c;特别是在用户界面和业务逻辑之间进行分离。以下是对它们的详细解释&#xff0c;包括它们的差异、优缺点。 MVC&#xff08;Model-View-Controller&#xff09; 结构 Model&#xf…

C++的继承(十一):私有继承和受保护的继承

但凡用过C的人都知道&#xff1a;私有继承的成员在派生类里均为私有&#xff0c;受保护的继承公有和受保护的成员在派生类里为受保护。另外C不对私有继承和受保护的继承的派生类指针自动转化为基础类。 #include <stdio.h> struct X {int a;X():a(9) {}int sqare() {ret…

5.nginx平滑升级

nginx平滑升级 一、nginx平滑升级1、下载新版本的安装包2、以之前的安装参数来编译新版本软件3、将新版本的nginx拷贝到安装目录4、启动新版本进程5、平缓关闭旧工作进程6、清理旧版本的nginx 一、nginx平滑升级 USR2 启动新版本进程 WINCH 平缓关闭旧工作进程 1、下载新版本…

分层注入的设计模式-上下层文件相互包含解决办法

现象&#xff1a;上下层文件相互包含 写代码时&#xff0c;会不会遇到&#xff0c;业务层内容要在底层硬件程序里写&#xff0c; 例如&#xff1a;一个外部按键&#xff0c;按键中断要触发一个应用层业务。 业务就要写道IO中断里&#xff0c;这个代码就要用到上层一些函数和变…

在长窗口时代,RAG技术是否仍然必要?

自从谷歌推出 Gemini 1.5 Pro&#xff0c;行业内部对于 RAG 的讨论就不绝于耳。 Gemini 1.5 Pro 的性能确实令人瞩目。根据谷歌公布的技术文档&#xff0c;该系统能够稳定处理长达 100 token 的内容&#xff0c;相当于一小时的视频、十一小时的音频、超过三万行的代码或七十万…

【VTKExamples::Utilities】第十七期 ZBuffer

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例ZBuffer,并解析接口vtkWindowToImageFilter,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ…

24 _ 分层和合成机制:为什么CSS动画比JavaScript高效?

在上一篇文章中我们分析了CSS和JavaScript是如何影响到DOM树生成的&#xff0c;今天我们继续沿着渲染流水线向下分析&#xff0c;来聊聊DOM树之后所发生的事情。 在前面《05 | 渲染流程&#xff08;上&#xff09;&#xff1a;HTML、CSS和JavaScript文件&#xff0c;是如何变成…

linux下can-utils的使用以及can接口的配置(以ubuntu20.04为例)

linux下can-utils的使用以及can接口的配置&#xff08;以ubuntu20.04为例&#xff09; can-utils是什么 can-utils 是一套用于Linux操作系统的开源工具&#xff0c;专门用来处理与CAN&#xff08;Controller Area Network&#xff09;总线相关的任务。CAN总线广泛应用于汽车和…

C语言文件操作:打开关闭,读写

程序文件 源程序文件&#xff08;后缀为.c&#xff09; 目标文件&#xff08;Windows环境后缀为.obj&#xff09; 可执行文件&#xff08;Windows环境后缀为.exe&#xff09; fputc FILE* pf fopen("test.txt","w");if (pf NULL){printf("%s\n"…

深入理解Qt计算器应用的构建过程

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、数字按钮的信号与槽函数连接 二、运算符按钮的信号与槽函数连接 三、特殊按钮的信号与…

红外超声波雷达测距(water)

文章目录 一 RS-232二 RS485三 Modbus四 stm32多路超声波测距4.1 设计方案4.2 代码 参考资料总结 实验要求 一. 采用stm32F103和HC-SR04超声波模块&#xff0c; 使用标准库或HAL库 定时器中断&#xff0c;完成1或2路的超声波障碍物测距功能。 1&#xff09;测试数据包含噪声&am…

Bezier Python 用法:深入探索与实用指南

Bezier Python 用法&#xff1a;深入探索与实用指南 在数字图形学和计算机编程中&#xff0c;贝塞尔曲线&#xff08;Bezier Curves&#xff09;是一种重要的参数曲线&#xff0c;被广泛应用于二维图形应用程序中&#xff0c;如字体轮廓、矢量图形和动画等。Python作为一种功能…

EukRep:区分真核和原核序列

https://github.com/patrickwest/EukRep 安装 conda create -y -n eukrep-env -c bioconda scikit-learn0.19.2 eukrep mamba install -c conda-forge numpy1.19.5 使用 EukRep -i <Sequences in Fasta format> -o <Eukaryote sequence output fasta file>

【Linux】线程ID

大致草稿—————————— 思维导图 学习目标 一、线程ID的理解 1.1 引出对tid的理解 我们先来创建一个线程复习一下线程的函数&#xff1a; pthread_t tid; // 创建一个线程 pthread_create(&tid, nullptr, threadrun, (void*)"thread-1"); // 打印出…

二分查找学习:优雅的二分查找——“Leetcode 35. 搜索插入位置”

例题 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2 示例 2…

怎么花草识别?方法有三种!

怎么花草识别&#xff1f;在这个五彩斑斓的世界里&#xff0c;花草是我们生活中不可或缺的一部分。它们点缀着我们的环境&#xff0c;为我们带来无尽的美丽与惊喜。然而&#xff0c;面对众多的花草种类&#xff0c;你是否曾感到困惑和迷茫&#xff0c;不知道如何识别它们&#…

VIO System 丨适用于控制器开发前期的测试系统

VIO综述 嵌入式软件的HIL测试需要复杂的测试系统及完整的ECU硬件&#xff0c;这导致通常只能在开发流程的后期阶段进行测试。全新推出的低成本解决方案VIO System&#xff0c;使得在开发前期不仅可以进行总线通讯测试&#xff0c;也可以同时进行I/O信号测试。 该系统旨在通过…

用 Vim 打造舒适高效的编程体验

作为程序员,Vim 无疑是最常使用的编辑器之一。它之所以如此受欢迎,得益于其强大的功能和高度可定制的特性。今天,让我带大家一起探索如何通过简单的 .vimrc 配置,打造一个个性化的 Vim 编程环境。 启用语法高亮 我们首先要确保 Vim 能够正确地识别和高亮代码语法。只需在 .vi…

LabVIEW版本控制

LabVIEW作为一种流行的图形化编程环境&#xff0c;在软件开发中广泛应用。有效地管理版本控制对于确保软件的可靠性和可维护性至关重要。LabVIEW提供了多种方式来管理VI和应用程序的修订历史&#xff0c;以满足不同规模和复杂度的项目需求。 LabVIEW中的VI修订历史 LabVIEW内置…