山东网站排行,教育网站模板,wordpress linux 中文字体,网站怎么做好 优帮云庐山派K230开发板实战#xff1a;3.1寸电容屏触摸坐标获取与手画板应用#xff08;Python API详解#xff09; 最近在玩庐山派K230开发板#xff0c;想给它接个屏幕做个交互应用#xff0c;发现官方配套的3.1寸电容触摸屏用起来挺方便的。很多刚开始接触的朋友可能会觉得触…庐山派K230开发板实战3.1寸电容屏触摸坐标获取与手画板应用Python API详解最近在玩庐山派K230开发板想给它接个屏幕做个交互应用发现官方配套的3.1寸电容触摸屏用起来挺方便的。很多刚开始接触的朋友可能会觉得触摸屏驱动有点复杂其实用K230的CanMV固件几行Python代码就能搞定。今天我就带大家从零开始一步步实现触摸坐标的读取并最终完成一个简单的手绘板应用。咱们这篇教程会分成几个部分先聊聊电容屏和电阻屏有啥区别然后详细讲解K230上操作触摸屏的Python API怎么用接着写个程序实时打印你手指点的位置最后把这些知识整合起来做一个能画画、能换颜色、能清屏的趣味手绘板。1. 硬件准备与触摸屏原理在写代码之前咱们得先把硬件连好并了解一下屏幕是怎么“感觉”到你的触摸的。1.1 连接你的屏幕首先确保你的庐山派K230开发板和3.1寸屏幕已经通过排线正确连接。连接口一般在开发板边缘对准防呆口插紧就行。这是后续所有操作的基础没连好屏幕可是啥都看不到的。1.2 电容触摸 vs 电阻触摸它们怎么工作咱们用的这块3.1寸屏幕和现在智能手机的屏幕一样是电容触摸屏。它和以前一些POS机、工业设备上常见的电阻屏工作原理完全不同。了解这个区别能帮你更好地理解代码里的某些行为比如为什么戴手套可能没反应。你可以把电容触摸屏想象成一层透明的、对电场特别敏感的材料。当你的手指导体靠近或接触屏幕时就会轻微改变屏幕那一点的电场。屏幕内部的控制器非常灵敏能检测到这种微小的电容变化从而精确计算出你手指的位置。而电阻触摸屏更像是两层可以轻微挤压的透明薄膜。当你用力按压用指甲、触笔甚至戴手套的手指都行时上下两层薄膜在按压点接触电路接通控制器通过测量电压变化来确定位置。为了让你更直观地看清它们的区别我整理了一个对比表格特性电容触摸屏电阻触摸屏工作原理检测人体引起的电容变化检测压力导致的薄膜接触触摸方式手指轻触即可支持多点触控需要施加压力一般只支持单点能否戴手套不能手套绝缘可以只要力度够响应速度快适合滑动等手势相对较慢耐用性表面玻璃硬度高但怕潮湿薄膜表面易划伤但适应恶劣环境精度高适合手指操作高适合触笔精细操作常见用途手机、平板、消费电子产品工业控制、医疗设备、户外终端所以记住咱们的屏幕是电容式的这意味着它反应快、支持多点虽然驱动层可能有限制但千万别戴着手套去点它。2. 核心APImachine.TOUCH类详解K230的CanMV固件已经把触摸屏的底层驱动封装好了我们通过machine模块里的TOUCH类来操作它。这部分是重中之重咱们把每个函数和参数都掰开揉碎了讲。2.1 导入与初始化首先在任何使用触摸屏的脚本开头都需要导入这个类。from machine import TOUCH然后创建一个触摸屏对象。目前K230只支持一个触摸设备所以索引号固定是0。tp TOUCH(0) # 实例化触摸屏设备这里有个重要的可选参数rotate如果你的屏幕安装方向比如竖屏变横屏导致触摸坐标和显示坐标对不上可以用它来旋转触摸坐标。# rotate 参数说明 # 0: ROTATE_0 - 不旋转 (默认) # 1: ROTATE_90 - 顺时针旋转90度 # 2: ROTATE_180 - 旋转180度 # 3: ROTATE_270 - 顺时针旋转270度即逆时针90度 # 例如如果屏幕是横着装的但触摸坐标是竖着的可以尝试 tp TOUCH(0, rotate1)注意rotate参数调整的是触摸坐标系统以适应不同的屏幕物理安装方向。如果触摸位置不准优先检查硬件连接和屏幕驱动其次再尝试调整这个参数。2.2 读取触摸数据read()方法初始化之后就可以在循环里不断读取触摸点了。# 读取触摸数据默认只读取一个点 point_data tp.read() # 也可以指定一次读取最多多少个触摸点比如我们的屏幕硬件支持最多5点 multi_point_data tp.read(5)read()方法返回一个元组里面包含一个或多个touch_info对象。即使你指定了读取多个点如果没有那么多手指在屏幕上返回的元组长度也会相应变短。如果完全没有触摸它会返回一个空元组()。2.3 触摸点信息touch_info对象read()方法返回的元组里每个元素都是一个touch_info对象。这个对象有几个属性记录了单个触摸点的详细信息x,y这是咱们最常用的代表触摸点在屏幕上的坐标。原点(0, 0)通常在屏幕的左上角。event理论上表示触摸事件如按下、移动、抬起但请注意根据原始资料当前固件版本中这个属性“还不支持”内部是K230自己维护的一套机制。所以暂时别依赖这个值来判断手指是否抬起。track_id触点ID用于在多点触摸中区分不同的手指。同样资料显示“目前还不支持”。width触点宽度。资料特别说明我们这块3.1寸屏的触摸芯片本身不支持获取宽度所以这个属性当前被用来等效于track_id。timestamp触摸发生的时间戳。重要提示关于event和track_id的支持情况原文有明确说明是“请等待嘉楠后续完善”。这意味着在写应用时我们无法直接通过API判断“手指抬起”这个动作也无法可靠地区分多个同时触摸的手指。这是当前固件的一个限制我们在设计手绘板逻辑时需要想办法绕过它。2.4 资源释放deinit()方法当你的程序结束不再使用触摸屏时最好显式地释放资源。虽然Python有垃圾回收但养成好习惯能让程序更稳健。tp.deinit() # 释放TOUCH设备资源3. 实战第一步实时打印触摸坐标理论讲完了咱们来点实际的。先写一个简单的程序在串口终端里实时打印你手指在屏幕上点的位置。这是调试触摸屏最基本也最有效的方法。# 立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源 # 开发板官网www.lckfb.com # 技术支持常驻论坛任何技术问题欢迎随时交流学习 # 立创论坛www.jlc-bbs.com/lckfb # 关注bilibili账号【立创开发板】掌握我们的最新动态 import time from machine import TOUCH # 实例化 TOUCH 设备 0 tp TOUCH(0) print(触摸坐标读取程序已启动请触摸屏幕...) while True: # 尝试读取最多5个触摸点硬件上限 points tp.read(5) # 如果返回的不是空元组说明有触摸发生 if points ! (): print(--- 检测到触摸 ---) # 使用enumerate遍历方便给触摸点编号 for i, point in enumerate(points, start1): print(f 触摸点 {i}: X {point.x}, Y {point.y}) print() # 打印空行分隔 # 短暂延时避免CPU占用率过高也方便观察输出 time.sleep(0.01) # 等待10毫秒代码逐行解析tp TOUCH(0)初始化触摸屏设备。while True:一个无限循环持续监听触摸。points tp.read(5)每次循环尝试读取最多5个触摸点数据。if points ! ():这是关键判断。如果points是空元组说明此刻屏幕没有被触摸。只有非空时才处理。for i, point in enumerate(points, start1):这里用到了Python内置的enumerate函数。它非常方便可以在遍历points元组的同时自动给我们生成一个序号i从1开始计数。这样打印出来的信息更清晰。print(f 触摸点 {i}: X {point.x}, Y {point.y})打印每个触摸点的编号和其X、Y坐标。time.sleep(0.01)每次循环后等待10毫秒。这个延时很有必要一方面降低了CPU使用率另一方面也让串口输出不至于刷屏太快方便你看清。把这段代码保存为main.py并运行然后用手指触摸屏幕你就能在CanMV IDE的串行终端里看到实时的坐标输出了。试着用多个手指同时触摸看看是否能识别出多个点。4. 综合项目打造你的简易手绘板能读到坐标了咱们就来玩个大的——做一个手绘板这个程序会显示一个画布你可以用手指在上面画画还能切换颜色和清空画布。这个程序稍微长一点但结构很清晰。我会把核心逻辑拆开讲。4.1 程序框架与显示初始化首先程序需要初始化显示系统并创建一个“画布”图像对象。import time, os, gc, sys, urandom from media.display import * from media.media import * from machine import TOUCH try: # 1. 显示模式配置 DISPLAY_MODE LCD # 可选 VIRT(IDE虚拟显示), LCD(3.1寸屏), HDMI(HDMI输出) if DISPLAY_MODE LCD: # 我们的3.1寸屏分辨率是800x480 DISPLAY_WIDTH 800 DISPLAY_HEIGHT 480 Display.init(Display.ST7701, widthDISPLAY_WIDTH, heightDISPLAY_HEIGHT, to_ideTrue) # ... 其他模式VIRT, HDMI的初始化代码类似详见完整代码 # 2. 初始化媒体管理器管理图像缓冲区等资源 MediaManager.init() # 3. 创建一张空白的RGB565图像作为我们的画布 img image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.RGB565) img.clear() # 用黑色清空画布 # 4. 初始化触摸屏 tp TOUCH(0) # 5. 定义画笔初始状态 current_color (0, 255, 0) # 初始为绿色(R, G, B) brush_size 10 # 画笔粗细 # 进入主循环...这里有几个关键点DISPLAY_MODE非常灵活。即使你没有实物屏幕设为VIRT也可以在CanMV IDE的帧缓冲区里看到画面方便调试。有屏幕就选LCD。image.Image()创建了一个图像对象所有画画的操作画点、画线、画矩形都是在这个内存中的图像上进行的。current_color用一个三元组(R, G, B)表示当前画笔颜色。4.2 定义交互区域与功能函数我们在画布上定义两个按钮区域并写好对应的功能函数。# 定义按钮在屏幕上的区域 (x, y, width, height) clear_button_area (DISPLAY_WIDTH - 100, 0, 100, 50) # 清除按钮在右上角 color_button_area (0, 0, 130, 50) # 换色按钮在左上角 def draw_clear_button(): 绘制红色的清除按钮 img.draw_rectangle(clear_button_area[0], clear_button_area[1], clear_button_area[2], clear_button_area[3], color(255, 0, 0), fillTrue) # 画一个红色填充矩形 img.draw_string_advanced(clear_button_area[0] 10, clear_button_area[1] 10, 30, 清除, color(255, 255, 255), scale2) # 写上白色文字 def draw_color_buttons(): 绘制黄色的颜色选择按钮 img.draw_rectangle(color_button_area[0], color_button_area[1], color_button_area[2], color_button_area[3], color(255, 255, 0), fillTrue) # 画一个黄色填充矩形 img.draw_string_advanced(color_button_area[0] 10, color_button_area[1] 10, 30, 随机颜色, color(0, 0, 0), scale2) # 写上黑色文字 def select_color(x, y): 如果触摸点在颜色按钮区域内则随机更换画笔颜色 global current_color cx, cy, cw, ch color_button_area if cx x cx cw and cy y cy ch: # 生成随机颜色 current_color (urandom.getrandbits(8), urandom.getrandbits(8), urandom.getrandbits(8)) print(f颜色已切换为: {current_color}) def check_clear_button(x, y): 如果触摸点在清除按钮区域内则清空画布 cx, cy, cw, ch clear_button_area if cx x cx cw and cy y cy ch: img.clear() print(画布已清除)函数select_color和check_clear_button的逻辑是一样的检查传入的坐标(x, y)是否落在对应按钮的矩形区域内。如果是就执行相应的动作换颜色或清屏。4.3 核心绘图逻辑与“连线”算法这是手绘板最核心的部分。我们如何把一个个离散的触摸点变成平滑的线条这里有个坑由于固件暂不支持event属性我们无法准确知道手指何时抬起。如果简单地把所有相邻读取到的点连起来当手指快速移动或抬起再按下时可能会把不相关的两点连在一起画出一条飞线。原文代码采用了一种巧妙的“距离判断”法来规避这个问题last_point None # 记录上一个有效的触摸点坐标 def draw_line_between_points(last_point, current_point): 在两个触摸点之间绘制连线通过插值让线条更平滑 if last_point is not None: # 计算当前点和上一个点的直线距离 dx current_point.x - last_point.x dy current_point.y - last_point.y distance (dx**2 dy**2) ** 0.5 # **关键判断**如果距离过大认为这是两次独立的触摸比如手指抬起后再次按下不进行连线 if distance 30: # 这个阈值30可以根据实际情况调整 return # 如果两点距离适中则在它们之间插入多个小圆点让线条看起来是连续的而不是一串点 min_distance 10 # 插值密度值越小线条越平滑 if distance min_distance: steps int(distance // min_distance) # 计算需要插入多少个点 for i in range(1, steps 1): # 计算插入点的坐标 new_x last_point.x i * dx / (steps 1) new_y last_point.y i * dy / (steps 1) # 画出插入的点 img.draw_circle(int(new_x), int(new_y), brush_size, colorcurrent_color, thickness3, fillTrue) # 无论如何画出当前的这个触摸点 img.draw_circle(current_point.x, current_point.y, brush_size, colorcurrent_color, thickness3, fillTrue)这个算法的精髓在于if distance 30: return这一行。它假设如果两次读取的坐标点距离超过30个像素那么它们很可能不是同一次连续滑动产生的而是两次独立的触摸动作。因此放弃在这两点之间画线只绘制当前的新点作为新线条的起点。4.4 主循环把所有部分串起来最后我们在一个无限循环里把所有功能整合起来。while True: # 1. 读取触摸一次只读一个点简化处理 points tp.read(1) # 2. 如果有触摸 if points ! (): point points[0] # 因为我们只读一个点所以直接取第一个 # 检查是否点击了功能按钮 select_color(point.x, point.y) check_clear_button(point.x, point.y) # 核心在上一个点和当前点之间画线内部会做距离判断 draw_line_between_points(last_point, point) # 更新“上一个点”为当前点供下次循环使用 last_point point # 3. 绘制界面元素按钮 draw_clear_button() draw_color_buttons() # 4. 将内存中的图像(img)显示到屏幕上 Display.show_image(img) # 短暂延时控制刷新率 time.sleep_ms(1) except KeyboardInterrupt: print(程序被用户中断) except Exception as e: print(f程序运行出错: {e}) finally: # 程序退出前务必释放硬件资源 Display.deinit() MediaManager.deinit()运行效果将完整代码即本章开头给出的长代码运行起来后你会看到屏幕左上角有一个“随机颜色”的黄色按钮点击它画笔颜色会随机变化。屏幕右上角有一个红色的“清除”按钮点击它整个画布会被清空。在屏幕其他区域你就可以用手指自由作画了。画线时应该是连续平滑的快速抬起再按下也不会出现奇怪的连线。通过这个项目你不仅学会了读取触摸坐标还掌握了如何基于坐标实现交互逻辑按钮并处理了固件限制下的连续绘图问题。这就是嵌入式开发中典型的“发现问题-分析原因-设计解决方案”的过程。希望这篇教程能帮你打开K230触摸屏开发的大门。