5.6 Touch 设备
2026/7/18大约 9 分钟设备驱动驱动设备Touch触摸屏
5.6 Touch 设备
📚 本节导读
学习时长: 约 40 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: C 语言基础、触摸屏基础知识、5.1 设备驱动框架
🎯 学习目标
- 理解 OneOS 中 Touch 设备的框架设计与中断回调机制
- 掌握触摸事件的四种类型(按下、抬起、移动、无事件)
- 掌握 Touch 设备的控制命令(获取 ID、设置范围、交换坐标等)
- 理解多点触控的数据结构
- 能够编写触摸屏事件处理程序
一、概述
Touch(触摸屏)设备是嵌入式人机交互的重要输入设备。OneOS 将触摸屏抽象为 OS_DEVICE_TYPE_TOUCH 类型设备,提供统一的事件处理机制。Touch 设备驱动位于 drivers/touch/ 目录下,核心头文件为 touch.h。
Touch 设备框架的特点:
- 中断回调:通过
irq_handle中断回调函数处理触摸事件,无需轮询 - 事件驱动:支持按下(DOWN)、抬起(UP)、移动(MOVE)三种触摸事件
- 多点触控:通过
track_id追踪多点,支持多点同时触摸 - 坐标变换:支持物理坐标与用户坐标的范围映射与交换
- 时间戳:每条触摸数据附带时间戳,支持 RTC 或系统滴答两种时钟源
二、核心数据结构
2.1 Touch 设备结构体 os_touch_device
typedef struct os_touch_device os_touch_t;
struct os_touch_device
{
struct os_device parent; /* 继承自 os_device_t */
struct os_touch_info info; /* 触摸设备信息 */
struct os_touch_config config; /* 触摸设备配置 */
const struct os_touch_ops *ops; /* Touch 操作函数表 */
os_err_t (*irq_handle)(os_touch_t *touch); /* 中断回调函数 */
};os_touch_device 继承自 os_device_t。其中 irq_handle 是由驱动层注册的中断处理函数,当触摸屏产生中断时被调用。
2.2 触摸设备信息 os_touch_info
struct os_touch_info
{
uint8_t type; /* 触摸类型(电容/电阻) */
uint8_t vendor; /* 触摸芯片厂商 */
uint8_t point_num; /* 支持的最大触摸点数 */
int32_t range_x; /* X 轴物理坐标范围 */
int32_t range_y; /* Y 轴物理坐标范围 */
int32_t user_range_x; /* 用户自定义 X 轴范围 */
int32_t user_range_y; /* 用户自定义 Y 轴范围 */
};2.3 触摸设备配置 os_touch_config
struct os_touch_config
{
struct os_device_pin_mode *irq_pin; /* 中断引脚配置 */
char *dev_name; /* 通信设备名称(如 I2C 设备名) */
void *user_data;
};2.4 触摸数据 os_touch_data
struct os_touch_data
{
uint8_t event; /* 触摸事件类型 */
uint8_t track_id; /* 触摸点 ID(多点触控标识) */
uint8_t width; /* 触摸点宽度 */
uint16_t x_coordinate; /* X 坐标 */
uint16_t y_coordinate; /* Y 坐标 */
os_tick_t timestamp; /* 数据时间戳 */
};每条触摸数据包含事件类型、轨迹 ID、坐标、宽度和时间戳,支持多点触控追踪。
2.5 Touch 操作函数表 os_touch_ops
struct os_touch_ops
{
os_size_t (*touch_readpoint)(struct os_touch_device *touch, struct os_touch_data *data, os_size_t touch_num);
os_err_t (*touch_control)(struct os_touch_device *touch, int cmd, void *arg);
};| 函数指针 | 说明 |
|---|---|
touch_readpoint | 读取触摸点数据,返回实际读取的点数 |
touch_control | 控制命令处理(获取 ID、设置范围等) |
三、触摸事件类型
#define OS_TOUCH_EVENT_NONE (0) /* 无事件 */
#define OS_TOUCH_EVENT_UP (1) /* 抬起事件 */
#define OS_TOUCH_EVENT_DOWN (2) /* 按下事件 */
#define OS_TOUCH_EVENT_MOVE (3) /* 移动事件 */| 事件 | 值 | 说明 |
|---|---|---|
OS_TOUCH_EVENT_NONE | 0 | 无触摸事件 |
OS_TOUCH_EVENT_UP | 1 | 手指从触摸屏抬起 |
OS_TOUCH_EVENT_DOWN | 2 | 手指按下触摸屏 |
OS_TOUCH_EVENT_MOVE | 3 | 手指在触摸屏上滑动 |
四、触摸芯片类型
4.1 厂商类型
#define OS_TOUCH_VENDOR_UNKNOWN (0) /* 未知厂商 */
#define OS_TOUCH_VENDOR_GT (1) /* GTxx 系列(汇顶) */
#define OS_TOUCH_VENDOR_FT (2) /* FTxx 系列(敦泰) */4.2 触摸 IC 类型
#define OS_TOUCH_TYPE_NONE (0) /* 无触摸 IC */
#define OS_TOUCH_TYPE_CAPACITANCE (1) /* 电容式触摸 IC */
#define OS_TOUCH_TYPE_RESISTANCE (2) /* 电阻式触摸 IC */五、控制命令
#define OS_TOUCH_CTRL_GET_ID (0) /* 获取设备 ID */
#define OS_TOUCH_CTRL_GET_INFO (1) /* 获取触摸设备信息 */
#define OS_TOUCH_CTRL_SET_MODE (2) /* 设置工作模式(轮询/中断) */
#define OS_TOUCH_CTRL_SET_X_RANGE (3) /* 设置 X 轴物理坐标范围 */
#define OS_TOUCH_CTRL_SET_Y_RANGE (4) /* 设置 Y 轴物理坐标范围 */
#define OS_TOUCH_CTRL_SET_USER_X_RANGE (5) /* 设置用户自定义 X 轴范围 */
#define OS_TOUCH_CTRL_SET_USER_Y_RANGE (6) /* 设置用户自定义 Y 轴范围 */
#define OS_TOUCH_CTRL_SET_X_TO_Y (7) /* 交换 X/Y 坐标 */
#define OS_TOUCH_CTRL_DISABLE_INT (8) /* 禁用中断 */
#define OS_TOUCH_CTRL_ENABLE_INT (9) /* 使能中断 */| 命令 | 说明 |
|---|---|
OS_TOUCH_CTRL_GET_ID | 读取触摸芯片 ID,用于验证驱动匹配 |
OS_TOUCH_CTRL_GET_INFO | 获取 os_touch_info 结构体的完整信息 |
OS_TOUCH_CTRL_SET_MODE | 设置轮询或中断工作模式 |
OS_TOUCH_CTRL_SET_X_RANGE | 设置物理 X 坐标范围(用于校准) |
OS_TOUCH_CTRL_SET_Y_RANGE | 设置物理 Y 坐标范围(用于校准) |
OS_TOUCH_CTRL_SET_USER_X_RANGE | 设置用户坐标系 X 范围(如映射到屏幕分辨率) |
OS_TOUCH_CTRL_SET_USER_Y_RANGE | 设置用户坐标系 Y 范围 |
OS_TOUCH_CTRL_SET_X_TO_Y | 交换 X/Y 轴(用于横竖屏切换) |
OS_TOUCH_CTRL_DISABLE_INT | 禁用触摸中断 |
OS_TOUCH_CTRL_ENABLE_INT | 使能触摸中断 |
六、时间戳获取
#ifdef OS_USING_RTC
#define os_touch_get_ts() time(OS_NULL) /* 使用 RTC 时间戳 */
#else
#define os_touch_get_ts() os_tick_get_value() /* 使用系统滴答时间戳 */
#endif根据系统配置,时间戳来源可以是 RTC 实时时钟或系统滴答计数器。
七、核心 API 详解
7.1 注册 Touch 设备
int os_hw_touch_register(os_touch_t *touch, const char *name, void *data);- 注册触摸屏设备到设备框架,通常由 BSP 层调用
touch:Touch 设备结构体指针,必须已填充ops和info字段name:设备名称,如"touch"、"touch0"data:用户自定义数据指针- 返回值:注册成功返回
OS_EOK
7.2 中断通知
void os_touch_irq_notify(os_touch_t *touch);- 底层驱动在触摸中断中调用,通知上层有触摸事件
- 内部调用
os_device_recv_notify()唤醒等待读取的任务
7.3 通过设备框架操作 Touch
Touch 设备使用标准设备框架 API 进行读写和控制:
/* 打开设备 */
os_device_t *dev = os_device_open_s("touch");
/* 读取触摸点数据 */
struct os_touch_data data;
os_device_read_block(dev, 0, &data, sizeof(data));
/* 控制命令 */
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_GET_INFO), &info);
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_SET_X_RANGE), &x_range);
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_ENABLE_INT), OS_NULL);八、使用示例
示例 1:触摸事件处理
#include <touch.h>
#include <device.h>
#include <os_task.h>
#define TOUCH_DEV_NAME "touch"
void touch_demo_task(void *arg)
{
os_device_t *dev;
struct os_touch_data data;
dev = os_device_open_s(TOUCH_DEV_NAME);
if (dev == OS_NULL)
{
os_kprintf("Failed to open touch device\r\n");
return;
}
while (1)
{
/* 阻塞等待触摸事件 */
if (os_device_read_block(dev, 0, &data, sizeof(data)) == sizeof(data))
{
switch (data.event)
{
case OS_TOUCH_EVENT_DOWN:
os_kprintf("Touch DOWN: (%d, %d), track_id=%d, width=%d, ts=%d\r\n",
data.x_coordinate, data.y_coordinate,
data.track_id, data.width, data.timestamp);
break;
case OS_TOUCH_EVENT_MOVE:
os_kprintf("Touch MOVE: (%d, %d), track_id=%d\r\n",
data.x_coordinate, data.y_coordinate,
data.track_id);
break;
case OS_TOUCH_EVENT_UP:
os_kprintf("Touch UP: (%d, %d), track_id=%d\r\n",
data.x_coordinate, data.y_coordinate,
data.track_id);
break;
default:
break;
}
}
}
}示例 2:获取触摸设备信息
#include <touch.h>
#include <device.h>
void get_touch_info_demo(void)
{
os_device_t *dev;
struct os_touch_info info;
dev = os_device_open_s("touch");
if (dev == OS_NULL) return;
/* 获取触摸设备信息 */
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_GET_INFO), &info);
os_kprintf("Touch Device Info:\r\n");
os_kprintf(" Type: %s\r\n", info.type == OS_TOUCH_TYPE_CAPACITANCE ? "Capacitance" : "Resistance");
os_kprintf(" Vendor: %d\r\n", info.vendor);
os_kprintf(" Point Num: %d\r\n", info.point_num);
os_kprintf(" Range X: %d\r\n", info.range_x);
os_kprintf(" Range Y: %d\r\n", info.range_y);
os_device_close(dev);
}示例 3:坐标校准与映射
#include <touch.h>
#include <device.h>
void calibrate_touch_demo(void)
{
os_device_t *dev;
int32_t x_range = 4096; /* 物理 X 范围 */
int32_t y_range = 4096; /* 物理 Y 范围 */
int32_t user_x = 480; /* 屏幕 X 分辨率 */
int32_t user_y = 320; /* 屏幕 Y 分辨率 */
dev = os_device_open_s("touch");
if (dev == OS_NULL) return;
/* 设置物理坐标范围 */
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_SET_X_RANGE), &x_range);
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_SET_Y_RANGE), &y_range);
/* 设置用户坐标范围(映射到屏幕分辨率) */
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_SET_USER_X_RANGE), &user_x);
os_device_control(dev, IOC_TOUCH(OS_TOUCH_CTRL_SET_USER_Y_RANGE), &user_y);
os_kprintf("Touch calibrated: phys(%d,%d) -> user(%d,%d)\r\n",
x_range, y_range, user_x, user_y);
os_device_close(dev);
}示例 4:注册自定义 Touch 设备
#include <touch.h>
#include <device.h>
#include <os_memory.h>
/* 底层 Touch 操作实现 */
static os_size_t my_touch_readpoint(struct os_touch_device *touch, struct os_touch_data *data, os_size_t touch_num)
{
/* 从硬件读取触摸点数据 */
data[0].event = OS_TOUCH_EVENT_DOWN;
data[0].track_id = 0;
data[0].width = 10;
data[0].x_coordinate = 100;
data[0].y_coordinate = 200;
data[0].timestamp = os_touch_get_ts();
return 1; /* 返回读取到的点数 */
}
static os_err_t my_touch_control(struct os_touch_device *touch, int cmd, void *arg)
{
switch (cmd)
{
case OS_TOUCH_CTRL_GET_INFO:
*(struct os_touch_info *)arg = touch->info;
break;
case OS_TOUCH_CTRL_SET_X_RANGE:
touch->info.range_x = *(int32_t *)arg;
break;
case OS_TOUCH_CTRL_SET_Y_RANGE:
touch->info.range_y = *(int32_t *)arg;
break;
default:
break;
}
return OS_SUCCESS;
}
static const struct os_touch_ops my_touch_ops =
{
.touch_readpoint = my_touch_readpoint,
.touch_control = my_touch_control,
};
/* 中断处理函数(由硬件中断触发) */
static os_err_t my_touch_irq_handler(os_touch_t *touch)
{
struct os_touch_data data[5]; /* 最多 5 点触控 */
os_size_t count;
/* 读取触摸数据 */
count = touch->ops->touch_readpoint(touch, data, 5);
/* 处理数据... */
for (int i = 0; i < count; i++)
{
os_kprintf("Touch: event=%d, (%d,%d)\r\n",
data[i].event, data[i].x_coordinate, data[i].y_coordinate);
}
return OS_SUCCESS;
}
static struct os_touch_device my_touch;
void my_touch_init(void)
{
/* 填充设备信息 */
my_touch.info.type = OS_TOUCH_TYPE_CAPACITANCE;
my_touch.info.vendor = OS_TOUCH_VENDOR_GT;
my_touch.info.point_num = 5;
my_touch.info.range_x = 4096;
my_touch.info.range_y = 4096;
my_touch.info.user_range_x = 480;
my_touch.info.user_range_y = 320;
/* 绑定操作函数表 */
my_touch.ops = &my_touch_ops;
/* 注册中断处理函数 */
my_touch.irq_handle = my_touch_irq_handler;
/* 注册到设备框架 */
os_hw_touch_register(&my_touch, "touch", OS_NULL);
}示例 5:结合 GUI 的触摸事件处理
#include <touch.h>
#include <device.h>
/* 简单的触摸手势识别 */
typedef enum
{
GESTURE_NONE = 0,
GESTURE_TAP,
GESTURE_SWIPE_LEFT,
GESTURE_SWIPE_RIGHT,
GESTURE_SWIPE_UP,
GESTURE_SWIPE_DOWN,
} gesture_t;
static int gesture_start_x = 0;
static int gesture_start_y = 0;
static int gesture_active = 0;
gesture_t detect_gesture(struct os_touch_data *data)
{
gesture_t gesture = GESTURE_NONE;
if (data->event == OS_TOUCH_EVENT_DOWN)
{
gesture_start_x = data->x_coordinate;
gesture_start_y = data->y_coordinate;
gesture_active = 1;
}
else if (data->event == OS_TOUCH_EVENT_UP && gesture_active)
{
int dx = data->x_coordinate - gesture_start_x;
int dy = data->y_coordinate - gesture_start_y;
if (abs(dx) < 20 && abs(dy) < 20)
{
gesture = GESTURE_TAP;
}
else if (abs(dx) > abs(dy))
{
gesture = (dx > 0) ? GESTURE_SWIPE_RIGHT : GESTURE_SWIPE_LEFT;
}
else
{
gesture = (dy > 0) ? GESTURE_SWIPE_DOWN : GESTURE_SWIPE_UP;
}
gesture_active = 0;
}
return gesture;
}
void touch_gesture_task(void *arg)
{
os_device_t *dev;
struct os_touch_data data;
gesture_t gesture;
dev = os_device_open_s("touch");
if (dev == OS_NULL) return;
while (1)
{
if (os_device_read_block(dev, 0, &data, sizeof(data)) == sizeof(data))
{
gesture = detect_gesture(&data);
switch (gesture)
{
case GESTURE_TAP:
os_kprintf("Gesture: TAP at (%d, %d)\r\n", data.x_coordinate, data.y_coordinate);
break;
case GESTURE_SWIPE_LEFT:
os_kprintf("Gesture: SWIPE LEFT\r\n");
break;
case GESTURE_SWIPE_RIGHT:
os_kprintf("Gesture: SWIPE RIGHT\r\n");
break;
case GESTURE_SWIPE_UP:
os_kprintf("Gesture: SWIPE UP\r\n");
break;
case GESTURE_SWIPE_DOWN:
os_kprintf("Gesture: SWIPE DOWN\r\n");
break;
default:
break;
}
}
}
}📝 本节小结
本节介绍了 OneOS 中 Touch 设备的使用方法,包括:
- 设备结构:
os_touch_device继承自os_device_t,通过os_touch_ops操作函数表实现底层硬件抽象 - 事件类型:支持 NONE、UP、DOWN、MOVE 四种触摸事件,通过
os_touch_data.event字段区分 - 多点触控:通过
track_id追踪多个触摸点,point_num指定最大支持点数 - 坐标系统:支持物理坐标与用户坐标的双重映射,以及 X/Y 轴交换(横竖屏切换)
- 中断回调:通过
irq_handle函数指针实现中断驱动的触摸处理 - 控制命令:提供 10 种控制命令,覆盖 ID 获取、坐标校准、模式切换、中断控制等全场景
- 时间戳同步:支持 RTC 和系统滴答两种时间戳来源
Touch 设备是人机交互的关键组件,掌握其事件处理与坐标校准是开发嵌入式 GUI 应用的基础。