STM32學習筆記(11)電容觸摸按鍵

簡介

用來偵測到手指的有效觸摸,通過觸摸電容屏幕達到類似觸摸按鍵的作用,相對於傳統的機械按鍵有壽命長、佔用空間少、易於操作等諸多優點。

原理

觸摸按鍵原理

未觸摸時,觸摸系統內僅有一個電容,對其先放電再充電,通過輸入捕獲(或其它方法)測出充電所需時間T1,當觸摸時,觸摸系統相當於並聯多一個電容,總電容增大,充電時間延長,通過測量此時充電所需時間T2,如果T2>T1,則已觸摸。(時間測量放在while(1)裏,即時刻測量,當測到T2,即已觸摸時,進行相應函數)

即系統檢測電容充放電時間的方法來判斷是否有觸摸 :

在這裏插入圖片描述

檢測過程

1.TPAD引腳(即觸摸按鍵 )設置爲推輓輸出,輸出0,使電容放電到0;
2.TPAD引腳設置爲浮空輸入(即IO口復位後的狀態),使電容開始充電;同時開啓TPAD引腳的輸入捕獲;
3.等待充電完成(充電到相應界限使得檢測到上升沿)
4.記錄充電時間。

程序思路

圖片源自正點原子視頻:
圖片源自正點原子視頻

代碼相關

代碼實現

1.復位TPAD
1.獲取電容沒有被觸摸時從無電到充電至觸發輸入捕獲的平均時間tpad_default_val

u8 TPAD_Init(u8 psc)  
{
 u16 buf[10];//讀取10次
 u16 temp;//取平均值
 u8 j,i;
 TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//以1Mhz的頻率計數 
 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(ARR最大的值)/2的數值,不正常!
 return 0;

2.得到定時器捕獲值(如果超時,則直接返回定時器的計數值.)

u16 TPAD_Get_Val(void)
{       
 TPAD_Reset();//計數器歸0
 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);   
}   

3.返回n次讀數裏面讀到的最大讀數值,如果這個值比平均值大,則按下

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;
}  

4.設置掃描觸摸按鍵

u8 TPAD_Scan()
{
 static u8 keyen=0; //0,可以開始檢測;>0,還不能開始檢測  
 u8 res=0;
 u8 sample=3;  //默認採樣次數爲3次  
 u16 rval;
 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;
} 

5.以定時器2通道2爲例配置輸入捕獲

void TIM5_CH2_Cap_Init(u16 arr,u16 psc)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef  TIM5_ICInitStructure;
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  //使能TIM5時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能PA端口時鐘
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;     //PA1 端口配置
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //浮空輸入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //設置爲浮空輸入
      
 TIM_TimeBaseStructure.TIM_Period = arr; //設定計數器自動重裝值   
 TIM_TimeBaseStructure.TIM_Prescaler =psc;  //預分頻器     
 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分割:TDTS = Tck_tim
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式
 TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //初始化TIM5
 //初始化通道2
  TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01  選擇輸入端 IC2映射到TI5上
  TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲
  TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; 
  TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;  //配置輸入分頻,不分頻 
  TIM5_ICInitStructure.TIM_ICFilter = 0x03;//IC2F=0011 配置輸入濾波器 8個定時器時鐘週期濾波
  TIM_ICInit(TIM5, &TIM5_ICInitStructure);//初始化I5 IC2

  TIM_Cmd(TIM5,ENABLE );  //使能定時器5
}

之後,在主函數先初始化TPAD_Init(6); 通過對函數TPAD_Scan(0)的判斷確定是否有觸摸

調用10次:取中間6次的平均值,使取值較穩定

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章