【STM32】HAL库 STM32CubeMX-正点原子TPAD(电容按键触摸)实验

2023-11-01 15:20

本文主要是介绍【STM32】HAL库 STM32CubeMX-正点原子TPAD(电容按键触摸)实验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

本实验通过STM32CubeMX和HAL库结合,实现正点原子的TPAD实验。

使用工具:

芯片:STM32F103ZET6(精英版)

软件:STM32CubeMx软件、MDK-Keil软件

库:STMF1 HAL库

知识概括:

GPIO控制LED的亮灭

定时器输入捕获

STM32CubeMx创建过程

什么是TPAD

        我们使用的是检测电容充放电时间的方法来判断是否有触摸,图 中的 A、B 分别表示有无人体按下时电容的充放电曲线。其中 R 是外接的电容充电电阻, Cs 是没有触摸按下时 TPAD 与 PCB 之间的杂散电容。而 Cx 则是有手指按下的时候,手指与 TPAD 之间形成的电容。图中的开关是电容放电开关(实际使用时,由 STM32F1 的 IO 代替)。

先用开关将 Cs(或 Cs+Cx)上的电放尽,然后断开开关,让 R 给 Cs(或 Cs+Cx)充电, 当没有手指触摸的时候,Cs 的充电曲线如图中的 A 曲线。而当有手指触摸的时候,手指和 TPAD 之间引入了新的电容 Cx,此时 Cs+Cx 的充电曲线如图中的 B 曲线。从上图可以看出,A、B 两 种情况下,Vc 达到 Vth 的时间分别为 Tcs 和 Tcs+Tcx。 其中,除了 Cs 和 Cx 我们需要计算,其他都是已知的,根据电容充放电公式:

 

 我们使用 PA1(TIM2_CH2(精英版))来检测 TPAD 是否有触摸,在每次检测之前,我们先配置 PA1 为推挽输出,将电容 Cs(或 Cs+Cx)放电,然后配置 PA1 为浮空输入,利用外部上拉电阻 给电容 Cs(Cs+Cx)充电,同时开启 TIM5_CH2 的输入捕获,检测上升沿,当检测到上升沿的时 候,就认为电容充电完成了,完成一次捕获检测。

每次复位重启的时候,我们执行一次捕获检测(可以认为没触摸),记录此时的值, 记为 tpad_default_val,作为判断的依据。在后续的捕获检测,我们就通过与 tpad_default_val 的 对比,来判断是不是有触摸发生。

原理图:

由于设计时 PA1 不直接连接到电容触摸按键,而是引到了插针上,我们需要通过跳线帽把 P10 上标为 ADC 的引脚与标号为“TPAD”的标号连接到一起。

简单来说:

TAPD是一个电容,我们先对电容进行放电,之后电容进行充电的过程中,IO端口会由低电平转换为高电平,通过定时器的输入捕获获取电容从低电平转换为高电平的时间。时间为Tcs,手指按下时,电容会增大,低电平转换为高电平的时间会加长,为Tcx。通过两次时间对比判断TPAD是否有触摸。

注:以上部分内容转自正点原子

工程创建

1设置RCC

设置高速外部时钟HSE,选择外部时钟源

 2设置时钟

3设置LED

 将PE5设置为输出模式,上拉电阻,同理设置PB5

 4定时器配置

设置TIM2的通道2

        预分频系数为71,频率为72MHz  / (71+1) = 1us

        自动加载值为最大值65535

        上升沿捕获

        滤波值为0

同时在NVIC中使能TIM2的中断 

5项目文件

 

 6创建工程文件

点击右上角CENERATE CODE 创建工程

代码部分:

创建tapd.c        tapd.h两个文件

tapd.h

#ifndef __TPAD_H__
#define __TPAD_H__#include "main.h"void tpad_init(void);               // 初始化
uint8_t tapd_scan(uint8_t mode);    // 扫描函数#endif

tapd.c

#include "tpad.h"
#include "tim.h"        // 需要使用到定时器的捕获功能/*@brief      复位TPAD#node       将TPAD按键看作是一个电容,手指按下和不按下电容值有变化先将GPIO设置为推挽输出,输出0,进行放电,在设置为GOIP为浮空输入,等待电容充电,并且捕获上拉
*/static uint8_t flag = 0;                        // 检测是否执行了输入捕获回调函数
uint16_t temp = 0;                              // 存取捕获的值
uint16_t tpad_default_val;                      // 手指不按下时,电容充电到高电平的时间static void tpad_reset(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_1;                       // 将PA1设置为开漏输出GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;                     // 上拉电阻GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);   // 将PA1置0,对电容进行放电htim2.Instance->SR = 0;     // 清除标记htim2.Instance->CNT = 0;    // 归零GPIO_InitStruct.Pin = GPIO_PIN_1;                       // 设置为输入模式,进行输入捕获GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 设置为上升沿捕获__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);    // 开启定时器捕获
}static void tpad_get_val(void)
{tpad_reset();                                   // 先进行复位(放电,置位,开启定时器捕获)while(flag == 0)                                // 判断捕获中断回调函数是否捕获完成{HAL_Delay(1);}flag = 0;                                       // 捕获完成后再次将flag置0
}// 捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{UNUSED(htim);HAL_TIM_IC_Stop_IT(&htim2, TIM_CHANNEL_2);      // 先关闭定时器捕获if (TIM2 == htim->Instance){temp = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);    // 获取当前捕获值flag = 1;                                   // 将flag置1,说明捕获完成}
}/**
* @brief 读取 n 次, 取最大值
* @param n :连续获取的次数
* @retval n 次读数里面读到的最大读数值
*/static uint16_t tapt_get_maxval(uint8_t n)
{uint16_t maxval = 0;while (n--) {tpad_get_val();     // 进行数据捕获,捕获成功后temp的值更新为最新的捕获值if (temp > maxval) {maxval = temp;  // 取捕获的最大值}}return maxval;          // 将数值返回
}    // 初始化触摸按键
void tpad_init(void)
{uint16_t buf[10];uint16_t m;uint8_t i, j;for (i = 0; i < 10; i++) {  // 获取10个数据tpad_get_val();buf[i] = temp;}for (i = 0; i < 9; i++) {   // 进行排序for (j = i+1; j < 10; j++) {if (buf[i] < buf[j]){m = buf[i];buf[i] = buf[j];buf[j] = m;}}}m = 0;for (i = 2; i < 8; i++) {       // 取中间的6个数据m += buf[i];}tpad_default_val = m / 6;       // 求平均值作为没有触摸时的值
}/**
* @brief    扫描触摸按键
* @param    mode :扫描模式
* @arg      0, 不支持连续触发(按下一次必须松开才能按下一次);
* @arg      1, 支持连续触发(可以一直按下)
* @retval   0, 没有按下; 1, 有按下;
*/uint8_t tapd_scan(uint8_t mode)     // 扫秒模式
{static uint8_t keyen = 0;       /* 0, 可以开始检测; >0, 还不能开始检测; */uint8_t res = 0;uint8_t sample = 3;             /* 默认采样次数为 3 次 */uint16_t rval = 0;if (mode) {                     // mode = 1为扫描模式,sample = 6;                 /* 支持连按的时候,设置采样次数为 6 次 */keyen = 0;                  /* 支持连按, 每次调用该函数都可以检测 */}rval = tapt_get_maxval(sample); // 获取读取的值if (rval > (tpad_default_val + 15)) {if (keyen == 0) {res = 1;}keyen = 3;}if (keyen) keyen--;             // 单次触发松手三次后将keyen置0,然后才能将res赋值为1return res;
}

在main函数的中添加一下语句:

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */#include "tpad.h"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
  /* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */tpad_init();              // TPAD电容按键初始化/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */uint8_t t = 0;while (1){if (tapd_scan(0)) {       // 非连续触发模式,返回1按下,返回0没有按下HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);}t++;if (t == 15) {t = 0;HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);}HAL_Delay(100);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

结果:

PE5连接的LED不停的闪烁说明程序在正常运行,按下电容按键后PB5连接的LED状态取反实现LED的亮灭。

这篇关于【STM32】HAL库 STM32CubeMX-正点原子TPAD(电容按键触摸)实验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/323898

相关文章

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

Lua 脚本在 Redis 中执行时的原子性以及与redis的事务的区别

在 Redis 中,Lua 脚本具有原子性是因为 Redis 保证在执行脚本时,脚本中的所有操作都会被当作一个不可分割的整体。具体来说,Redis 使用单线程的执行模型来处理命令,因此当 Lua 脚本在 Redis 中执行时,不会有其他命令打断脚本的执行过程。脚本中的所有操作都将连续执行,直到脚本执行完成后,Redis 才会继续处理其他客户端的请求。 Lua 脚本在 Redis 中原子性的原因

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

STM32CubeMX和HAL库-新建项目

目录 新建项目 选择开发板  MCU图形化配置界面总览 MCU配置 新建项目 新建项目包含选择MCU创建项目、选择开发板新建项目和交叉选择MCU新建项目三部分。 1. 选择MCU创建项目 单击主菜单项File→New Project,或Home视图上的ACCESS TO MCU SELECTOR 按钮,都可以打开的New Project from a MCU/MPU对话框。

独立按键单击检测(延时消抖+定时器扫描)

目录 独立按键简介 按键抖动 模块接线 延时消抖 Key.h Key.c 定时器扫描按键代码 Key.h Key.c main.c 思考  MultiButton按键驱动 独立按键简介 ​ 轻触按键相当于一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通与断开。  ​ 按键抖动 由于按键内部使用的是机