IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32学习(电容触摸按键) -> 正文阅读

[嵌入式]STM32学习(电容触摸按键)

1.电容触摸按键原理

?R:外接电容充放电电阻;Cs:TPAD和PCB间的杂散电容;Cx:手指按下时,手指和TPAD之间的电容;开关:电容放电开关,由STM32IO口代替。

2.电容充电时间与电容大小的关系

同样的条件下,电容值C跟时间t成正比关系,电容越大,充电到达某个临界值的时间越长。

3.检测电容触摸按键过程

(1)TPAD引脚设置为推挽输出,输出0,实现电容放电到0;

(2)TPAD引脚设置为浮空输入(IO口复位后的状态),电容开始充电;

(3)同时开启TPAD引脚的输入捕获,开始捕获;

(4)等待充电完成(充电到底Vx,检测到上升沿);

(5)计算充电时间。

没有按下的时候,充电的时间为T1(default)。按下TPAD,电容变大,所以充电时间为T2。我们可以

通过检测充放电的时间,来判断是否按下。如果T2-T1大于某个值,就可以有按键按下。

实验内容

手触摸按键后,LED1灯翻转。

硬件连接?

?软件设计

?1.相关库函数

(1)void TPAD_Reset(void)函数:复位TPAD

设置IO口为推挽输出输出0,电容放电。等待放电完成之后,设置为浮空输入,从而开始充电。同时把计数器的CNT设置为0;

(2)TPAD_Get_Val()函数:获取一次捕获值(得到充电时间)

?复位TPAD,等待捕获上升沿,捕获之后,得到定时器的值,计算充电时间;

(3)TPAD_Get_MaxVal()函数:

多次调用TPAD_Get_Val函数获取充电时间。获得最大值。

(4)TPAD_Init()函数:初始化TPAD

在系统初启动后,初始化输入捕获。先10次调用TPAD_Get_Val()函数获取10次充电时间,然后获取中间N(N=8或者6)次的平均值,作为在没有电容触摸按键按下时的时候的充电时间缺省值tpad_default_val;

(5)TPAD_Scan()函数:扫描TPAD

调用TPAD_Get_MaxVal()函数获取多次充电中最大的充电时间,跟tpad_default_val比较,如果大于某个阈值,则认为有触摸动作;

(6)void TIM5_CH2_Cap_Init(u16 arr,u16 psc)函数:输入捕获通道初始化

2.程序思路

3.实验代码

tpad.h
?

#ifndef __TPAD_H__
#define __TPAD_H__
#include "sys.h"

void TPAD_Reset(void);
u16 TPAD_Get_Val(void);
u16 TPAD_Get_MaxVal(u8 n);
u8 TPAD_Init(u8 psc);
u8 TPAD_Scan(u8 mode);
void TIM2_CH1_Cap_Init(u32 arr,u16 psc);

#endif

?tpad.c

#include "tpad.h"
#include "usart.h"
#include "sys.h"
#include "delay.h"

#define TPAD_ARR_MAX_VAL 0xFFFFFFFF        //最大的ARR值
vu16 tpad_default_val=0;                   //空载的时候,计数器需要的时间

void TPAD_Reset(void)                      //TPAD复位
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;    //PA5
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//普通输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度100MHz
    GPIO_InitStructure.GPIO_OType=GPIO_OType_pp;    //推挽
    GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;    //下拉
    GPIO_Init(GPIOA,&GPIO_InitStructure)            //初始化PA5
    
    GPIO_ResetBits(GPIOA,GPIO_Pin_5);               //输出0,放电
    delay_ms(5);
    TIM_ClearITPendingBit(TIM2,TIM_IT_CC1|TIM_IT_Update);//清除中断标志
    TIM_SetCounter(TIM2,0);                         //归0

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;    //复用输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度100MHz
    GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;    //推挽
    GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;  //不带上下拉
    GPIO_Init(GPIOA,&GPIO_InitStructure);           //初始化PA5

}

u16 TPAD_Get_Val(void)        //得到定时器捕获值
{
    TPAD_Reset();
    while(TIM_GetFlagStatus(TIM2,TIM_IT_CC1)==RESET)//等待捕获上升沿
    {    
        if(TIM_GetCounter(TIM2)>TPAD_ARR_MAX_VAL-500)
        return TIM_GetCounter(TIM2);//超时了,直接返回CNT的值
    }
    return TIM_GetCapture1(TIM2);//若没超时,返回TIM2_CCR2的值
}

u16 TPAD_Get_MaxVal(u8 n)        //读取n次,取最大值
{
    u16 temp=0,res=0;
    while(n--)
    {
        temp=TPAD_Get_Val();    //得到一次值
        if(temp>res)res=temp;
    }
    return res;
}

u8 TPAD_Init(u8 psc)           //初始化触摸按键
{
    u16 buf[10],temp;
    u8 j,i;
    TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);    //设置分频系数
    for(i=0;i<10;i++)
    {
        buf[i]=TPAD_Get_Val();
        delay_ms(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;
    for(i=2;i<8;i++)//取中间的6个数据进行平均
    tpad_default_val=temp/6;
    printf("tpad_default_val:%d\r\n",tpad_default_val);
    if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;
    //初始化遇到超过TPAD_ARR_MAX_VAl/2的数值,不正常
    return 0;    
}

#define TPAD_GATE_VAL 100    //触摸的门限值
u8 TPAD_Scan(u8 mode)  //扫描触摸按键
{
    static u8 keyen=0;    //0,可以开始检测;>0,还不能开始检测
    u8 res=0;             //res=0说明按键无效,res=1说明按键有效
    sample=3;             //默认采样次数为3次
    u16 rval;            
    if(mode)              //mode:0,不支持连续触发
    {
        sample=6;         //支持连按的时候,设置采样次数为6次
        keyen=0;          //支持连按
    }
    rval=TPAD_Get_MaxVal(sample);    //连续采样3次,取最大值
    if(rval>(tpad_default_val+TPAD_GATE_VAL)&&rval<(10*tpad_default_val))
    {
        if((keyen==0)&&(rval>(tpad_default_val+TPAD_GATE_VAL)))res=1;
        keyen=3;
    }
    if(keyen)keyen--;
    return res;            
}

void TIM2_CH1_Cap_Init(u32 arr,u16 psc) //定时器2通道2输入捕获
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM2_ICInitTypeDef TIM2_ICInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);    //TIM2时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);    //使能PORTA时钟
    
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2);    //PA5复用为定时器2
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;    //GPIOA5
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;  //复用功能
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;    //速度100MHz
    GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;        //推挽复用输出
    GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;      //不带上下拉
    GPIO_Init(GPIOA,&GPIO_InitStructure);               //初始化PA5
    
    TIM_TimeBaseInitStructure.TIM_Period=arr;            //设计定时器自动重装载值
    TIM_TimeBaseInitStructure.TIM_Prescaler=psc;         //预分频器
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//TIM向上计数
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);   //初始化定时器2

    TIM2_ICInitStructure.TIM_Channel=TIM_Channel_1;    //选择输入端IC1映射到TIM2
    TIM2_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising    //上升沿捕获
    TIM2_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
    TIM2_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;    //配置输入分频,不分频
    TIM2_ICInitStructure.TIM_ICFilter=0x00;                //不滤波
    TIM_ICInit(TIM2,TIM2_ICInitStructure);                //使能定时器2
    
    TIM_Cmd(TIM2,ENABLE);    //使能定时器2
}

main.c

#include "sys.h"
#include "tpad.h"
#include "led.h"
#include "usart.h"
#include "delay.h"

int main(void)
{
    U8 t=0;
    NVIC_PriorityGroupConfig(NVIC_PriorityGruop_2);//设置系统中断优先级分组2
    delay_init(168);    //初始化延时函数
    uart_init(115200);    //初始化串口波特率115200
    LED_Init();    //初始化LED
    TPAD_Init(8);    //初始化触摸按键
    while(1)
    {
        if(TPAD_Scan(0)) //成功捕获到了一次上升沿
        {
            LED1=!LED1;    //LED1取反
        }
        t++;
        if(t==15)
        {
            t=0;
            LED0=!LED0;    //LED0取反,提示程序正在运行
        }
        delay_ms(10);
    } 
}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:31:28  更:2022-10-22 21:34:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:52:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码