第二十二章 获取触摸坐标-K230触摸屏交互基础
🎯 本章目标 :
掌握在 K230 开发板(如 CanMV-K230)上通过 I2C 接口获取触摸屏坐标 的方法,学会使用
touch
模块或 I2C 协议读取 X、Y 坐标与触摸状态,实现触摸交互功能,为构建图形用户界面(GUI)打下基础。
1. 触摸屏硬件概述
1.1 常见触摸屏类型
类型 | 说明 | 是否适用于 K230 |
---|---|---|
电阻式 | 压力感应,需按压 | ✅ 支持(较少) |
电容式 | 指尖感应,支持多点 | ✅ 推荐(常见于 TFT 屏) |
📌 K230 典型配置 :
TFT LCD + 电容触摸屏 (如 2.8"、3.5" 屏),通过 I2C 传输触摸数据。
1.2 主流触摸控制器芯片
芯片 | 接口 | I2C 地址 | 特点 |
---|---|---|---|
FT6236 / FT6336 | I2C | 0x38 |
电容式,2点触控 |
GT911 | I2C | 0x14 或 0x5D |
多点触控,需配置 |
XPT2046 | SPI | - | 电阻式,SPI 接口 |
✅ 本章重点 :FT6336 + I2C 获取触摸坐标(最常见)
2. 硬件连接
触摸屏引脚 | K230 引脚 | 说明 |
---|---|---|
SCL | I2C1_SCLK(如 Pin3) | I2C 时钟 |
SDA | I2C1_SDA(如 Pin2) | I2C 数据 |
GND | GND | 地 |
VDD | 3.3V | 电源 |
INT | 可选 GPIO | 中断输出(通知有触摸) |
RST | 可选 GPIO | 复位引脚 |
✅ 注意 :
触摸控制器与 OLED/EEPROM 共用 I2C 总线,需通过
i2c.scan()
确认地址。
3. 使用 touch
模块(CanMV 官方支持)
⚠️ 前提 :固件需包含
touch
模块(非所有版本支持)
python
import touch
import time
3.1 初始化触摸屏
python
# 创建触摸对象
ts = touch.Touch(screen_width=320, screen_height=240)
# 检查是否初始化成功
if ts.init():
print("✅ 触摸屏初始化成功")
else:
print("❌ 触摸屏初始化失败")
raise Exception("Touch init failed")
3.2 读取触摸坐标
python
while True:
# 获取触摸状态
touch_points = ts.points()
if touch_points:
for point in touch_points:
x, y, event_type, id = point
# event_type: 0=按下, 1=释放, 2=移动
# id: 触摸点 ID
print(f"触摸: ID={id}, X={x}, Y={y}, 事件={event_type}")
else:
# 无触摸
pass
time.sleep_ms(10)
✅ 输出示例:
c触摸: ID=0, X=120, Y=100, 事件=0 触摸: ID=0, X=125, Y=102, 事件=2 触摸: ID=0, X=0, Y=0, 事件=1
4. 手动 I2C 读取触摸数据(通用方法)
若无 touch
模块,可直接通过 I2C 读取触摸芯片寄存器。
4.1 FPIOA 映射与 I2C 初始化
python
from fpioa_manager import fm
from machine import I2C, Pin
# I2C 引脚
I2C_SDA = 2
I2C_SCL = 3
fm.register(I2C_SDA, fm.fpioa.I2C1_SDA)
fm.register(I2C_SCL, fm.fpioa.I2C1_SCL)
i2c = I2C(I2C.I2C1, freq=400_000, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL))
4.2 扫描 I2C 设备确认触摸芯片
python
devices = i2c.scan()
print("I2C 设备地址:", [hex(dev) for dev in devices])
# FT6336 地址通常为 0x38
TOUCH_ADDR = 0x38
if TOUCH_ADDR not in devices:
print(f"❌ 未检测到触摸芯片 @ 0x38")
else:
print(f"✅ 检测到触摸芯片 @ 0x{TOUCH_ADDR:02X}")
4.3 读取 FT6336 触摸数据
python
# FT6336 寄存器地址
REG_TD_STATUS = 0x02 # 触摸点数
REG_P1_XH = 0x03 # 第一个触摸点 X 高位
def read_touch():
# 读取状态寄存器
try:
data = i2c.readfrom_mem(TOUCH_ADDR, REG_TD_STATUS, 1)[0]
num_points = data & 0x0F
if num_points > 0:
# 读取第一个触摸点(2 个字节 X,2 个字节 Y)
raw = i2c.readfrom_mem(TOUCH_ADDR, REG_P1_XH, 4)
# 解析 X: [XH(高4位), XL] → 12位
x = ((raw[0] & 0x0F) << 8) | raw[1]
# 解析 Y: [YH(高4位), YL]
y = ((raw[2] & 0x0F) << 8) | raw[3]
return x, y
else:
return None, None
except:
return None, None
# 循环读取
while True:
x, y = read_touch()
if x is not None and y is not None:
print(f"触摸坐标: X={x}, Y={y}")
else:
# print("无触摸")
pass
time.sleep_ms(50)
5. 坐标映射到屏幕显示区域
触摸屏原始坐标通常为 0~4095
,需映射到屏幕分辨率(如 320x240)。
python
def map_touch_to_screen(x_raw, y_raw, screen_w=320, screen_h=240):
x = int(x_raw * screen_w / 4095)
y = int(y_raw * screen_h / 4095)
return x, y
# 使用
x_raw, y_raw = read_touch()
if x_raw:
x, y = map_touch_to_screen(x_raw, y_raw)
print(f"屏幕坐标: X={x}, Y={y}")
✅ 校准建议:实际使用中可能需手动校准映射系数。
6. 实战项目:触摸点显示在 TFT 屏上
python
# 假设已初始化 TFT 屏幕(见第13章)
import st7789
import vga1_8x8 as font
# 清屏
tft.fill(0)
tft.text(font, "触摸测试", 100, 100, st7789.YELLOW)
while True:
x_raw, y_raw = read_touch()
if x_raw and y_raw:
# 映射到 240x240 屏幕
x = int(x_raw * 240 / 4095)
y = int(y_raw * 240 / 4095)
# 限制范围
x = max(0, min(239, x))
y = max(0, min(239, y))
# 显示触摸点
tft.fill(0) # 清屏
tft.text(font, "Touch:", 10, 10, st7789.CYAN)
tft.text(font, f"X={x}", 10, 30, st7789.YELLOW)
tft.text(font, f"Y={y}", 10, 50, st7789.YELLOW)
tft.pixel(x, y, st7789.RED) # 画点
tft.circle(x, y, 5, st7789.GREEN) # 画圈
else:
tft.fill_rect(10, 70, 200, 20, 0) # 清除提示
7. 高级技巧与优化
7.1 使用中断引脚(INT)减少轮询
python
from machine import Pin
INT_PIN = 12
fm.register(INT_PIN, fm.fpioa.GPIOHS0)
int_pin = Pin(INT_PIN, Pin.IN)
# 仅在 int_pin.value() == 0 时读取触摸
if not int_pin.value():
x, y = read_touch()
✅ 优势:降低 CPU 占用
7.2 触摸事件去抖与滤波
python
last_x, last_y = None, None
threshold = 5
def smooth_touch(new_x, new_y):
global last_x, last_y
if last_x is None:
last_x, last_y = new_x, new_y
return new_x, new_y
# 简单滤波
x = (last_x * 2 + new_x) // 3
y = (last_y * 2 + new_y) // 3
last_x, last_y = x, y
return x, y
8. 常见问题与调试
❌ 问题1:无法读取触摸数据
排查:
- I2C 地址是否正确?
- 接线是否松动?
- 电源是否稳定?
❌ 问题2:坐标跳变或不准
解决:
- 增加滤波(均值、中值)
- 检查屏幕方向是否匹配
- 手动校准映射参数
❌ 问题3:touch
模块导入失败
原因 :固件未包含该模块
解决:使用 I2C 手动读取(通用方法)
9. 性能与限制
操作 | 耗时 |
---|---|
I2C 读取一次 | ~2ms |
坐标解析 | < 0.1ms |
轮询频率 | 建议 10~50ms 间隔 |
✅ 建议:
- 使用定时器周期读取
- 结合 GUI 框架实现按钮、滑动等交互
✅ 本章你已掌握:
- 触摸屏硬件连接与 I2C 通信
- 使用
touch
模块获取坐标 - 手动 I2C 读取 FT6336 数据
- 坐标映射与显示
- 触摸去抖与优化