微控制器入門學習十五 STM32微控制器學習十二 電容觸控按鍵
阿新 • • 發佈:2019-01-24
由電容充放電公式可知:同樣的條件下,電容越大,充電時間越長。
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。
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);
}
}