![](https://img-blog.csdnimg.cn/img_convert/ad9b84fa7dce6359656ec832887b786f.png)
![](https://img-blog.csdnimg.cn/img_convert/3d4e511d6a7f4a191630705e70d5a795.png)
![](https://img-blog.csdnimg.cn/img_convert/61beb5abf05e91e1caca947d0657c658.png)
![](https://img-blog.csdnimg.cn/img_convert/261b9d33e80e2336e345ca1575f40086.png)
开发步骤
本章所要实现的功能是:通过 TIM5 的通道 2(PA1)捕获电容触摸按键输入 信号的高电平脉宽,根据捕获到高电平时间大小控制 DS1 指示灯开关,同时 DS0 指示灯不断闪烁表示系统正常运行。程序框架如下: (1)初始化 PA1 管脚为 TIM5 通道 2 输入捕获功能,设置上升沿捕获等 (2)读取一次捕获高电平的值 (3)电容触摸按键初始化 (4)检测电容触摸按键是否按下 (5)编写主函数
touch_key.h+touch_key.c
#ifndef _touch_key_H
#define _touch_key_H
#include "system.h"
void TIM5_CH2_Input_Init(u16 arr, u16 psc);
u16 Touch_Get_Val();
u8 Touch_Key_Scan(u8 mode);
u8 Touch_Key_Init(u8 psc);
#endif
#include "touch_key.h"
#include "SysTick.h"
#include "stdio.h"
#define Touch_ARR_MAX_VAL 0XFFFF //最大重装载值
u16 touch_default_val=0; //初始化默认值即没触摸时的值,进行对比,得出是否触摸的值
void TIM5_CH2_Input_Init(u16 arr, u16 psc)//自动重装载值,预分频值
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_TimeBaseInitStructure.TIM_Period=arr;//自动重装载值(与预分频值决定计时时间)
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;//预分频值
//72000k/预分频值+1=Nk,1k=0.5ms,Nk=1/N ms,再乘自动重装载值等于计数值
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//时钟分频因子
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数模式
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure );
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占式优先级,按自己需求配置
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//响应式优先级
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//通道1
TIM_ICInitStructure.TIM_ICFilter=0x00;//ICFILTER <= 0xF//滤波
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性为上升沿
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射
TIM_ICInit(TIM5, &TIM_ICInitStructure);
TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE);//两个中断,溢出和捕获中断
TIM_Cmd( TIM5, ENABLE);
}
void Touch_Reset()//将电容电释放掉,从零开始,检查充电时间
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_ResetBits( GPIOA, GPIO_Pin_1);//给低电平使电容放电
delay_ms(5);//放电需要时间
TIM_ClearFlag(TIM5, TIM_FLAG_CC2 | TIM_FLAG_Update);
TIM_SetCounter( TIM5, 0);//设定计数器从零开始计数
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
u16 Touch_Get_Val()//捕获高电平的值
{
Touch_Reset();
while(TIM_GetFlagStatus(TIM5, TIM_FLAG_CC2)==0)
{
if(TIM_GetCounter(TIM5)>(Touch_ARR_MAX_VAL-500))
{
return TIM_GetCounter(TIM5);//超时,返回最大值
}
}
return TIM_GetCapture2(TIM5);
}
u8 Touch_Key_Init(u8 psc)//按键程序初始化 //取得未按下触摸键时所得的标准值
{
u8 i=0;
u16 buf[10];
u32 temp;
TIM5_CH2_Input_Init(Touch_ARR_MAX_VAL,psc);
for(i=0;i<10;i++)//循环多次取值,减小所受干扰
{
buf[i]=Touch_Get_Val();
delay_ms(10);
}
u8 j=0;
for(i=0;i<9;i++)//进行排序,取中间6组,进行滤波
{
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++)
{
temp+=buf[i];
touch_default_val=temp/6;
printf("未触摸按键时的值=%d\r\n",touch_default_val);\
}
if(touch_default_val>(Touch_ARR_MAX_VAL/2))
{
return 1;
}
return 0;
}
u16 Touch_Get_MaxVal(u8 s)//取得采样最大值 即按下触摸按键后得到的最大值
{
u16 temp=0;
u16 res=0;
while(s--)
{
temp=Touch_Get_Val();
if(temp>res)res=temp;
}
return res;
}
#define TOUCH_GATE_VAL 200 //按下触摸后的差值(估计数)
u8 Touch_Key_Scan(u8 mode)//mode为0则单次触摸,为1则连续触摸
{
u16 sample=3;
u16 rval=0;
u8 res=0;
static u8 keyen=0;
if(mode)keyen=0;
rval=Touch_Get_MaxVal(sample);
if(rval>(touch_default_val+TOUCH_GATE_VAL)&&rval<(Touch_ARR_MAX_VAL/2))
{
if((keyen==0)&&rval>(touch_default_val+TOUCH_GATE_VAL))
{
res=1;
}
printf("触摸后捕获高电平值为:%d\r\n",rval);
keyen=1;
}
else
keyen=0;
return res;
}
main.c
#include "stm32f10x.h"
#include "led.h"
#include "system.h"
#include "SysTick.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "time.h"
#include "pwm.h"
#include "usart.h"
#include "stdio.h"
#include "iwdg.h"
#include "wwdg.h"
#include "input.h"
#include "touch_key.h"
int main()
{
u8 i=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组
SysTick_Init(72);
LED_Init();
USART1_Init(115200);//波特率115200
if(Touch_Key_Init(6-1))printf("捕获错误");//每计数一次12us
else
Touch_Key_Init(6-1);
while(1)
{
if(Touch_Key_Scan(0))LED2=!LED2;
i++;
if(i%20==0)LED1=!LED1;
delay_ms(10);
}
}