由於剛好有小項目需要用到觸摸按鍵,stm8s可以節約一塊觸摸按鍵的片子,並且成本比較低。在某些對成本比較敏感的應用還是有價值的。現將自己網上找到的資料與自己學習的心得記下與大家分析。ST的底層庫對滾動條也支持,效果還是不錯的
一、原理分析
ST的電容式觸摸按鍵方案通過一個電阻和感應電極的電容CX構成的阻容(RC)網絡的充電/放電時間來檢測人體觸摸所帶來的電容變化。
如上圖所示,當人手按下時相當於感應電極上並聯了一個電容Cx,增加了感應電極上的電容,感應電極進行充放電的時間會增加,從而檢測到按鍵的狀態。
先用開關將 Cs(或 Cs+Cx)上的電放盡,然後斷開開關,讓 R 給 Cs(或 Cs+Cx)充電,當沒有手指觸摸的時候, Cs 的充電曲線如圖中的 A 曲線。而當有手指觸摸的時候, 手指和 TPAD之間引入了新的電容 Cx,此時 Cs+Cx 的充電曲線如圖中的 B 曲線。 從上圖可以看出, A、 B兩種情況下, Vc 達到
Vth 的時間分別爲 Tcs 和 Tcs+Tcx。
其中, 除了 Cs 和 Cx 我們需要計算,其他都是已知的,
根據電容充放電公式:Vc=V0*(1-e^(-t/RC))
其中 Vc 爲電容電壓, V0 爲充電電壓, R 爲充電電阻, C 爲電容容值, e 爲自然底數, t 爲充電時間。根據這個公式,我們就可以計算出 Cs 和 Cx。 利用這個公式,我們還可以作一個簡單的電容計,直接可以測電容容量了,有興趣的朋友可以搗鼓下。
其實我們只要能夠區分 Tcs 和 Tcs+Tcx,就已經可以實現觸摸檢測了,當充電時間在 Tcs 附近,就可以認爲沒有觸摸,而當充電時間大於 Tcs+Tx 時,就認爲有觸摸按下( Tx爲檢測閥值)。
實際應用中感應電極可以直接在PCB板上繪製成按鍵、滾輪或滑動條的應用樣式,也可以做成彈簧件插在PCB板上,即使隔着絕緣層(玻璃、樹脂)也不會對其檢測性能有所影響。
二、硬件設計
REF_LOAD:對按鍵進行充放電的引腳,所有按鍵必須共用一個LOAD(保證一致性)。也可以用VCC代替。
SH_MCKEY:屏蔽引腳,這個根據實際情況來覺得是否接,一般調試的時候預留着
PD2-PD6 PC6 PC7爲用戶按鍵部分
注意:不要將按鍵檢測腳安排在True open drain引腳和OSC1/PA1,OSC2/PA2引腳上(前者無法輸出高電平,後者的內部結構與一般IO口不同,不適宜作爲按鍵檢測腳使用)
三、軟件分析
MCU需要資源
1個16位定時器 (用於採集按鍵信號: 測量RC充放電時間)
1個8位定時器 (主要作爲後處理的時基信號)
void main(void)
{
volatile u16 temp;
CLK_HSICmd(ENABLE);//使能HSI
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//
CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);//主頻16M
Delay(10000);
TSL_Init(); //按鍵庫初始化
Extra_Init();
while(1)
{
temp = uMainCounting;
TSL_Action();//獲取按鍵狀態
Runing_Session[0] = uMainCounting - temp;
temp = uMainCounting;
Key_State_Machine();
Runing_Session[1] = uMainCounting - temp;
}
}
void TSL_Init(void)
{
disableInterrupts();
DetectionIntegrator = DETECTION_INTEGRATOR_DEFAULT;
EndDetectionIntegrator = END_DETECTION_INTEGRATOR_DEFAULT;
ECSTimeStep = ECS_TIME_STEP_DEFAULT;
ECSTemporization = ECS_TEMPO_DEFAULT;
RecalibrationIntegrator = RECALIBRATION_INTEGRATOR_DEFAULT;
DetectionTimeout = DTO_DEFAULT;
ECS_K_Fast = ECS_IIR_KFAST_DEFAULT;
ECS_K_Slow = ECS_IIR_KSLOW_DEFAULT;
ECSTimeStepCounter = ECSTimeStep;
ECSTempoCounter = 0;
ECSTempoPrescaler = 0;
TSL_IO_Init();
#if (RTOS_MANAGEMENT == 0)
TSL_Timer_Init();
#endif
#if NUMBER_OF_SINGLE_CHANNEL_KEYS > 0
TSL_SCKey_Init();
#endif
#if NUMBER_OF_MULTI_CHANNEL_KEYS > 0
TSL_MCKey_Init();
#endif
enableInterrupts();
TSLState = TSL_IDLE_STATE;
}