华诚HC8T046P触控IC有4个输入/输出管脚,所以最大可以实现三通道输入。用这颗IC实现三通道触摸的最大难点在于只有一个通道负责输出,三个通道三种波形,如果对波形识别不准确就会导致窜键的产生。
P10~P13是4个输入/输出管脚
IC定制P10、P11、P13触摸输入管脚,P12为PWM输出管脚。IC上电P12输出为低电平;P10通道被触摸P12通道持续输出高电平,P10触摸松开后P12恢复低电平;P11通被道触摸P12输出高-低-高,P11触摸松开后P12恢复低电平;P13通道被触摸P12输出高-低-高-低-高,P13触摸松开后P12恢复低电平;高低电平要持续10ms后才继续变化且IC只响应单通道触摸。
一开始的思路是按下触摸产生中断,由于高/低电平会持续稳定10ms,启动定时器进行10ms一次的采样,将采集到数据(几高几低)与P10、P11、P13的波形进行对比,就可以判断出是哪个通道被触摸。
static void touch_keys_timer(unsigned long _data)
{
struct rk_keys_drvdata *pdata = rk_key_get_drvdata();
struct rk_keys_button *button = (struct rk_keys_button *)_data;
struct input_dev *input = pdata->input;
int state, i, j;
int touch_state[10] = {0};
printk("%s :__LINE__ %d, code %d, gpio_get_value %d\n", __FUNCTION__,\
__LINE__, button->code, gpio_get_value(button->gpio));
while(i < 10)
{
touch_state[i] = gpio_get_value(button->gpio);
for(j = 0; j <= i ; j++)
{
printk("%s:touch_state[%d] %d\n", __func__, j, touch_state[j]);
}
if(4 == i)
{
for(j = 0; j <= i ; j++)
{
printk("%s:touch_state[%d] %d\n", __func__, j, touch_state[j]);
}
if(1 == touch_state[0] && 0 == touch_state[1] && 0 == touch_state[2]\
&& 0 == touch_state[3] && 0 == touch_state[4])
{
printk("i %d, 按键一\n", i);
input_event(input, EV_KEY, 158, 1);
input_sync(input);
input_event(input, EV_KEY, 158, 0);
input_sync(input);
button->isisr = 0;
return;
}
else if(1 == touch_state[0] && 1 == touch_state[1] && \
1 == touch_state[2] && 1 == touch_state[3] && 1 == touch_state[4])
{
printk("i %d, 按键一\n", i);
input_event(input, EV_KEY, 158, 1);
input_sync(input);
input_event(input, EV_KEY, 158, 0);
input_sync(input);
button->isisr = 0;
return;
}
else if(1 == touch_state[0] && 0 == touch_state[1] && \
1 == touch_state[2] && 0 == touch_state[3] && 0 == touch_state[4])
{
printk("i %d, 按键二\n", i);
input_event(input, EV_KEY, 115, 1);
input_sync(input);
input_event(input, EV_KEY, 115, 0);
input_sync(input);
button->isisr = 0;
return;
}
else if(1 == touch_state[0] && 0 == touch_state[1] && \
1 == touch_state[2] && 1 == touch_state[3] && 1 == touch_state[4])
{
printk("i %d, 按键二\n", i);
input_event(input, EV_KEY, 115, 1);
input_sync(input);
input_event(input, EV_KEY, 115, 0);
input_sync(input);
button->isisr = 0;
return;
}
else if(1 == touch_state[0] && 0 == touch_state[1] && \
1 == touch_state[2] && 0 == touch_state[3] && 1 == touch_state[4])
{
printk("i %d, 按键三\n", i);
input_event(input, EV_KEY, 114, 1);
input_sync(input);
input_event(input, EV_KEY, 114, 0);
input_sync(input);
button->isisr = 0;
return;
}
else
{
printk("其他情况\n");
button->isisr = 0;
return;
}
}
i++;
mdelay(11);
};
button->isisr = 0;
button->isr_count = 0;
return;
}
然而担心的问题出现了,不管怎么调整采样的时间,都会出现窜键。通过示波器观察波形,导致窜键的原因是高/低电平有几率出现不到10ms就开始变化,如下图:
在查看LOG过程中,我发现对应的通过产生的中断个数是固定的。比如触摸P10通道,输出高电平,这时候只产生一个中断;触摸P11通道,输出高-低-高,产生两个中断;触摸P13通道,输出高-低-高-低-高,产生三个中断(设置为上升沿中断)。
于是可以通过采样中断次数来判断是哪个通道被触摸,将上面的代码修改如下:
static void touch_keys_timer(unsigned long _data)
{
struct rk_keys_drvdata *pdata = rk_key_get_drvdata();
struct rk_keys_button *button = (struct rk_keys_button *)_data;
struct input_dev *input = pdata->input;
int state, i, j;
int touch_state[10] = {0};
printk("%s :__LINE__ %d, code %d, gpio_get_value %d\n",__FUNCTION__,\
__LINE__, button->code, gpio_get_value(button->gpio));
while(i < 10)
{
touch_state[i] = gpio_get_value(button->gpio);
for(j = 0; j <= i ; j++)
{
printk("%s:touch_state[%d] %d\n", __func__, j, touch_state[j]);
}
if(4 == i)
{
printk("中断次数 %d\n", button->isr_count);
if(button->isr_count == 1)
{
printk("i %d, 按键一\n", i);
input_event(input, EV_KEY, 158, 1);
input_sync(input);
input_event(input, EV_KEY, 158, 0);
input_sync(input);
button->isisr = 0;
button->isr_count = 0;
return;
}
else if(button->isr_count == 2)
{
printk("i %d, 按键二\n", i);
input_event(input, EV_KEY, 115, 1);
input_sync(input);
input_event(input, EV_KEY, 115, 0);
input_sync(input);
button->isisr = 0;
button->isr_count = 0;
return;
}
else if (button->isr_count == 3)
{
printk("i %d, 按键三\n", i);
input_event(input, EV_KEY, 114, 1);
input_sync(input);
input_event(input, EV_KEY, 114, 0);
input_sync(input);
button->isisr = 0;
button->isr_count = 0;
return;
}
else
{
printk("其他情况\n");
button->isisr = 0;
button->isr_count = 0;
return;
}
}
i++;
mdelay(11);
};
button->isisr = 0;
button->isr_count = 0;
return;
}
目前触控只是实现了短触的功能,长触还为实现。