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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于stm32f10x(原子)的电容触摸实验的个人解读 (16) -> 正文阅读

[嵌入式]基于stm32f10x(原子)的电容触摸实验的个人解读 (16)

? ? ? ? 首先,我先介绍电容触摸按键的原理。

? ? ? ? 一个电容充满电的时候是需要一定时间,当两个电容并联的时候,此时,总电容大小就变成两个电容之和。导致充电的时间变成。电容触摸实验就是基于此,来根据时间的长短变换来确定是否有按键按下,并做出相应的反应。

我们从主函数开始看

????????int main(void)
?{?? ?
??? ?u8 t=0; ??? ?
?? ?delay_init();?? ? ? ??? ? //延时函数初始化?? ? ?
?? ?NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
?? ?uart_init(115200);?? ? //串口初始化为115200
??? ?LED_Init();?? ??? ??? ? ? ? //LED端口初始化
? TPAD_Init(6);?? ??? ??? ?//初始化触摸按键
? ??? ?while(1)
?? ?{?? ??? ??? ??? ??? ? ??? ??? ??? ??? ??? ??? ? ??? ??? ??
??? ??? ?if(TPAD_Scan(0))?? ?//成功捕获到了一次上升沿(此函数执行时间至少15ms)
?? ??? ?{
?? ??? ??? ?LED1=!LED1;?? ??? ?//LED1取反
?? ??? ?}
?? ??? ?t++;
?? ??? ?if(t==15)?? ??? ??
?? ??? ?{
?? ??? ??? ?t=0;
?? ??? ??? ?LED0=!LED0;?? ??? ?//LED0取反,提示程序正在运行
?? ??? ?}
?? ??? ?delay_ms(10);
?? ?}

while里面的先不看。当程序初始化好,走到TPAD_Init(6);?? ??

#define TPAD_ARR_MAX_VAL ?? ?0XFFFF?? ?//最大的ARR值
vu16 tpad_default_val=0;
u8 TPAD_Init(u8 psc)
{
?? ?u16 buf[10];
?? ?u16 temp;
?? ?u8 j,i;
?? ?TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//以12Mhz的频率计数?
?? ?for(i=0;i<10;i++)//连续读取10次
?? ?{?? ??? ??? ??? ??
?? ??? ?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++)temp+=buf[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;?? ??? ? ? ? ?? ? ? ??? ??? ??? ??? ??? ? ??
}

? ? ? ? 开始,程序创建一个数组,为了取平均值,获取没有按键按下时的准确时间;

?TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//以12Mhz的频率计数 (定时器初始化),这里就不说了

这里的定时器时钟频率是72Mhz,所以计数频率是72/(psc-1+1)=12,这是计数频率 ,不是定时器周期。

? ?buf[i]=TPAD_Get_Val();跳转定时器捕获上升沿时间

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);//超时了,直接返回CNT的值
?? ?};?? ?
?? ?return TIM_GetCapture2(TIM5);?? ? ?
} ?? ??

void TPAD_Reset(void)
{
? ?? ?GPIO_InitTypeDef ?GPIO_InitStructure;?
?? ?RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);?? ? //使能PA端口时钟
?? ?
?? ?//设置GPIOA.1为推挽使出
??? ?GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;?? ??? ??? ??? ? //PA1 端口配置
??? ?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);?? ??? ??? ??? ??? ??? ? //PA.1输出0,放电

?? ?delay_ms(5);

?? ?TIM_SetCounter(TIM5,0);?? ??? ?//归0
?? ?TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志
?? ?//设置GPIOA.1为浮空输入
?? ?GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;?? ? //浮空输入
?? ?GPIO_Init(GPIOA, &GPIO_InitStructure);

? ??
}

?? ?TPAD_Reset();

这个函数的目的是为了先将通过引脚输出低电平来达到电容的电放掉的目的,之后,在将引脚设为输入模式,清除中断标志位,这里不需要对中断进行初始化,因为我们用不到中断服务函数,我们只需要确定是否发生中断。

???????? ?while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET)//等待捕获上升沿
?? ?{
?? ??? ?if(TIM_GetCounter(TIM5)>TPAD_ARR_MAX_VAL-500)return TIM_GetCounter(TIM5);//超时了,直接返回CNT的值
?? ?};?? ?
?? ?return TIM_GetCapture2(TIM5);?? ? ?
} ?? ??

如果一直没有捕获上升沿,则

?if(TIM_GetCounter(TIM5)>TPAD_ARR_MAX_VAL-500)return TIM_GetCounter(TIM5);//超时了,直接返回CNT的值(防止非法状态,比如一直是低电平,导致死循环。)这里为什么减500,我也不知道,查资料说是平经验得到的,鬼知道是什么经验;

如果,捕获高电平则返回定时器5 的计数器值

TIM_GetCapture2(TIM5);?

TIM_GetCounter(TIM5);

这两句话其实差别不大,第一句话,适当定时器5 通道处于输入模式下,CCR存放的上次捕获事件 的计数器的值返回。第二句话,是直接返回计数器值。只不过第一个数字更准确点。

? ? ? ? 通过TPAD_Init函数的第一次循环,获取十次没有按下的时间,之后,进行大小排序,去掉最大和最小,求平均,最后输出;

?? ?if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常!
?? ?return 0;? ? ? ? 这里是为了有需要的准备的,因为主函数没有接受,所以也没用。

????????tpad_default_val>TPAD_ARR_MAX_VAL/2 至于这句话怎么得到的,也是凭经验,我也查不到相关资料,只知道凭经验。

? ? ? ? 这样,就彻底得到了没有按键按下的时候的时间T1

接下来,就是获取按键按下的时间

?? ?while(1)
?? ?{?? ??? ??? ??? ??? ? ??? ??? ??? ??? ??? ??? ? ??? ??? ??
??? ??? ?if(TPAD_Scan(0))?? ?//成功捕获到了一次上升沿(此函数执行时间至少15ms)
?? ??? ?{
?? ??? ??? ?LED1=!LED1;?? ??? ?//LED1取反
?? ??? ?}
?? ??? ?t++;
?? ??? ?if(t==15)?? ??? ??
?? ??? ?{
?? ??? ??? ?t=0;
?? ??? ??? ?LED0=!LED0;?? ??? ?//LED0取反,提示程序正在运行
?? ??? ?}
?? ??? ?delay_ms(10);
?? ?}
?}

TPAD_Scan(0)

#define TPAD_GATE_VAL ?? ?100?? ?//触摸的门限值,也就是必须大于tpad_default_val+TPAD_GATE_VAL,才认为是有效触摸.

这里tpad_default_val就是没有按键按下的计数器大小,上面讲过
u8 TPAD_Scan(u8 mode)
{
?? ?static u8 keyen=0;?? ?//0,可以开始检测;>0,还不能开始检测?? ??
?? ?u8 res=0;
?? ?u8 sample=3;?? ??? ?//默认采样次数为3次?? ??
?? ?u16 rval;
?? ?if(mode)
?? ?{
?? ??? ?sample=6;?? ??? ?//支持连按的时候,设置采样次数为6次
?? ??? ?keyen=0;?? ??? ?//支持连按?? ? ?
?? ?}
?? ?rval=TPAD_Get_MaxVal(sample);?
?? ?if(rval>(tpad_default_val+TPAD_GATE_VAL))//大于tpad_default_val+TPAD_GATE_VAL,有效
?? ?{?? ??? ??? ??? ??? ??? ??? ??
?? ??? ?if(keyen==0)res=1;?? ??? ?//keyen==0,有效?
?? ??? ?//printf("r:%d\r\n",rval);?? ??? ? ? ? ?? ? ? ??? ??? ??? ??? ??? ? ??
?? ??? ?keyen=3;?? ??? ??? ??? ?//至少要再过3次之后才能按键有效 ??
?? ?}?
?? ?if(keyen)keyen--;?? ??? ? ? ?? ??? ??? ??? ??? ??? ??? ? ? ?? ??? ? ? ? ?? ? ? ??? ??? ??? ??? ??? ? ??
?? ?return res;
}?? ?

这里的mode的作用就是选择是否支持连续按。这里只讲解mode=0,及不支持连按

TPAD_Get_MaxVal(sample);?

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

这里sample为3,及计算三次。TPAD_Get_Val();这个函数上面讲过,就是获取计数器的值,只不过这里指的是按键按下后的值;

? ?if(temp>res)res=temp;获取3次数值中最大的,返回;

? ?if(rval>(tpad_default_val+TPAD_GATE_VAL))//大于tpad_default_val+TPAD_GATE_VAL,有效
?? ?{?? ??? ??? ??? ??? ??? ??? ??
?? ??? ?if(keyen==0)res=1;?? ??? ?//keyen==0,有效?
?? ??? ?//printf("r:%d\r\n",rval);?? ??? ? ? ? ?? ? ? ??? ??? ??? ??? ??? ? ??
?? ??? ?keyen=3;?? ??? ??? ??? ?//至少要再过3次之后才能按键有效 ??
?? ?}?
?? ?if(keyen)keyen--;?? ??? ? ? ?? ??? ??? ??? ??? ??? ??? ? ? ?? ??? ? ? ? ?? ? ? ??? ??? ??? ??? ??? ? ??
?? ?return res;
}?? ?

如果条件成立,则进行返回1,同时也可以选择输出按键按下的时间

?if(keyen)keyen--;? 这句话,个人认为是进行延时

?? ?if(TPAD_Scan(0))?? ?//成功捕获到了一次上升沿(此函数执行时间至少15ms)
?? ??? ?{
?? ??? ??? ?LED1=!LED1;?? ??? ?//LED1取反
?? ??? ?}
?? ??? ?t++;
?? ??? ?if(t==15)?? ??? ??
?? ??? ?{
?? ??? ??? ?t=0;
?? ??? ??? ?LED0=!LED0;?? ??? ?//LED0取反,提示程序正在运行
?? ??? ?}
?? ??? ?delay_ms(10);
?? ?}
?}
当if语句得到为1时,则可以令灯翻转,得到0,则跳动到下面语句

?t++;
?? ??? ?if(t==15)?? ??? ??
?? ??? ?{
?? ??? ??? ?t=0;
?? ??? ??? ?LED0=!LED0;?? ??? ?//LED0取反,提示程序正在运行
?? ??? ?}
?? ??? ?delay_ms(10);
?? ?}这语句的目的就是告诉我们程序是正在运行的,发生错误的话是TPAD_Scan(0)错误

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:04:50  更:2021-09-03 12:05:15 
 
开发: 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/26 0:41:01-

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