天天看點

STM32學習筆記(11)電容觸摸按鍵簡介原理代碼相關

文章目錄

  • 簡介
  • 原理
    • 觸摸按鍵原理
    • 檢測過程
    • 程式思路
  • 代碼相關
    • 代碼實作

簡介

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

原理

觸摸按鍵原理

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

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

STM32學習筆記(11)電容觸摸按鍵簡介原理代碼相關

檢測過程

1.TPAD引腳(即觸摸按鍵 )設定為推挽輸出,輸出0,使電容放電到0;

2.TPAD引腳設定為浮空輸入(即IO口複位後的狀态),使電容開始充電;同時開啟TPAD引腳的輸入捕獲;

3.等待充電完成(充電到相應界限使得檢測到上升沿)

4.記錄充電時間。

程式思路

圖檔源自正點原子視訊:

STM32學習筆記(11)電容觸摸按鍵簡介原理代碼相關

代碼相關

代碼實作

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次的平均值,使取值較穩定