display_and_touch.py 为K230外接液晶显示屏与电容触摸屏功能演示程序,实现的效果为在屏幕上随机位置绘制"Hello World!,你好世界!!!"字符串,同时响应触摸事件,在触摸点绘制红色十字。
K230 支持 电容屏 和 电阻屏 的触摸输入,提供了基于 RT-Smart 封装的 TOUCH
类接口。可使用它读取触点坐标、事件类型等信息,广泛应用于 HMI、交互终端等场景。01Studio配套的mipi LCD分无触摸版本和带触摸版本,带触摸版本配的是电容触摸,支持单点和多点触控,使用时直接调用即可。
基本的使用方式如下:
python
from machine import TOUCH
# 实例化触摸设备 0
tp = TOUCH(0)
# 可选:启用坐标旋转(旋转 90 度),适配屏幕方向
# tp = TOUCH(0, 1)
# 读取当前触摸点数据
p = tp.read()
# 输出完整的触摸数据结构
print(p)
# 如有触摸点,可访问第一个触点的坐标与事件类型
# print(p[0].x) # X 坐标
# print(p[0].y) # Y 坐标
# print(p[0].event) # 事件类型(如 Touch Down、Move、Up)
接口说明
接口名 | 说明 |
---|---|
TOUCH(id) |
创建触摸屏实例,id=0 表示设备号 |
TOUCH(id, rotate) |
实例化并启用屏幕坐标旋转,rotate=1 代表旋转 90 度 |
read() |
返回当前触摸点信息,通常是一个列表结构 |
示例详解
1. 实例化设备
tp = TOUCH(0)
创建 TOUCH
设备对象,表示使用触摸通道 0。
可选参数 TOUCH(0, 1)
用于对坐标做旋转,适用于竖屏方向的设备。
2. 读取触摸数据
p = tp.read()
print(p)
返回的 p
通常是一个包含多个触点对象的列表。每个对象包含:
-
x
: X 坐标 -
y
: Y 坐标 -
event
: 触摸事件(如 Touch Down、Move、Touch Up)
3. 示例输出参考
[<TouchPoint x=120 y=65 event=0>]
如果有多个触点,例如支持多指操作:
[<TouchPoint x=120 y=65 event=0>, <TouchPoint x=250 y=130 event=0>]
应用场景
场景 | 示例 |
---|---|
图形界面交互 | 基于触摸点驱动按钮点击、滑动切换 |
自定义手势识别 | 多点滑动、旋转等操作识别 |
简单绘图板或签名板 | 基于触点轨迹做线条绘制 |
常见问题
Q:没有读取到触摸点,返回是空列表? A:此时说明屏幕未被触摸。tp.read()
只在屏幕被按下时返回触点。
Q:如何处理多点触控? A:读取到的是一个包含多个 TouchPoint
的列表,使用 for
循环逐个读取即可。
Q:是否支持旋转坐标系? A:支持,通过第二个参数 TOUCH(0, 1)
可开启坐标旋转(90 度顺时针)。
显示接口API 介绍
01studio k230 canMV开发板上外接的是01官方提供的ST7701显示驱动器的3.5寸液晶显示屏。
init
描述
初始化 Display 通路,包括 VO 模块、 DSI 模块和 LCD/HDMI。
必须在 MediaManager.init()之前调用
语法
init(type=None, width=None, height=None, osd_num=1, to_ide=False, flag=None, fps=None, quality=90)
参数
参数名称 | 描述 | 输入 / 输出 | 说明 |
---|---|---|---|
type | 显示设备类型 | 输入 | 必选 |
width | 分辨率宽度 | 输入 | 可选参数,默认值根据 type 决定 |
height | 分辨率高度 | 输入 | 可选参数,默认值根据 type 决定 |
osd_num | 在 show_image 时支持的 LAYER 数量 | 输入 | 越大占用内存越多 |
to_ide | 是否将屏幕显示传输到 IDE 显示 | 输入 | 开启时占用更多内存 |
flag | 显示 标志 | 输入 | |
fps | 显示帧率 | 输入 | 仅支持 VIRT 类型 |
quality | 设置 Jpeg 压缩质量 |
输入 | 仅在 to_ide=True 时有效,范围 [10-100] |
返回值
返回值 | 描述 |
---|---|
无 |
show_image
描述
在屏幕上显示图像。
语法
show_image(img, x=0, y=0, layer=None, alpha=255, flag=None)
参数
参数名称 | 描述 | 输入 / 输出 | 说明 |
---|---|---|---|
img | 显示的图像 | 输入 | |
x | 起始坐标的 x 值 | 输入 | |
y | 起始坐标的 y 值 | 输入 | |
layer | 显示到 指定层 | 输入 | 仅支持 OSD 层,若需要多层请在 init 中设置 osd_num |
alpha | 图层混合 alpha | 输入 | |
flag | 显示 标志 | 输入 |
返回值
返回值 | 描述 |
---|---|
无 |
deinit
描述
执行反初始化, deinit 方法会关闭整个 Display 通路,包括 VO 模块、 DSI 模块和 LCD/HDMI。
必须在 MediaManager.deinit()之前调用
必须在 sensor.stop()之后调用
语法
deinit()
返回值
返回值 | 描述 |
---|---|
无 |
bind_layer
描述
将 sensor
或 vdec
模块的输出绑定到屏幕显示。无需用户手动干预即可持续显示图像。
必须在 init 之前调用
语法
bind_layer(src=(mod, dev, layer), dstlayer, rect=(x, y, w, h), pix_format, alpha, flag)
参数
参数名称 | 描述 | 输入 / 输出 | 说明 |
---|---|---|---|
src | sensor 或 vdec 的输出信息 |
输入 | 可通过 sensor.bind_info() 获取 |
dstlayer | 绑定到 Display 的 显示层 | 输入 | 可绑定到 video 或 osd 层 |
rect | 显示区域 | 输入 | 可通过 sensor.bind_info() 获取 |
pix_format | 图像像素格式 | 输入 | 可通过 sensor.bind_info() 获取 |
alpha | 图层混合 alpha | 输入 | |
flag | 显示 标志 | 输入 | LAYER_VIDEO1 不支持 |
返回值
返回值 | 描述 |
---|---|
无 |
width
描述
获取屏幕或某一图层的显示宽度
语法
width(layer = None):
参数
参数名称 | 描述 | 输入 / 输出 | 说明 |
---|---|---|---|
layer | 指定获取 显示层 的宽度,如果不传则表示获取屏幕的分辨率宽度 |
返回值
返回值 | 描述 |
---|---|
width | 屏幕或显示层的宽度信息 |
height
描述
获取屏幕或某一图层的显示高度
语法
height(layer = None):
参数
参数名称 | 描述 | 输入 / 输出 | 说明 |
---|---|---|---|
layer | 指定获取 显示层 的高度,如果不传则表示获取屏幕的分辨率高度 |
返回值
返回值 | 描述 |
---|---|
height | 屏幕或显示层的高度信息 |
数据结构描述
type
类型 | 参数取值 | 备注 |
---|---|---|
VIRT | 640x480@90 | 默认值 IDE 调试专用,不在外接屏幕上显示内容 用户可自定义设置分辨率 (64x64)-(4096x4096) 和帧率 (1-200) |
DEBUGGER | 调试屏幕专用 | |
ST7701 | Display.init(Display.ST7701, width = 800, height = 480) | 默认值 800x480 |
Display.init(Display.ST7701, width = 480, height = 800) | 480x800 | |
Display.init(Display.ST7701, width = 854, height = 480) | 854x480 | |
Display.init(Display.ST7701, width = 480, height = 854) | 480x854 | |
Display.init(Display.ST7701, width = 640, height = 480) | 640x480 | |
Display.init(Display.ST7701, width = 480, height = 640) | 480x640 | |
Display.init(Display.ST7701, width = 368, height = 552) | 368x552 | |
Display.init(Display.ST7701, width = 552, height = 368) | 552x368 | |
HX8399 | Display.init(Display.HX8399, width = 1920, height = 1080) | 默认值 1920x1080 |
Display.init(Display.HX8399, width = 1080, height = 1920) | 1920x1080 | |
ILI9806 | Display.init(Display.ILI9806, width = 800, height = 480) | 默认值 800x480 |
Display.init(Display.ILI9806, width = 480, height = 800) | 480x800 | |
ILI9881 | Display.init(Display.ILI9881, width = 1280, height = 800) | 默认值 1280x800 |
Display.init(Display.ILI9881, width = 800, height = 1280) | 800x1280 | |
LT9611 | Display.init(Display.LT9611, width = 1920, height = 1080, fps = 30) | 默认值 1920x1080@30 |
Display.init(Display.LT9611, width = 1920, height = 1080, fps = 60) | 1920x1080@60 | |
Display.init(Display.LT9611, width = 1280, height = 720, fps = 60) | 1280x720@60 | |
Display.init(Display.LT9611, width = 1280, height = 720, fps = 50) | 1280x720@50 | |
Display.init(Display.LT9611, width = 1280, height = 720, fps = 30) | 1280x720@30 | |
Display.init(Display.LT9611, width = 640, height = 480, fps = 60) | 640x480@60 |
layer
K230 提供 2 层视频图层支持和 4 层 OSD 图层支持。分列如下:
显示层 | 说明 | 备注 |
---|---|---|
LAYER_VIDEO1 | 仅可在 bind_layer 中使用,支持硬件旋转 | |
LAYER_VIDEO2 | 仅可在 bind_layer 中使用,不支持硬件旋转 | |
LAYER_OSD0 | 支持 show_image 和 bind_layer 使用 | |
LAYER_OSD1 | 支持 show_image 和 bind_layer 使用 | |
LAYER_OSD2 | 支持 show_image 和 bind_layer 使用 | |
LAYER_OSD3 | 支持 show_image 和 bind_layer 使用 |
flag
标志 | 说明 | 备注 |
---|---|---|
FLAG_ROTATION_0 | 旋转 0 度 |
|
FLAG_ROTATION_90 | 旋转 90 度 |
|
FLAG_ROTATION_180 | 旋转 180 度 |
|
FLAG_ROTATION_270 | 旋转 270 度 |
|
FLAG_MIRROR_NONE | 不镜像 | |
FLAG_MIRROR_HOR | 水平镜像 | |
FLAG_MIRROR_VER | 垂直镜像 | |
FLAG_MIRROR_BOTH | 水平与垂直镜像 |


导入模块
import time, os, urandom, sys
from media.display import *
from media.media import *
from machine import TOUCH
-
time
: 用于时间控制 -
os
: 操作系统接口 -
urandom
: 生成随机数 -
media.display
和media.media
: 显示和媒体相关功能 -
TOUCH
: 触摸屏驱动
常量定义
DISPLAY_WIDTH = ALIGN_UP(800, 16) # 显示宽度,对齐到16像素
DISPLAY_HEIGHT = 480 # 显示高度
初始化
tp = TOUCH(0) # 初始化触摸屏设备0
主函数 display_test()
1. 图像缓冲区创建
img = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888)
img2 = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888)
-
img
: 主显示图像缓冲区 -
img2
: 触摸点显示图像缓冲区(用于绘制触摸轨迹) -
ARGB8888
: 32位颜色格式(Alpha, Red, Green, Blue各8位)
2. 显示系统初始化
Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
MediaManager.init()
-
初始化ST7701显示控制器
-
to_ide=True
: 可能表示同时输出到IDE预览
3. 主循环
触摸处理部分
point = tp.read(1) # 读取触摸点数据
if len(point):
pt = point[0]
if pt.event == 0 or pt.event == TOUCH.EVENT_DOWN or pt.event == TOUCH.EVENT_MOVE:
img2.draw_cross(pt.x, pt.y, color=(255,0,0), width=1, think_ness=1)
Display.show_image(img2, layer=Display.LAYER_OSD2, alpha=128)
-
检测触摸事件(按下、移动)
-
在触摸位置绘制红色十字
-
在OSD2图层显示触摸轨迹,设置半透明效果(alpha=128)
文字显示部分
x = (urandom.getrandbits(11) % img.width())
y = (urandom.getrandbits(11) % img.height())
img.draw_string_advanced(x, y, 32, "Hello World!,你好世界!!!", color=(0,0,255))
Display.show_image(img)
-
在随机位置显示中英文文字
-
文字颜色为蓝色
-
将图像显示到屏幕上
循环控制
img.clear() # 清空主图像缓冲区
time.sleep(0.05) # 50ms延迟,控制刷新率
4. 异常处理和清理
except KeyboardInterrupt as e:
print("user stop: ", e)
except BaseException as e:
sys.print_exception(e)
Display.deinit() # 释放显示资源
MediaManager.deinit() # 释放媒体资源
程序入口
if __name__ == "__main__":
os.exitpoint(os.EXITPOINT_ENABLE)
display_test()
-
启用退出点机制,允许安全中断程序
-
调用主测试函数
程序功能总结
-
显示测试: 在屏幕随机位置显示"Hello World!,你好世界!!!"
-
触摸测试: 检测触摸并在触摸位置绘制红色十字轨迹
-
多图层显示: 使用不同图层分别显示文字和触摸轨迹
-
实时更新: 以约20FPS的速率刷新显示
程序用于嵌入式设备的显示和触摸屏功能验证。
源程序如下:
python
import time, os, urandom, sys
from media.display import *
from media.media import *
from machine import TOUCH
DISPLAY_WIDTH = ALIGN_UP(800, 16)
DISPLAY_HEIGHT = 480
tp = TOUCH(0)
def display_test():
print("display and touch test")
# create image for drawing
img = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888)
img.clear()
img2 = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888)
img2.clear()
# use lcd as display output
Display.init(Display.ST7701, width = DISPLAY_WIDTH, height = DISPLAY_HEIGHT, to_ide = True)
# init media manager
MediaManager.init()
try:
while True:
os.exitpoint()
point = tp.read(1)
if len(point):
print(point)
pt = point[0]
if pt.event == 0 or pt.event == TOUCH.EVENT_DOWN or pt.event == TOUCH.EVENT_MOVE:
img2.draw_cross(pt.x, pt.y, color=(255,0,0), width = 1, think_ness = 1)
Display.show_image(img2, layer = Display.LAYER_OSD2, alpha = 128)
x = (urandom.getrandbits(11) % img.width())
y = (urandom.getrandbits(11) % img.height())
img.draw_string_advanced(x,y,32, "Hello World!,你好世界!!!", color = (0, 0, 255),)
# draw result to screen
Display.show_image(img)
img.clear()
time.sleep(0.05)
except KeyboardInterrupt as e:
print("user stop: ", e)
except BaseException as e:
import sys
sys.print_exception(e)
# deinit display
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
# release media buffer
MediaManager.deinit()
if __name__ == "__main__":
os.exitpoint(os.EXITPOINT_ENABLE)
display_test()