stm32时钟电路电容电容按键,为什么超时会返回CNT值,有什么用处吗…?

有分享,才有进步
电容触摸按键原理
RC充放电电路原理
电阻R和电容C串联
当开关断开时,电阻R,电容0两端电压都是0,无电流
当开关闭合时(瞬间),电阻R两端V1(上端)和0(下端)有电压差,产生电流
此时电子通过电阻R积累在电容正极(上端),直到电容C电压为V1,充电完成
此时R两端电压均为V1,无压差,不再有电流经过
电容C的电压从0-V1,充电过程中,有充电时间t和电容C的电压Vt之间的关系(右图)
看以看出随充电时间越来越长,充电的效率(斜率)越来越低
当按键按下瞬间,电阻R两端电压V1和0,此时瞬间电流为I = V1 / R
当电容C充电一段时间后,假设电容C此时的电压为Vc,那么此时电阻C两端的电压为V1和Vc,此时的瞬间电流为I = (V1-Vc) / R
所以随着充电时间的增加,电容C的电压增加,电阻R两端压差减小,电流降低,电子积累速度减慢,充电效率降低
RC电路充放电公式
Vt = V0 + (V1 - V0) * [1 - exp(-t / RC)]
V0:电容的初始电压值
V1:电容最终可以冲/放到的电压值
Vt:电容t时刻的电压值
若电容C从0V开始充电,那么V0 = 0,则公式简化为:
Vt =V1 * [1 - exp(-t / RC)]
公式中V1, R均为常数,要达到相同的充电电压Vt,那么充电时间t和电容值C,成正比
同样条件下,电容C和充电时间t成正比
达到相同的电压,电容越大,所需要的充电时间越长
电容触摸按键原理
R:外接电容充放电电阻
Cs:TPAD与PCB之间存在杂散电容
Cx:当手指按下时,手指和TPAD之间的电容
手指未按下时的电路,TPAD与PCB之间存在电容Cs
当手指按下时,手指与TPAD之间存在电容Cx,此时相当于Cs与Cx并联,电容总值=Cs+Cx
根据上边”RC充放电电路原理”可知:
当R一定时,达到相同的电压,电容越大,需要的充电时间越长
所以,我们假设未触摸时充电时间为T1,触摸时充电时间为T2(T2 & T1)
检测电容触摸按键过程
1,电容放电到0
TPAD引脚设置为推挽输出,放电
放电到0V后,将计数器值设置为0,充电计时使用
2,电容充电
TPAD引脚设置为浮空输入(IO复位后的状态)
3,充电完成(Vx)进入输入捕获
TPAD引脚开启输入捕获
因为放完电的时候C的电压为 0,所以设置上升沿捕获
4,是否按下-计算充电时间,对比是否按下
当未按下时,记录充电完成的时间T1(计数器频路*数值)
检测当次充电时间T2,与T1对比,如果超过预设时间T3,说明按键按下
电容触摸按键的硬件连接
PA1引脚说明:
电容触摸按键TPAD(黄色部分),TPAD引脚与PA1项链
使用TIM5_CH2进行输入捕获
tpad.h声明功能函数
#ifndef __TPAD_H
#define __TPAD_H
#include "sys.h"
extern vu16 tpad_default_
TPAD_Reset(void);
TPAD_Get_Val(void);
TPAD_Get_MaxVal(u8 n);
TPAD_Init(u8 psc);
TPAD_Scan(u8 mode);
TIM5_CH2_Cap_Init(u16 arr,u16 psc);
tpad.c-tpad.h声明功能函数的实现
#include "tpad.h"
#include "delay.h"
#include "usart.h"
#define TPAD_ARR_MAX_VAL 0XFFFF
vu16 tpad_default_val=0;
u8 TPAD_Init(u8 psc)
u16 buf[10];
TIM5_CH2_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];
for(i=2;i&8;i++)temp+=buf[i];
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;
void TPAD_Reset(void)
GPIO_InitTypeDef
GPIO_InitS
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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);
delay_ms(5);
TIM_SetCounter(TIM5, 0);
TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
u16 TPAD_Get_Val(void)
TPAD_Reset();
while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET)
if(TIM_GetCounter(TIM5)&TPAD_ARR_MAX_VAL-500)
return TIM_GetCounter(TIM5);
return TIM_GetCapture2(TIM5);
u16 TPAD_Get_MaxVal(u8 n)
u16 temp=0;
u16 res=0;
while(n--)
temp=TPAD_Get_Val();
if(temp&res)res=
#define TPAD_GATE_VAL 100
u8 TPAD_Scan(u8 mode)
static u8 keyen=0;
u8 sample=3;
rval=TPAD_Get_MaxVal(sample);
if(rval&(tpad_default_val+TPAD_GATE_VAL))
if(keyen==0)res=1;
if(keyen)keyen--;
void TIM5_CH2_Cap_Init(u16 arr, u16 psc)
GPIO_InitTypeDef
GPIO_InitS
TIM_TimeBaseInitTypeDef
TIM_TimeBaseS
TIM_ICInitTypeDef
TIM5_ICInitS
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period =
TIM_TimeBaseStructure.TIM_Prescaler =
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_R
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM5_ICInitStructure.TIM_ICFilter = 0x03;
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
TIM_Cmd(TIM5, ENABLE );
main.c 当捕获到电容触摸按键按下(捕获上升沿),LED1反转
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "tpad.h"
int main(void)
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
TPAD_Init(6);
if(TPAD_Scan(0))
LED1=!LED1;
LED0=!LED0;
delay_ms(10);
LED0每间隔一段时间闪烁,标志程序正在运行中
当手指按下电容触摸按键时,LED1取反
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!查看: 150|回复: 2
TIM_GetCounter(TIM5)和TIM_GetCapture1(TIM5)的区别
主题帖子精华
初级会员, 积分 120, 距离下一级还需 80 积分
在线时间18 小时
今天学习电容式按键看到教程里的捕获超时返回CNT值用的是TIM_GetCounter();而之前的高电平捕获有另一个TIM_GetCapture1()获取定时器计数值。我自己想的这两个函数返回的值应该是一样的,从论坛搜索找不到要的答案,就改了一下例程使两个数通过串口输出比较一下。两个函数获取定时器计数值
& && && && && && && && && && &&&CAP_VAL = TIM_GetCapture1(TIM5);& & & & & & & & & & & & & & & & counter_val = TIM_GetCounter(TIM5);
串口输出:
& & & & & & & & printf(&按键按下 %lld us\r\n&,temp);
& & & & & & & & printf(&CAP_VAL = %d us\r\n&,CAP_VAL);
& & & & & & & & printf(&counter_val = %d us\r\n&,counter_val);
{6Q5DJ`V07C2}T)KT94}@@H.png (71.83 KB, 下载次数: 0)
定时器计数值
22:54 上传
可以看到两个值相差1、2us。
主题帖子精华
初级会员, 积分 120, 距离下一级还需 80 积分
在线时间18 小时
电容式按键的Cs和R取多大合适,我看原理图上并没有Cs这个器件。
_C([CDO1$KI6`)`S2M]D8.png (33.39 KB, 下载次数: 0)
电容式按键原理
23:00 上传
主题帖子精华
初级会员, 积分 120, 距离下一级还需 80 积分
在线时间18 小时
电容式按键的Cs和R取多大合适,我看原理图上并没有Cs这个器件。
Powered by晶振为什么要加电容 需要配多大电容
这要根据晶振的规格和电路中的因素来确定,同是16MHZ的晶体谐振器,其负载电容值有可能不一样,如10PF,20PF.....负载电容值是在其生产加工过程中确定的,无法进行改变.购买晶振时应该能得到准确的规格书.
晶振在电路中使用时,应满足CL=C+CS.
CL为规格书中晶振的负载电容值,
C为电路中外接的电容值(一般由两颗电容通过串并联关系得到),
CS为电路的分布电容,这和电路的设计,元器件分布等因素有关,值不确定,一般为3到5PF.
所以根据以上公式就可以大概推算出应该使用的电容值,而且这一电容值可以使晶振工作在其标称频率附近.
如:我用的430的单片机,8M晶振,配的是12pF的电容,其实容量的大小没必要多准确,几皮法到十几皮法都可以的。
估计都差不多,你看看芯片资料上应该有。
单片机中的外接晶振为什么要并上两个电容 ??为什么好要接到啊?
1.为了要满足谐振的条件。
具体讲就是:晶体元件的负载电容是指在电路中跨接晶体两端的总的外界有效电容。是指晶振要正常震荡所需要的电容。一般外接电容,是为了使晶振两端的等效电容等于或接近负载电容。不是所有晶体振荡电路都需要匹配电容。是否需要由振荡电路的形式决定,分析时需采用晶体的等效模型。 2.接地:晶体旁边的两个电容接地, 实际上就是电容三点式电路的分压电容, 接地点就是分压点. 以接地点即分压点为参考点, 振荡引脚的输入和输出是反相的, 但从并联谐振回路即石英晶体两端来看, 形成一个正反馈以保证电路持续振荡
当然,你也可以这样理解:
的在测试时有一个“负载电容”的条件,在工作时满足这个条件,振荡频率才与一致,也就是说,只有连接合适的电容才能满足的起振要求,晶振才能正常工作。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!只是没有人告诉你!
STM32F051 触摸按键功能
搞了几天STM32F051的触摸按键功能,最后发现其实很简单。最开始下载了官方的库,结果使用的时候发现程序居然会跑飞,后来还是自己写吧,写完了才发现原来很简单,这里把代码贴出来和大家分享。
// --------------------TSCtrl.h---------------------------
#pragma once
enum TSCStatus
TSC_RELEASE,
TSC_PRESSED
class TSCtrl
// 构造对象。
static TSCtrl &Construction(void)
static TSCtrl ts_
return ts_
// 扫描端口。
void Scan(void);
// 获取状态。
TSCStatus GetPortStatus(int index);
~TSCtrl();
#define tsc (TSCtrl::Construction())//-----------------------TSCtrl.cpp-----------------------------
#include "TSCtrl.h"
#include "stm32f0xx_gpio.h"
#include "stm32f0xx_rcc.h"
#include &stdlib.h&
#define THRESHOLD 30
// 按下时刻的门槛,根据实际情况修改此值。
#define PORT_NR 3
struct PortStatus
short fixed_
short current_
unsigned short enable_
struct ScanTrace
PortStatus port[PORT_NR];
char port_
ScanTrace _trace =
935, 0, TSC_RELEASE, 1 && 12,
// 935根据你的板卡而定,它是指在没有触碰按钮时刻采集的数据,该值在IOGXCR寄存器中。
926, 0, TSC_RELEASE, 1 && 13,
// 1&&13这些数据也要根据实际情况修改,这里使用的是GP4_IO1, GP4_IO2,GP4_IO4。
1100, 0, TSC_RELEASE, 1 && 15,
#define CAP_PORT
// 根据实际情况修改。
#define SAMPCAP_PIN
GPIO_Pin_11
#define CHANNEL0_PIN
GPIO_Pin_9
#define CHANNEL1_PIN
GPIO_Pin_10
#define CHANNEL2_PIN
GPIO_Pin_12
static void _init_hw(void)
// 打开时钟。
::RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitTypeDef gpio_
gpio_config.GPIO_Mode = GPIO_Mode_AF;
gpio_config.GPIO_OType = GPIO_OType_OD;
gpio_config.GPIO_Speed = GPIO_Speed_2MHz;
gpio_config.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpio_config.GPIO_Pin = SAMPCAP_PIN;
::GPIO_Init(CAP_PORT, &gpio_config);
// 初始化CAP引脚。
gpio_config.GPIO_OType = GPIO_OType_PP;
gpio_config.GPIO_Pin = CHANNEL0_PIN | CHANNEL1_PIN | CHANNEL2_PIN;
::GPIO_Init(CAP_PORT, &gpio_config);
// 初始化CHANNEL引脚。
// 重定义引脚的功能。
::GPIO_PinAFConfig(CAP_PORT, 9, GPIO_AF_3);
::GPIO_PinAFConfig(CAP_PORT, 10, GPIO_AF_3);
::GPIO_PinAFConfig(CAP_PORT, 11, GPIO_AF_3);
::GPIO_PinAFConfig(CAP_PORT, 12, GPIO_AF_3);
::RCC_AHBPeriphClockCmd(RCC_AHBPeriph_TS, ENABLE);
// CTPH = 1x tPGCLK, CTPL = 1x tPGCLK, PGPSC = 5(fHCLK/32), MCV = 6, TSCE = ENABLE
TSC-&CR = (0 && 28) | (0 && 24) | (5 && 12) | (6 && 5) | (1 && 0);
// 关闭施密特出发。
unsigned tmp_value = 0xFFFFFFFF;
tmp_value &= (unsigned)~((unsigned)1 && 12);
tmp_value &= (unsigned)~((unsigned)1 && 13);
tmp_value &= (unsigned)~((unsigned)1 && 14);
tmp_value &= (unsigned)~((unsigned)1 && 15);
TSC-&IOHCR &= tmp_
// Sampling enabled
tmp_value = 0;
tmp_value |= (unsigned)((unsigned)1 && 14);
TSC-&IOSCR |= tmp_
// Channel enabled, G4_IO4 G4_IO2 G4_IO1
// TSC-&IOCCR = (0x01 && 12);
// Enable group, G4
TSC-&IOGCSR |= (1 && 3);
static int _wait_eoc(void)
int ret = 0;
if (TSC-&ISR & 0x01)
// Check MCEF flag
if (TSC-&ISR & 0x02)
static void _scan_channel(int index)
TSC-&IOCCR = _trace.port[index].enable_
TSC-&ICR |= 0x03;
TSC-&CR |= 0x02;
int delay_cnt = 0;
while(_wait_eoc() == 0)
if(++delay_cnt & 10000)
// 避免死循环。
_trace.port[index].status = TSC_RELEASE;
_trace.port[index].current_value = TSC-&IOGXCR[3];
short diff = ::abs(_trace.port[index].current_value - _trace.port[index].fixed_value);
if(diff & THRESHOLD)
_trace.port[index].status = TSC_PRESSED;
_trace.port[index].status = TSC_RELEASE;
void TSCtrl::Scan(void)
_scan_channel(_trace.port_index++);
_trace.port_index = (_trace.port_index &= PORT_NR) ? 0 : _trace.port_
TSCStatus TSCtrl::GetPortStatus(int index)
return _trace.port[index].
TSCtrl::TSCtrl()
_init_hw();
TSCtrl::~TSCtrl()
使用代码如下:
int main(void)
tsc.Scan();
t = tsc.GetPortStatus(1);
t = tsc.GetPortStatus(2);
t = tsc.GetPortStatus(3);
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!求救!请问有谁用过STM32触摸按键的?
[问题点数:100分]
本版专家分:0
CSDN今日推荐
本版专家分:0
本版专家分:495
本版专家分:0
匿名用户不能发表回复!|
CSDN今日推荐

我要回帖

更多关于 stm32 电容触摸 的文章

 

随机推荐