1. 触摸屏基础:电阻屏与电容屏原理、接口与关键参数
做驱动这么多年,我调试过的触摸屏少说也有几十款了。从早期的电阻屏到现在的多点电容屏,底层原理其实没变过——就是检测触摸位置,然后告诉系统。但你要是真去调驱动,会发现坑多得很。这一章我们先打好基础。
1.1 电阻屏 vs 电容屏:原理与实战差异
先说电阻屏。它的结构很简单:两层透明导电层中间夹着空气。你用手指或者笔按下去,上层就碰到了下层。驱动芯片检测到电压变化,算出坐标。
电阻屏核心原理:通过物理按压使上下导电层接触,形成分压电路。X轴和Y轴分时测量,得到坐标。
我刚开始做驱动时,调的第一块屏就是四线电阻屏。当时有个问题:触摸不准,边缘偏差很大。后来发现是校准算法没做——电阻屏必须做四点或五点校准,因为ITO导电层的均匀性不可能完美。
电容屏就不一样了。它靠的是人体电场。你的手指靠近屏幕时,会改变电极间的电容值。驱动芯片扫描这些电容变化,算出触摸点。
| 对比项 | 电阻屏 | 电容屏 |
|---|---|---|
| 检测原理 | 物理按压接触 | 人体电容耦合 |
| 支持多点 | 不支持(真多点) | 支持(2~10点) |
| 耐用性 | 易磨损 | 表面玻璃,耐用 |
| 透光率 | 约75%~85% | 约90%以上 |
| 成本 | 低 | 中高 |
| 典型应用 | 工业设备、收银机 | 手机、平板、车载 |
我的经验:如果你在调电阻屏驱动,记得把ADC采样次数设成4~8次做均值滤波。不然噪声会让你怀疑人生。电容屏则要注意防水——水滴会模拟出触摸事件,很多消费级方案在湿手场景下表现很差。
1.2 触摸屏接口:I2C、SPI、USB
接口这块,我建议你重点掌握I2C和SPI。因为绝大多数触摸屏都用这两个。USB触摸屏多见于大尺寸交互平板,驱动模型不太一样。
I2C接口
I2C是触摸屏的标配接口。两根线(SCL、SDA),速度一般在400kHz~1MHz。驱动里要做的事情很简单:读寄存器,拿坐标数据。
但有个坑——I2C的地址冲突。我记得有一次,一个项目里触摸屏和光感传感器挂在同一条I2C总线上,地址都是0x38。折腾了两天才发现是地址冲突。后来我习惯在硬件设计阶段就确认好所有I2C设备的地址。
// 典型的I2C触摸屏读坐标流程
static int touch_read_points(struct i2c_client *client, struct touch_data *data)
{
int ret;
uint8_t buf[10];
// 1. 写寄存器地址,告诉芯片我们要读触摸状态
buf[0] = 0x02; // 状态寄存器地址
ret = i2c_master_send(client, buf, 1);
if (ret < 0) return ret;
// 2. 读取触摸数据
ret = i2c_master_recv(client, buf, 10);
if (ret < 0) return ret;
// 3. 解析坐标
data->x = (buf[2] << 8) | buf[3];
data->y = (buf[4] << 8) | buf[5];
data->pressure = buf[6];
return 0;
}
SPI接口
SPI比I2C快,适合高刷新率的触摸屏。四根线(CS、SCLK、MOSI、MISO),速度能跑到几十MHz。但SPI的缺点是占用的GPIO多。
调SPI触摸屏时,我最常遇到的问题就是时序。有些芯片的CS片选信号要求严格——必须在SCLK第一个时钟沿之前拉低,传输结束后再拉高。差几个纳秒就可能读不到数据。
注意:SPI模式下,触摸屏的中断引脚(INT)通常不能省。因为SPI是主设备主动发起通信,如果没有中断,你得不停地轮询,CPU占用率会很高。
USB接口
USB触摸屏本质上是一个HID设备。驱动层直接用Linux内核的HID子系统就能处理。但有个问题——USB触摸屏的坐标范围通常是固定的(比如0~32767),需要做映射到屏幕分辨率。
我调过一款USB触摸框,厂商给的报告描述符里把触摸点数量写死了。结果换了新固件后,多点触摸数据格式变了,驱动直接解析错误。后来我加了一段动态解析报告描述符的逻辑才搞定。
1.3 关键参数:分辨率、刷新率、多点触控
这三个参数直接决定了触摸体验。你想想看,一个刷新率只有30Hz的触摸屏,滑动时明显感觉卡顿。而分辨率不够的话,精细操作根本做不了。
触摸分辨率
触摸分辨率不是屏幕分辨率。它指的是触摸芯片能区分的最小位移。常见的有1024×1024、2048×2048。对于电容屏,分辨率越高,画线越平滑。
我遇到过一个问题:某款触摸屏的分辨率是4096×4096,但屏幕只有1920×1080。驱动里做坐标映射时,如果直接用线性映射,边缘会有1~2个像素的偏差。后来我加了非线性校准才解决。
刷新率
刷新率就是触摸芯片每秒上报数据的次数。单位是Hz。手机触摸屏一般在120Hz~240Hz,工业屏可能只有60Hz。
| 刷新率 | 适用场景 | 注意事项 |
|---|---|---|
| 60Hz | 工业控制、收银机 | 基本够用,滑动有轻微延迟 |
| 120Hz | 中端手机、平板 | 流畅,适合日常操作 |
| 240Hz | 高端手机、游戏设备 | 极低延迟,但功耗高 |
避坑指南:我曾经把一款触摸屏的刷新率从60Hz调到120Hz,结果I2C总线负载过高,导致其他传感器通信异常。后来我改用SPI接口才解决。所以调刷新率时,别忘了看看总线带宽够不够。
多点触控
多点触控分两种:真多点和伪多点。真多点能同时跟踪多个手指的独立坐标,伪多点只能检测到两个手指的简单手势(比如缩放)。
驱动里处理多点触控,最核心的是MT协议(Multi-Touch Protocol)。Linux内核里分Type A和Type B两种。Type A用于不支持硬件跟踪的芯片,每次上报所有触摸点;Type B支持硬件跟踪,每个触摸点有独立的ID。
// Linux MT协议 Type B 上报示例
static void report_touch_points(struct input_dev *dev, struct touch_data *points, int count)
{
int i;
for (i = 0; i < count; i++) {
input_mt_slot(dev, points[i].id); // 设置当前slot
input_mt_report_slot_state(dev, MT_TOOL_FINGER, 1); // 手指按下
input_report_abs(dev, ABS_MT_POSITION_X, points[i].x);
input_report_abs(dev, ABS_MT_POSITION_Y, points[i].y);
input_report_abs(dev, ABS_MT_PRESSURE, points[i].pressure);
}
input_mt_sync_frame(dev); // 同步帧
input_sync(dev);
}
嗯,这里要注意:Type B协议要求驱动维护触摸点的跟踪状态。如果芯片不支持硬件ID,你需要在驱动里自己做跟踪算法。我一般用最近邻匹配——把当前帧的触摸点和上一帧的做距离计算,距离最小的认为是同一个手指。
1.4 本章知识体系
下面这张图把触摸屏的核心知识串起来了。从物理原理到接口协议,再到驱动开发的关键参数,你可以对照着梳理自己的知识盲区。
这张图把触摸屏的知识分成了三个维度:工作原理、接口协议、关键参数。你从任何一个维度切入都可以,但最终都要落到驱动开发上。我个人习惯先搞清楚芯片用的是哪种原理,再看接口类型,最后确认参数范围。这样写驱动时心里有底。