K230基础-获取触摸坐标

第二十二章 获取触摸坐标-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 0x140x5D 多点触控,需配置
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 数据
  • 坐标映射与显示
  • 触摸去抖与优化

相关推荐
知南x3 小时前
STM32MP157目标检测环境搭建 (3) NCNN环境安装
stm32·嵌入式硬件·目标检测
日更嵌入式的打工仔5 小时前
InitLWIP() 初始化
笔记·嵌入式硬件·学习
人类发明了工具5 小时前
【三维重建-对极几何】极线约束(Epipolar Constraint)
图像处理·数码相机·三维重建
学生董格6 小时前
[嵌入式embed]Keil5-STM32F103C8T6(江协科技)+移植RT-Thread v3.15模版
stm32·嵌入式硬件·rt-thread·keil5·江协科技
AndrewHZ6 小时前
【图像处理基石】GIS图像处理入门:4个核心算法与Python实现(附完整代码)
图像处理·python·算法·计算机视觉·gis·cv·地理信息系统
酷飞飞6 小时前
掌握DMA基于GD32F407VE的天空星的配置
stm32·单片机·嵌入式硬件·arm
清风6666667 小时前
基于单片机的Boost升压斩波电源电路
单片机·嵌入式硬件·毕业设计·课程设计
qiuiuiu4137 小时前
正点原子RK3568学习日记-GIT
linux·c语言·开发语言·单片机
搞一搞汽车电子13 小时前
单片机的堆\栈\Flash\Ram区别和联系
单片机·嵌入式硬件