零基础RT-thread第四节:电容按键

电容按键 其实只需要理解,手指按上去后充电时间变长,我们可以利用定时器输入捕获功能计算充电时间,超过无触摸时的充电时间一定的阈值就认为是有手指触摸。

基本原理就是这样,我们开始写代码:
其实,看过了上一章内容,就知道,我们只需要把TIM环境配置好,就相当于把HAL库搬了过来,直接使用HAL库的例程就可以了。

在这里插入图片描述

这是一个放电的过程,我们需要它一开始时是没有电的

static void TPAD_Reset(void)
{GPIO_InitTypeDef  GPIO_InitStructure;//配置引脚为普通推挽输出GPIO_InitStructure.Pin = TPAD_TIM_CH_PIN;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_PULLDOWN;HAL_GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);//输出低电平,放电HAL_GPIO_WritePin ( TPAD_TIM_CH_PORT, TPAD_TIM_CH_PIN ,GPIO_PIN_RESET);//保持一小段时间低电平,保证放电完全HAL_Delay(5);//清除更新标志__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_CC1);__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);//计数器归0__HAL_TIM_SET_COUNTER(&TIM_Handle,0);//引脚配置为复用功能,不上、下拉GPIO_InitStructure.Pin = TPAD_TIM_CH_PIN;GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;GPIO_InitStructure.Alternate = TPAD_TIM_AF;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(TPAD_TIM_CH_PORT,&GPIO_InitStructure);
}

然后是tpad.c的完整代码:

/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-06-14     c       the first version*/#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <tpad.h>#define TPAD_ARR_MAX_VAL    0XFFFF//保存没按下时定时器计数值
__IO uint16_t tpad_default_val=0;/************************************* 定时器输入捕获配置************************************/TIM_HandleTypeDef TIM_Handle;
static void TIMx_CHx_Cap_Init(uint32_t arr,uint16_t psc)
{GPIO_InitTypeDef  GPIO_InitStructure;TIM_IC_InitTypeDef sConfigIC;//使能TIM时钟TPAD_TIM_CLK_ENABLE();//使能通道引脚时钟TPAD_TIM_GPIO_CLK_ENABLE();//端口配置GPIO_InitStructure.Pin = TPAD_TIM_CH_PIN;//复用功能GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;GPIO_InitStructure.Alternate = TPAD_TIM_AF;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;//不带上下拉GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);//初始化TIM//设定计数器自动重装值TIM_Handle.Instance = TPAD_TIMx;TIM_Handle.Init.Prescaler = psc;TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;TIM_Handle.Init.RepetitionCounter = 0;TIM_Handle.Init.Period = arr;TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_IC_Init(&TIM_Handle);//上升沿触发sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;// 输入捕获选择sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;//配置输入分频,不分频sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;//配置输入滤波器 不滤波sConfigIC.ICFilter = 0;//初始化捕获通道HAL_TIM_IC_ConfigChannel(&TIM_Handle, &sConfigIC, TPAD_TIM_Channel_X);//启动TIMHAL_TIM_IC_Start(&TIM_Handle, TPAD_TIM_Channel_X);
}/****************************************** 为电容按键放电* 清除定时器标志及计数******************************************/
static void TPAD_Reset(void)
{GPIO_InitTypeDef  GPIO_InitStructure;//配置引脚为普通推挽输出GPIO_InitStructure.Pin = TPAD_TIM_CH_PIN;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_PULLDOWN;HAL_GPIO_Init(TPAD_TIM_CH_PORT, &GPIO_InitStructure);//输出低电平,放电HAL_GPIO_WritePin ( TPAD_TIM_CH_PORT, TPAD_TIM_CH_PIN ,GPIO_PIN_RESET);//保持一小段时间低电平,保证放电完全HAL_Delay(5);//清除更新标志__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_CC1);__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);//计数器归0__HAL_TIM_SET_COUNTER(&TIM_Handle,0);//引脚配置为复用功能,不上、下拉GPIO_InitStructure.Pin = TPAD_TIM_CH_PIN;GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;GPIO_InitStructure.Alternate = TPAD_TIM_AF;GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(TPAD_TIM_CH_PORT,&GPIO_InitStructure);
}/****************************************************** 得到定时器捕获值* 如果超时,则直接返回定时器的计数值.******************************************************/
static uint16_t TPAD_Get_Val(void)
{/* 先放电完全,并复位计数器 */TPAD_Reset();//等待捕获上升沿while(__HAL_TIM_GET_FLAG(&TIM_Handle,TIM_FLAG_CC1) == RESET ){//超时了,直接返回CNT的值if(__HAL_TIM_GET_COUNTER( &TIM_Handle)>TPAD_ARR_MAX_VAL-500)return __HAL_TIM_GET_COUNTER( &TIM_Handle);};/* 捕获到上升沿后输出TIMx_CCRx寄存器值 */return HAL_TIM_ReadCapturedValue(&TIM_Handle, TIM_CHANNEL_1);
}/****************************************************** 读取n次,取最大值* n:连续获取的次数* 返回值:n次读数里面读到的最大读数值******************************************************/
static uint16_t TPAD_Get_MaxVal(uint8_t n)
{uint16_t temp=0;uint16_t res=0;while(n--){temp=TPAD_Get_Val();//得到一次值if(temp>res)res=temp;};return res;
}/********************************************************
*
* 初始化触摸按键
* 获得空载的时候触摸按键的取值.
* 返回值:0,初始化成功;1,初始化失败
*
*********************************************************/
uint8_t TPAD_Init(void)
{uint16_t buf[10];uint32_t temp=0;uint8_t j,i;//设定定时器预分频器目标时钟为:9MHz(216Mhz/24)TIMx_CHx_Cap_Init(TPAD_ARR_MAX_VAL,24-1);for(i=0;i<10;i++)//连续读取10次{buf[i]=TPAD_Get_Val();HAL_Delay(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;//取中间的6个数据进行平均for(i=2;i<8;i++){temp+=buf[i];}tpad_default_val=temp/6;/* printf打印函数调试使用,用来确定阈值TPAD_GATE_VAL,在应用工程中应注释掉 *///printf("tpad_default_val:%d\r\n",tpad_default_val);//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常!if(tpad_default_val>TPAD_ARR_MAX_VAL/2){return 1;}return 0;
}uint8_t TPAD_Scan(uint8_t mode)
{//0,可以开始检测;>0,还不能开始检测static uint8_t keyen=0;//扫描结果uint8_t res=0;//默认采样次数为3次uint8_t sample=3;//捕获值uint16_t rval;if(mode){//支持连按的时候,设置采样次数为6次sample=6;//支持连按keyen=0;}/* 获取当前捕获值(返回 sample 次扫描的最大值) */rval=TPAD_Get_MaxVal(sample);/* printf打印函数调试使用,用来确定阈值TPAD_GATE_VAL,在应用工程中应注释掉 *///printf("scan_rval=%d\n",rval);//大于tpad_default_val+TPAD_GATE_VAL,且小于10倍tpad_default_val,则有效if(rval>(tpad_default_val+ 100)&&rval<(10*tpad_default_val)){//keyen==0,有效if(keyen==0){res=1;}keyen=3;                //至少要再过3次之后才能按键有效}if(keyen){keyen--;}return res;
}

接下来是tpad.h

/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-06-14     c       the first version*/
#ifndef APPLICATIONS_TPAD_H_
#define APPLICATIONS_TPAD_H_#define TPAD_TIMx                   TIM2
#define TPAD_TIM_CLK_ENABLE()       __TIM2_CLK_ENABLE()#define TPAD_TIM_Channel_X          TIM_CHANNEL_1
#define TPAD_TIM_GetCaptureX        TIM_GetCapture1#define TPAD_TIM_GPIO_CLK_ENABLE()  __GPIOA_CLK_ENABLE()
#define TPAD_TIM_CH_PORT            GPIOA
#define TPAD_TIM_CH_PIN             GPIO_PIN_5
#define TPAD_TIM_AF                 GPIO_AF1_TIM2/************************** TPAD 函数声明********************************/
uint8_t TPAD_Init(void);
uint8_t TPAD_Scan(uint8_t mode);#endif /* APPLICATIONS_TPAD_H_ */

最后是main.c

/** Copyright (c) 2006-2025, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2025-06-14     RT-Thread    first version*/#include <rtthread.h>#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>#include <rtdevice.h>
#include <board.h>
#include <tpad.h>#define LED_R_PIN    GET_PIN(H, 10)static rt_base_t led_r_stat = PIN_LOW;int main(void)
{TPAD_Init();rt_pin_mode(LED_R_PIN, PIN_MODE_OUTPUT);while (1){if (TPAD_Scan(0)) {led_r_stat = (led_r_stat == PIN_LOW) ? PIN_HIGH : PIN_LOW;rt_pin_write(LED_R_PIN, led_r_stat);}}return RT_EOK;
}

感觉代码太不RTthread了。直接从HAL库例程平移过来。不过不管怎么说,电容按键可以使用了。

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

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

相关文章

SQL基础操作:从增删改查开始

好的&#xff01;SQL&#xff08;Structured Query Language&#xff09;是用于管理关系型数据库的标准语言。让我们从最基础的增删改查&#xff08;CRUD&#xff09;​​ 操作开始学习&#xff0c;我会用简单易懂的方式讲解每个操作。 &#x1f6e0; 准备工作&#xff08;建表…

vim 编辑模式/命令模式/视图模式常用命令

以下是一份 Vim 命令大全&#xff0c;涵盖 编辑模式&#xff08;Insert Mode&#xff09;、命令模式&#xff08;Normal Mode&#xff09; 和 视图模式&#xff08;Visual Mode&#xff09; 的常用操作&#xff0c;适合初学者和进阶用户使用。 &#x1f9fe; Vim 模式简介 Vim…

每天看一个Fortran文件(10)

今天来看下MCV模式调用物理过程的相关代码。我想改进有关于海气边界层方面的内容&#xff0c;因此我寻找相关的代码&#xff0c;发现在physics目录下有一个sfc_ocean.f的文件。 可以看见这个文件是在好多好多年前更新的了&#xff0c;里面内容不多&#xff0c;总共146行。是计算…

python打卡day37

疏锦行 知识点回顾&#xff1a; 1. 过拟合的判断&#xff1a;测试集和训练集同步打印指标 2. 模型的保存和加载 a. 仅保存权重 b. 保存权重和模型 c. 保存全部信息checkpoint&#xff0c;还包含训练状态 3. 早停策略 作业&#xff1a;对信贷数据集训练后保存权重&#xf…

【Spark征服之路-2.9-Spark-Core编程(五)】

RDD行动算子&#xff1a; 行动算子就是会触发action的算子&#xff0c;触发action的含义就是真正的计算数据。 1. reduce ➢ 函数签名 def reduce(f: (T, T) > T): T ➢ 函数说明 聚集 RDD 中的所有元素&#xff0c;先聚合分区内数据&#xff0c;再聚合分区间数据 val…

【入门】【练17.3 】比大小

| 时间限制&#xff1a;C/C 1000MS&#xff0c;其他语言 2000MS 内存限制&#xff1a;C/C 64MB&#xff0c;其他语言 128MB 难度&#xff1a;中等 分数&#xff1a;100 OI排行榜得分&#xff1a;12(0.1分数2难度) 出题人&#xff1a;root | 描述 试编一个程序&#xff0c;输入…

CppCon 2017 学习:Free Your Functions!

“Free Your Functions!” 这句话在C设计中有很深的含义&#xff0c;意思是&#xff1a; “Free Your Functions!” 的理解 “解放你的函数”&#xff0c;鼓励程序员&#xff1a; 不要把所有的函数都绑在类的成员函数里&#xff0c;优先考虑写成自由函数&#xff08;non-mem…

日常运维问题汇总-19

60. OVF3维护成本中心与订货原因之间的对应关系时&#xff0c;报错提示&#xff0c;SYST: 不期望的日期 00/00/0000。消息号 FGV004&#xff0c;如下图所示&#xff1a; OVF3往右边拉动&#xff0c;有一个需要填入的字段“有效期自”&#xff0c;此字段值必须在成本中心定义的有…

2025SCA工具推荐︱基于多模态SCA的新一代开源供应链风险审查与治理平台

近年来&#xff0c;随着开源软件在企业数字化转型中的广泛应用&#xff0c;开源供应链攻击事件频发&#xff0c;企业普遍面临三大突出难题&#xff1a;一是不清楚自身引入了哪些开源组件&#xff0c;二是不掌握组件中潜在的安全漏洞和合规风险&#xff0c;三是缺乏自动化、全流…

CppCon 2017 学习:Migrating a C++03 library to C++11 case study

这段内容是在介绍 Wt&#xff08;发音类似 “witty”&#xff09; —— 一个用于 C 的 Web UI 框架。总结如下&#xff1a; 什么是 Wt&#xff1f; Wt 是一个 用 C 编写的 widget&#xff08;控件&#xff09;驱动的 Web 框架。类似于桌面 GUI 框架&#xff08;比如 Qt&#…

coding习惯 + Bug记录整理

&#x1f4d6; 清单 1、包装类型导致的NPE2、xxApiWrapper命名3、see注释4、MySQL模糊匹配特殊字符bug 整理些平时不好的coding习惯导致的bug&#x1f4dd; 1、包装类型导致的NPE 处理项目的一个bug&#xff0c;看日志是发生了空指针&#xff0c;相关代码如下&#xff1a; D…

机器学习项目微服务离线移植

机器学习项目微服务离线移植 引言&#xff1a;为什么需要Docker化机器学习项目&#xff1f; 在当今的机器学习工程实践中&#xff0c;项目部署与移植是一个常见但极具挑战性的任务。传统部署方式面临着"在我机器上能运行"的困境——开发环境与生产环境的不一致导致…

JS红宝书笔记 8.4 类

与函数类型相似&#xff0c;定义类也有两种主要方式&#xff1a;类声明和类表达式&#xff0c;这两种方式都使用class关键字加大括号 与函数表达式类似&#xff0c;类表达式在它们被求值前也不能引用&#xff0c;不过与函数定义不同的是&#xff0c;虽然函数声明可以提升&…

专题:2025游戏科技与市场趋势报告|附130+份报告PDF汇总下载

原文链接&#xff1a;https://tecdat.cn/?p42733 2024年全球游戏市场规模突破1877亿美元&#xff0c;中国以37.5%的全球占比成为核心增长引擎。生成式AI以52%的企业采用率重塑开发流程&#xff0c;混合休闲游戏实现37%的收入增长&#xff0c;跨端互通产品贡献42%增量。玩家行为…

【沉浸式解决问题】Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required

目录 一、问题描述二、场景还原1. 测试mapper2. 测试service 三、原因分析四、解决方案1. DemoApplicationTests2. DemoApplication 后记 一、问题描述 在Application文件中加了ComponentScan注解&#xff0c;此后运行任何测试方法均报错 java.lang.IllegalStateException: Fa…

Ubuntu 和 CentOS 中配置静态 IP

在 Ubuntu 和 CentOS 中配置静态 IP 的方法有所不同&#xff0c;主要因为两者使用的网络管理工具不同。以下是详细步骤&#xff1a; Ubuntu&#xff08;18.04 及更新版本&#xff0c;使用 netplan&#xff09; 1. 查看网卡名称 ip a记录网卡名称&#xff08;如 ens33、eth0&a…

4、做中学 | 二年级下期 Golang整型和浮点型

上篇介绍了哪些数据类型&#xff0c;如何进行声明常量和变量&#xff0c;那么接下来进行详细学习下各个数据类型的使用&#xff01; 一、整数 在go中&#xff0c;整数分为俩类&#xff0c;一个是无符号整数&#xff0c;即0以上数值&#xff1b;另一个是有符号数值&#xff0c;…

C++11 GC Interface:从入门到精通

文章目录 一、引言二、C11简介2.1 C11发展历史2.2 C11新特性概述 三、C11中的垃圾收集支持和基于可达性的泄漏检测3.1 背景与原理3.2 相关标准与接口3.3 示例代码 四、C11 GC interface的使用场景4.1 简化内存管理4.2 提高代码可靠性 五、C23中移除垃圾收集支持和基于可达性的泄…

《高并发系统性能优化三板斧:缓存 + 异步 + 限流》

高并发系统性能优化三板斧&#xff1a;缓存 异步 限流 引言 在互联网应用的高并发场景下&#xff0c;系统性能面临巨大挑战。以某电商平台会员活动为例&#xff0c;活动期间瞬时QPS可达10万&#xff0c;若未进行有效优化&#xff0c;服务器将迅速崩溃。本文从缓存、异步、限…

JVM(4)——引用类型

痛点引入&#xff1a; 为什么需要不同的引用类型&#xff1f;直接只用强引用不行吗&#xff1f;&#xff08;内存泄漏风险、缓存管理粗粒度、对象生命周期监听需求&#xff09; 核心作用&#xff1a; 解释引用类型如何让程序员与垃圾收集器&#xff08;GC&#xff09;协作&…