1. 程式人生 > >微控制器入門學習十五 STM32微控制器學習十二 電容觸控按鍵

微控制器入門學習十五 STM32微控制器學習十二 電容觸控按鍵

由電容充放電公式x=V1[1etRC]可知:同樣的條件下,電容越大,充電時間越長。

1、電容觸控按鍵原理

電容觸控按鍵原理如下圖:
電容觸控按鍵
R:外接電容充放電電阻。
Cs:TPAD和PCB間的雜散電容。
Cx:手指按下時,手指和TPAD之間的電容。
開關:電容放電開關,由STM32 IO口代替。

當手指按下時,相當於並聯了一個電容,故C=C1+C2,電容值變大,則T變長,若將沒有觸控電容觸控按鍵前的充電時間記為T1,手指觸控後的時間記為T2,則可以認為T2-T1大於某個值,就可以判斷有按鍵按下了。

2、檢測電容觸控按鍵過程

①TPAD引腳設定為推輓輸出,輸出0,實現電容放電到0。
②TPAD引腳設定為浮空輸入(IO復位後的狀態),電容開始充電。
③同時開啟TPAD引腳的輸入捕獲開始捕獲。
④等待充電完成(充電到底Vx,檢測到上升沿)。
⑤計算充電時間。

3、電容觸控按鍵硬體連線

連線

從上圖中看出電容與stm32引腳PA1連線,從下圖中可以看出PA1可以使用TIM5的通道2,也可以使用TIM2的通道2。
PA1

4、示例程式碼

本示例程式碼實現的功能是 通過觸控 電容觸控按鍵完成LED1燈的亮滅。
程式思路圖如下:
思路

程式程式碼如下:

#define TPAD_ARR_MAX_VAL    0XFFFF  //最大的ARR值
vu16 tpad_default_val=0;//空載的時候(沒有手按下),計數器需要的時間


//初始化觸控按鍵
//獲得空載的時候觸控按鍵的取值.
//返回值:0,初始化成功;1,初始化失敗
u8 TPAD_Init(u8 psc)
{
    u16 buf[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/2的數值,不正常! return 0; } //復位一次 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); } //得到定時器捕獲值 //如果超時,則直接返回定時器的計數值. 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); } //讀取n次,取最大值 //n:連續獲取的次數 //返回值: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; } //掃描觸控按鍵 //mode:0,不支援連續觸發(按下一次必須鬆開才能按下一次);1,支援連續觸發(可以一直按下) //返回值:0,沒有按下;1,有按下; #define TPAD_GATE_VAL 100 //觸控的門限值,也就是必須大於tpad_default_val+TPAD_GATE_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; } //定時器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埠時鐘 //設定GPIOA.1為浮空輸入 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); //設定為浮空輸入 //初始化TIM5 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); //根據TIM_TimeBaseInitStruct中指定的引數初始化TIMx的時間基數單位 //初始化通道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 } int main(void) { u8 t=0; delay_init(); //延時函式初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設定NVIC中斷分組2:2位搶佔優先順序,2位響應優先順序 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); } }