当前位置: 首页>編程日記>正文

stm32学习笔记——电容触摸按键的实现

stm32学习笔记——电容触摸按键的实现

目录

一、电容触摸按键原理

二、正点原子战舰开发板对应的硬件原理图 

三、代码实现

1.定时器的初始化配置函数(此处使用通用定时器TIM5的通道2,对应的端口是)

2.电容触摸按键初始化

3、捕获一次充电时间的函数 

4、按键检测函数

总结


一、电容触摸按键原理

触摸电容按键工作原理:当手按下时,形成附加电容,按下和松开两种状态的区别是电路中的电容值不同。而电容值的不同可以体现在充电时间上。所以可以利用输入捕获充电时间实现按键检测。

二、正点原子战舰开发板对应的硬件原理图 

 1、电容触摸按键电路是片外电路,要实现电容充放电状态切换,可以将其连接到芯片端口。通过端口状态从开漏输出或推挽输出,到浮空输入的状态转换,实现从放电到充电的状态转换。

2、补充说明:

①关于为什么开漏和推挽输出可以实现电容的放电?

 对端口设置为推挽输出或者开漏输出,并将其置0,可以实现电容的放电(本质原因:无论是开漏模式还是推挽模式,置0都是将电容接到地,可以实现放电)

②关于为什么充电时端口要设置为浮空输入?

将对应的端口置为浮空输入(浮空即没有芯片内部电流影响外电路电容充电),当充电到一定值,电容上电压达到一定值,使得施密特触发器产生一定输出,也即可以检测到上升沿,可以触发输入捕获时间。

3、此处使用通用定时器TIM5的通道2,对应的端口是PA.1,将正点原子战舰开发板的P7.1和P7.2用跳线帽连接。也即实现了端口PA.1与外电路触摸电容相连,进而可以控制外电路电容充放电,并实现输入捕获充电时间。

三、代码实现

1.定时器的初始化配置函数(此处使用通用定时器TIM5的通道2,对应的端口是)

代码如下:

void TIM5_IC2Init(uint16_t pre,uint16_t reload)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_ICInitTypeDef TIM_ICInitStruct;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_ResetBits(GPIOA,GPIO_Pin_1);delay_ms(100);//放电TIM_TimeBaseInitStruct.TIM_Prescaler = pre;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period = reload;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStruct.TIM_ICFilter = 0x00;//不采用滤波器TIM_ICInit(TIM5,&TIM_ICInitStruct);    TIM_Cmd(TIM5,ENABLE);}

2.电容触摸按键初始化

说明:利用该函数获得未按下时的充电时间,与后面按下时的充电时间作比较,进而可以判断是否按下。

代码如下:

uint16_t TPAD_Init_val;//全局变量用于存储未按下时的充电时间
void TPAD_Init(void)
{uint16_t buf[10];uint8_t i;uint8_t j;uint16_t temp;for(i=1;i<=10;i++){buf[i-1]= get_val();delay_ms(10);}for(i=0;i<9;i++){for(j=0;j<9-i;j++){if(buf[j]<buf[j+1])//从大到小排序{temp = buf[j];buf[j] = buf[j+1];buf[j+1] = temp;}}}temp = 0;for(i=2;i<8;i++){temp += buf[i];}TPAD_Init_val = temp/6;}

补充说明:为了提高可靠性,捕获10次充电时间,并去掉两个最大和最小值,再取平均值。

3、捕获一次充电时间的函数 

说明:要捕获一次充电时间要经过一下几个步骤:①放电②计数器清零、标志位清零③充电④根据标志位读取定时器输入捕获的充电时间,并返回

代码如下:


uint16_t get_val(void)
{uint16_t temp;GPIO_InitTypeDef GPIO_InitStructure;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_Out_OD;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_ResetBits(GPIOA,GPIO_Pin_1);delay_ms(5);//放电TIM_ClearITPendingBit(TIM5,TIM_IT_CC2);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA,&GPIO_InitStructure);//充电TIM_SetCounter(TIM5,0);//计数器清零while( TIM_GetFlagStatus(TIM5,TIM_IT_CC2)!=SET){if(TIM_GetCounter(TIM5)>max_count-500)//认为已经超时了{return TIM_GetCounter(TIM5);}}temp = TIM_GetCapture2(TIM5);return temp;}

补充说明:

1、注意标志位的判断的库函数一定不要使用错误!!!要用TIM_GetFlagStatus而不能用

TIM_GetITStatus。二者的区别是,库函数FlagStatus单纯判断标志位是否置位,即当事件发生但是没有使能对应事件的中断时,标志位仍然置位,但没有发生中断。而库函数ITStatus,不仅判断了标志位还判断了使能位,只有当中断发生(事件发生+中断使能)才返回SET。

2、注意分清标志位和中断的概念区别

当某个模块(比如串口、定时器)含有状态寄存器则涉及标志位和中断之间的区别,进而有库函数FlagStatus和ITStatus的使用区别。
标志位置位,是指当某事件发生时,无论对应的中断是否使能都会使得相应的标志位置位。
而当对应的中断也使能时,可以产生中断,此时要进行中断优先级配置、初始化配置、编写中断服务函数。

而此实验中只使用了标志位,而没有使用中断,所以不用进行中断优先级配置、初始化配置、编写中断服务函数。

3、关于TIM_ClearITPendingBit(TIM5,TIM_IT_CC2);

此处虽然没有用到中断,且中断和标志位的概念不同。但是清除中断标志位和标志位都是对SR寄存器操作,故可以替代使用。

4、按键检测函数

说明:不断检测是否按下,本质是不断捕获充电时间,如果充电时间大于设置的门限值(实验确定),则认为按下。

代码如下:


uint8_t TPAD_Scan(void)
{//实现不支持连按的第一种思路(以松开的检测值作为松开标志)static uint8_t flag = 0;uint16_t temp = get_val_max(sampletime);if(temp < TPAD_Init_val+10 ){flag = 0;}if((temp>TPAD_Init_val+TPAD_gate_val)&&(!flag)){printf("get_val_max %d\r\n",temp);flag = 1;return 1;}else return 0;//实现不支持连按的第二种思路,以不满足按下条件作为松开标志//第二种思路的结果性能更稳定:可以通过改变标志变量的值改变检测按下与松开状态切换的时间间隔。//编写代码思路:从简入手,即先实现支持连按的,再加标志/*uint8_t res = 0;static uint8_t flag = 0;if(get_val_max(sampletime)>TPAD_Init_val+TPAD_gate_val)//TPAD_gate_val是宏定义的门限值(具体值通过实验确定){if(flag == 0){res = 1;}flag = 3;}if(flag){flag--;}return res;*/
}

 补充说明:

1、实现按键检测思路(不支持连按)


 2、一次检测涉及三次输入捕获,取最大值,提高可靠性

三次输入捕获获得最大值的代码如下:

uint16_t get_val_max(uint8_t n)
{uint16_t temp;uint16_t val_max;val_max = get_val();while(n-1){temp = get_val();printf("get_val is %d\r\n",temp);if(temp > val_max){val_max = temp;}n--;}return val_max;
}

 3、如果连续三次检测不能满足按下条件则认为松开了,则改变标志变量,进而可以检测下一次按下

总结

以上就是今天要讲的内容,本文简单介绍了正点原子开发板触摸按键的使用以及代码编写过程中的注意事项。

·

希望大家多多支持,一键三连呀~~~


https://www.fengoutiyan.com/post/15306.html

相关文章:

  • 鏡像模式如何設置在哪,圖片鏡像操作
  • 什么軟件可以把圖片鏡像翻轉,C#圖片處理 解決左右鏡像相反(旋轉圖片)
  • 手機照片鏡像翻轉,C#圖像鏡像
  • 視頻鏡像翻轉軟件,python圖片鏡像翻轉_python中鏡像實現方法
  • 什么軟件可以把圖片鏡像翻轉,利用PS實現圖片的鏡像處理
  • 照片鏡像翻轉app,java實現圖片鏡像翻轉
  • 什么軟件可以把圖片鏡像翻轉,python圖片鏡像翻轉_python圖像處理之鏡像實現方法
  • matlab下載,matlab如何鏡像處理圖片,matlab實現圖像鏡像
  • 圖片鏡像翻轉,MATLAB:鏡像圖片
  • 鏡像翻轉圖片的軟件,圖像處理:實現圖片鏡像(基于python)
  • canvas可畫,JavaScript - canvas - 鏡像圖片
  • 圖片鏡像翻轉,UGUI優化:使用鏡像圖片
  • Codeforces,CodeForces 1253C
  • MySQL下載安裝,Mysql ERROR: 1253 解決方法
  • 勝利大逃亡英雄逃亡方案,HDU - 1253 勝利大逃亡 BFS
  • 大一c語言期末考試試題及答案匯總,電大計算機C語言1253,1253《C語言程序設計》電大期末精彩試題及其問題詳解
  • lu求解線性方程組,P1253 [yLOI2018] 扶蘇的問題 (線段樹)
  • c語言程序設計基礎題庫,1253號C語言程序設計試題,2016年1月試卷號1253C語言程序設計A.pdf
  • 信奧賽一本通官網,【信奧賽一本通】1253:抓住那頭牛(詳細代碼)
  • c語言程序設計1253,1253c語言程序設計a(2010年1月)
  • 勝利大逃亡英雄逃亡方案,BFS——1253 勝利大逃亡
  • 直流電壓測量模塊,IM1253B交直流電能計量模塊(艾銳達光電)
  • c語言程序設計第三版課后答案,【渝粵題庫】國家開放大學2021春1253C語言程序設計答案
  • 18轉換為二進制,1253. 將數字轉換為16進制
  • light-emitting diode,LightOJ-1253 Misere Nim
  • masterroyale魔改版,1253 Dungeon Master
  • codeformer官網中文版,codeforces.1253 B
  • c語言程序設計考研真題及答案,2020C語言程序設計1253,1253計算機科學與技術專業C語言程序設計A科目2020年09月國家開 放大學(中央廣播電視大學)
  • c語言程序設計基礎題庫,1253本科2016c語言程序設計試題,1253電大《C語言程序設計A》試題和答案200901
  • 肇事逃逸車輛無法聯系到車主怎么辦,1253尋找肇事司機