需求情景
如上图,单电容触摸按键,返回的是按键电容对应的一个数值。当人不触碰按键是,,计数值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;
}
}