STM32F429第二十三篇之电容按键
发布日期:2021-05-14 11:31:47 浏览次数:19 分类:精选文章

本文共 5501 字,大约阅读时间需要 18 分钟。

文章目录

前言

本文主要介绍电容按键的原理与使用方法,主要使用的ARM资源为捕获模块,并不涉及新的模块。所以本文内容不涉及新的HAL库内容的介绍。

关于捕获模块部分,可以参考以下三篇博客:

本文主要参考资料:

  • 刘火良,杨森.STM32库开发实战指南——基于STM32F4.机械工业出版社

本实验的源代码如下所示:

本实验的主要功能为:

  1. 通过电容按键改变LED1的状态。每次点击电容按键,LED的状态置反。
  2. LED0按照1s的周期切换状态。

硬件分析

在这里插入图片描述

本实验的硬件如上图所示:

  1. 将TPAD与STM_ADC短接。
  2. STM_ADC即为PA5。

所以,相当于将按键TPAD与PA5直接短接。

原理

电容器就是可以容纳电荷的器件,在两块金属板之间添加绝缘体就构成了最简答的电容器。而在PCB中,可以设计为一块带有上拉电阻的铜块,而其被接地的铜块包围住,这就构成了最简单的电容接触按键。当电路板的形状固定时,电容接触按键的容值也基本上是固定的。

此时,若将手指接触到PCB板,电容接触按键的容值就会改变,这是因为在金属板和手指之间又新增了一个等效的电容Cs。如下图所示:

在这里插入图片描述
在这里插入图片描述
综上,电容接触按键的原理就是:当手指接触到按键的实收,按键的等效电容就会增大。因此,其充电时间增加。

所以,本实验只需要检测电容按键的充电时间,即可判断手指是否接触按键。

具体来说,可以大致分成以下几个步骤:

  1. 将PA5与电容短接——硬件分析已经实现。
  2. 将PA5用作推挽输出,且输出低电平,使电容放电。
  3. 将PA5用作TIM2CH1的捕获管脚。电容在上拉的作用下开始充电,PA5捕获电容充电时间。
  4. 通过判断充电时间长短,来确定按键是否被按下。

源程序

主函数

/**  ******************************************************************************  * @file    main.c  * @author  zhy  * @version 1.0  * @date    2021-04-26  * @brief   电容按键使用:  *             1.通过按下电容按键,改变LED1的状态  *             2.LED0按照1s的频率改变其状态  *          管脚分配:  *             PA5:用于捕获电容充电时间  *          使用资源:  *             TIM2CH1  ******************************************************************************  */#include "stdio.h"#include "stm32f4xx_hal.h"#include "tpad.h"#include "capture.h"#include "sys.h"#include "usart.h"#include "delay.h"#include "led.h"int main(){       /* 1.变量初始化 */    TpadStatus tpadStatus = TPAD_HIGH;    uint32_t timeInMs = HAL_GetTick();    uint32_t timeNewMS = 0;        /* 2.硬件初始化 */    HAL_Init();    SystemClock_Config();    UartInit();    LedInit();    CaptureInit();    TpadInit();    /* 3.while循环 */    while (1)    {           timeNewMS = HAL_GetTick();        TpadScan(&tpadStatus);        if (tpadStatus == TPAD_RISING)        {               LED1 = !LED1;        }        if (timeNewMS - timeInMs >= 1000)        {               timeInMs = timeNewMS;            LED0 = !LED0;        }    }}

主函数可以分成三个部分:

  1. 变量初始化
  2. 硬件初始化
  3. while循环

在硬件初始化中,CaptureInit() 初始化TIM2CH1。其初始化的方法与之前博客介绍的基本相同,不再详细介绍。TpadInit()为电容触摸按键初始化,下文详细分析。

在while循环中,函数TpadScan()将按键的处理结果通过传递到变量tpadStatus中。若检测到上升沿,则将LED1置反。需要注意的是,此处的上升沿是逻辑上的上升沿指的是:按键由无效状态变成有效状态。然后通过Tick时钟判断当前时间,从而实现LED0的1s周期变化。

TpadInit

/**  * @brief 触摸按键初始化——将按键放电 * @note 无 * @param {*}无 * @retval 无 */void TpadInit(void){       /* 1.时钟初始化 */    __HAL_RCC_GPIOA_CLK_ENABLE();    /* 2.GPIO初始化 */    GPIO_InitTypeDef initGpio;    initGpio.Pin = GPIO_PIN_5;           //pin5    initGpio.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出    initGpio.Speed = GPIO_SPEED_FAST;    //速度:快    HAL_GPIO_Init(GPIOA, &initGpio);     //初始化PA5    /* 3.初始化 */    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //PA5输出低电平    /* 4.获取为触摸时的电容充电时间 */    GetTimeUntoched();}

该函数十分简单。首先,将PA5初始化为输出低电平的推挽输出。然后调用GetTimeUntoched()函数来求取未接触按键时,按键的充电时间。

GetTimeUntoched

/**  * @brief 获取初始时间 * @note 无 * @param {*}无 * @retval 无 */void GetTimeUntoched(void){       int16_t temp[10] = {   0};    for (uint8_t i = 0; i < 10; i++)    {           GetTimeCharge((uint16_t *)(void *)temp + i);    }    int16_t min = 0;    int16_t max = 0;    int16_t sub = 0;    int16_t average = 0;    for (uint8_t i = 1; i < 10; i++)    {           sub = temp[i] - temp[0];     //获取差值        min = min > sub ? sub : min; //差值的最小值        max = max < sub ? sub : max; //差值的最大值        average += sub;              //差值的和    }    average -= min + max;                        //剔除最小与最大值    average >>= 3;                               //差值的平均    timeUntouched = average + temp[0];           //实际的平均值    printf("timeUntouched:%d\n", timeUntouched); //输出未按下按键时的充电时间}

通过调用函数GetTimeCharge()来获取10次充电时间。默认认为在函数初始化的时候,手指没有触碰按键。然后通过10次求平均的方式,来获得比较准确的按键的充电时间。将其存储在全局变量timeUntouched中,且通过串口输出。

GetTimeCharge

/**  * @brief 获取捕获时间 * @note 无 * @param {uint32_t} *time 捕获时间 * @retval 无 */void GetTimeCharge(uint16_t *time){       /* PA5:推挽输出 */    GPIOA->MODER &= ~GPIO_MODER_MODE5;    GPIOA->MODER |= GPIO_MODER_MODE5_0;    GPIOA->OTYPER &= ~GPIO_OTYPER_OT_5;    /* 输出低电平 */    PAout.bit5 = 0;    delay_us(50);    /* PA5:复用为TIM2CH1 */    GPIOA->MODER &= ~GPIO_MODER_MODE5;    GPIOA->MODER |= GPIO_MODER_MODE5_1;    GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL5;    GPIOA->AFR[0] |= GPIO_AFRL_AFRL5_0; //0b0001:AF1    TIM2->SR = 0x0000;        //清空中断标志    TIM2->CR1 |= TIM_CR1_CEN; //打开计数器    while (!(TIM2->SR & TIM_SR_CC1IF)) //等待充电完成        ;    TIM2->SR ^= TIM_SR_CC1IF;  //清除中断标记    TIM2->CNT = 0;             //清空计数器    TIM2->CR1 &= ~TIM_CR1_CEN; //关闭计数器    *time = TIM2->CCR1;         //获取捕获值    printf("time:%d\n", *time); //发送时间值}

该函数用于获取电容的充电时间。

  1. 将PA5配置为推挽输出且输出低电平,延时一段时间,让电容充分放电。
  2. 将PA5配置为复用功能,复用做TIM2CH1的上升沿检测管脚。打开计数器开始计时。
  3. 通过while循环等待上升沿触发,然后关闭计时器,清零计数器等操作后,将捕获的电容充电时间通过参数输出,且用串口打印。

TpadScan

/**  * @brief 判断按键是否有按下 * @note 无 * @param {TpadStatus} *tpadStatus 按键状态 * @retval 无 */void TpadScan(TpadStatus *tpadStatus){       static uint8_t timeHigh = 0;    uint16_t timeCharge = 0;    GetTimeCharge(&timeCharge);    if (timeCharge > timeUntouched * 5 >> 2) //若是平均未触碰充电时间的5/4,则判断是按键按下    {           timeHigh = 3;        switch (*tpadStatus)        {           case TPAD_LOW:            *tpadStatus = TPAD_RISING;            break;        case TPAD_RISING:            *tpadStatus = TPAD_HIGH;            break;        default:            break;        }    }    else //若检测到时间不足    {           *tpadStatus = TPAD_HIGH;        if (timeHigh > 0)        {               timeHigh--;        }        else        {               *tpadStatus = TPAD_LOW;        }    }}

首先,判断充电时间是否为原有时间的5/4。若复合条件,则认为手指接触了按键,否则,则认为手指离开了按键。

若条件由不符合变为复合,则认为这是一个上升沿。否则,其处于高电平或者低电平。

变量timeHigh相当于为滤波器,至少3次连续的条件不符合才认为其为真。这是为了防止按键抖动。

上一篇:硬件介绍之NT35510(80系列并口使用)
下一篇:STM32CubeMX第六篇之捕获实验

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年04月19日 10时52分33秒