需求情景
如上圖,單電容觸摸按鍵,返回的是按鍵電容對應的一個數值。當人不觸碰按鍵是,,計數值TSICNT大。 當人觸摸按鍵後,TSICNT變小。
如何把具體數值的變化,變成人理解的按下 釋放呢?
設計思路
狀態定義:
空閒狀態 IDLE(檢測是否進入TOUCH狀態;更新BASELINE值;)
人手按下狀態 TOUCH(檢測是否保持TOUCH狀態,還是切到RELEASE狀態)
人手釋放狀態 RELEASE(等待固定時間,進入IDLE狀態)
區間定義:
key_baseline
在人不觸碰TouchSense的情況下,採集一個基準值key_baseline
IDLE狀態定義一個區間
key_baseline-key_baseline_delta ~~~key_baseline+key_baseline_delta
定義成key_idle_low ~~~key_idle_high
key_baseline_delta 取5U
key_touch_delta
定義一個人觸碰下的界限值key_touch_threshold_temp =key_baseline - key_touch_delta
key_touch_delta取200U
狀態轉換條件:
IDLE
key_state_temp = kKey_State_Idle;
key_event = kKey_Event_Idle;
IDEL—>TOUCH
當連續檢測採樣值小於key_touch_threshold_temp 達到MAX_TOUCH_DEBOUNCE這麼多次數,可以認爲肯定有人觸摸按鍵,狀態轉換。
key_state_temp = kKey_State_Touched;
key_event = kKey_Event_Touch;
if (key_state_temp == kKey_State_Idle)
{
key_event = kKey_Event_Idle;
if (TSI_sampleResult < key_touch_threshold_temp)
{
/* There's a finger touch */
key_touch_debounce_temp++;
key_release_debounce_temp = 0U;
if (key_touch_debounce_temp > MAX_TOUCH_DEBOUNCE)
{
key_touch_debounce_temp = 0U;
key_release_debounce_temp = 0U;
key_event = kKey_Event_Touch; /* Indicates the TSI channel is touched */
key_state_temp = kKey_State_Touched;
}
}
else
{
key_touch_debounce_temp = 0U; //從這可以看出需要連續MAX_BASELINE_DEBOUNCE這麼多次
key_release_debounce_temp = 0U;
}
}
TOUCH狀態保持
只要TSI_sampleResult < key_touch_threshold_temp,可以肯定人手一直按着,狀態不變
key_state_temp = kKey_State_Touched;
key_event = kKey_Event_Touch;
TOUCH—>RELEASE
當TSI_sampleResult > key_touch_threshold_temp,開始計次數,如果連續MAX_TOUCH_DEBOUNCE這麼多次採樣值都大於key_touch_threshold_temp,可以確定人手釋放,狀態切換。
key_event = kKey_Event_Release;
key_state_temp = kKey_State_Released;
else if (key_state_temp == kKey_State_Touched)
{
key_event = kKey_Event_Touched; /* Indicates the TSI channel is touched */
if (TSI_sampleResult < key_touch_threshold_temp)
{
/* Indicates the TSI channel is Stick Touched */
key_release_debounce_temp = 0U; //這邊清零了,所以是需要連續的MAX_TOUCH_DEBOUNCE次release檢測
}
else
{
/* Condition: finger touch release */
key_touch_debounce_temp = 0U;
key_release_debounce_temp++;
if (key_release_debounce_temp > MAX_TOUCH_DEBOUNCE)
{
key_release_debounce_temp = 0U;
key_event = kKey_Event_Release;
key_state_temp = kKey_State_Released;
}
}
}
RELEASE—>IDLE
等待適合的時間,狀態切換。
key_event = kKey_Event_Idle;
key_state_temp = kKey_State_Idle;
IDLE區間的實時更新:
我們想保證按鍵事件的準確,必須保證key_baseline_temp這個基準的準確。那怎麼調整基準值,啥時調整的?
這時候就是key_idle_low和key_idle_high這兩個值登場的時候啦。key_baseline_delta 取5U,所以key_idle_low和key_idle_high相差10U。
上調
只要檢測到TSI_sampleResult > key_idle_high,就計數一次。連續檢測到MAX_BASELINE_DEBOUNCE這麼多次,就 把基準上調1;
key_baseline_temp = key_baseline_temp + 1U;
下調
只要檢測到TSI_sampleResult < key_idle_low,就計數一次。連續檢測到MAX_BASELINE_DEBOUNCE這麼多次,就 把基準下調1;
key_baseline_temp = key_baseline_temp - 1U;
else if (TSI_sampleResult > key_idle_high)
{
key_touch_debounce_temp = 0U;
key_base_debounce_temp++;
if (key_base_debounce_temp > MAX_BASELINE_DEBOUNCE)
{
key_base_debounce_temp = 0U;
key_baseline_temp = key_baseline_temp + 1U;
}
}
else if (TSI_sampleResult < key_idle_low)
{
key_touch_debounce_temp = 0U;
key_base_debounce_temp++;
if (key_base_debounce_temp > MAX_BASELINE_DEBOUNCE)
{
key_base_debounce_temp = 0U;
key_baseline_temp = key_baseline_temp - 1U;
}
}
else
{
key_touch_debounce_temp = 0U;
key_base_debounce_temp = 0U;//這邊清零了,所以是需要連續的MAX_TOUCH_DEBOUNCE次base_debounce檢測
}
學習程序過程遇到問題
/* Key event indicates momentary actions */
typedef enum _key_event
{
kKey_Event_Idle = 0U, /* Key is not touched */
kKey_Event_Touch, /* Key is touched for the first time */
kKey_Event_Touched, /* Key has been touched */
kKey_Event_Stick, /* Key has been touched for a long time */
kKey_Event_Release, /* Key is released for the first time */
kKey_Event_Released, /* Key has been released */
kKey_Event_Abnormal, /* Key is in abnormal status */
}key_event_t;
kKey_Event_Release, /* Key is released for the first time */
kKey_Event_Released, /* Key has been released */
就是沒看清這個Release 和 Released兩個狀態
感覺Released狀態就是爲了在正確檢測到release之後等待一會兒,等電容值迴歸到正常值,再進入IDLE狀態。如果直接進入IDLE狀態,程序就會開始不停的進行key_baseline的調整。怎麼感覺這種功能可以通過調節觸發進入Release的計數次數來改變啊???
爲什麼要等待合適時間?其實是主程序的需求。主程序需要檢測到release這個狀態進行輸出。
else if (key_state_temp == kKey_State_Touched)
{
key_event = kKey_Event_Touched; /* Indicates the TSI channel is touched */
if (TSI_sampleResult < key_touch_threshold_temp)
{
/* Indicates the TSI channel is Stick Touched */
key_release_debounce_temp = 0U;
}
else
{
/* Condition: finger touch release */
key_touch_debounce_temp = 0U;
key_release_debounce_temp++;
if (key_release_debounce_temp > MAX_TOUCH_DEBOUNCE)
{
key_release_debounce_temp = 0U;
key_event = kKey_Event_Release;
key_state_temp = kKey_State_Released;
}
}
}
else if (key_state_temp == kKey_State_Released)
{
/* Restore KEY_STATE_IDLE automatically */
key_event = kKey_Event_Released;
key_release_debounce_temp++;
if (key_release_debounce_temp > 10U)
{
/* Delay to assure this key is sent */
key_release_debounce_temp = 0U;
key_event = kKey_Event_Idle;
key_state_temp = kKey_State_Idle;
}
}