基于树莓派rp2040的模拟鼠标制作
项目介绍:
本项目基于硬禾学堂的树莓派rp2040 Game kit硬件平台实现与电脑通信控制电脑鼠标以及LCD屏幕控制及参数调整。
- 设计思路(框图)
-
硬件介绍:
240*240LCD屏幕、多个按键、四向遥杆、红外、蜂鸣器、姿态传感器、温度传感器等等,可以用micropython、C、C++编程。
-
实现功能及展示:
实现了通过USB端口控制PC屏幕上的光标移动和点击操作,行使电脑鼠标的功能,在240*240的LCD屏幕内可以通过该鼠标进行菜单选择和参数控制。
- 主要代码片段:
if(ox != rectx or oy != recty): display.fillor(ox,oy,20,20,0XFFFF)#刷新鼠标移动区域 if(oy+5>=140 and oy+5 <=185): display.blit_buffer(fm1buf5, 0, 120, 240, 30) display.blit_buffer(fm1buf6, 0, 150, 240, 30) if(oy+5<175): menu_flag = 0 if(oy+5 >175): display.blit_buffer(fm1buf7, 0, 180, 240, 30) display.blit_buffer(fm1buf8, 0, 210, 240, 30) menu_flag = 1
这段程序前两行是比较现在坐标和上次坐标,只有鼠标移动(坐标变换)时才会刷新屏幕,且只刷新原来鼠标在的区域,下面两个if是用鼠标图片坐标判断位于的位置在menu1还是menu2,从而实现灵敏度设置和切换成控制电脑的菜单功能。
xValue = (int)(xAxis.read_u16()/30000)-1 yValue = (int)(yAxis.read_u16()/30000)-1
没有使用复杂的滤波,只是将adc值加减乘除归一化到-1到1的范围,利用后期乘以一定倍数来调整灵敏度。
if (buttonValueA == 0): mouse.press(2) else: mouse.release(2) if (buttonValueB == 0): mouse.press(1) else: mouse.release(1) #返回 if(buttonValueStart==0): break #按Select进入滚轮模式 if(buttonValueSelect==0): sleep(0.5) while True: xValue = (int)(xAxis.read_u16()/30000)-1 yValue = (int)(yAxis.read_u16()/30000)-1 buttonValueA = buttonA.value() buttonValueB = buttonB.value() buttonValueStart = buttonStart.value() buttonValueSelect = buttonSelect.value() print(str(xValue) +", " + str(yValue) + " -- " + str(buttonValueA) + " -- "+ str(buttonValueB)+ " -- " + str(buttonValueStart)+ " -- " + str(buttonValueSelect)) utime.sleep(0.01) #if (xValue >= 2 or xValue <= -2 or yValue >= 2 or yValue <= -2): #hValue = yValue - xValue mouse.move(0,0,-xValue,0) #按Select退出滚轮模式 if(buttonValueSelect==0): sleep(0.5) break
这段代码实现了模拟鼠标左右两个按键以及切换到鼠标滚轮的功能,恰当利用延时避免重复操作。
5.遇到的主要难题及解决方法:
①屏幕刷新导致显示不流畅等问题:
由于是第一次尝试图形化编程,解决了图片显示问题后,我在移动鼠标图片时发现利用st7789库中带的fill函数来刷屏会导致画面闪烁以及运行速度慢等情况,影响了鼠标移动的流畅度。后来我试用了局部刷新,即只刷新移动的部分图片,发现速度比之前快很多,之后再尝试了只有图片移动时才刷新,发现流畅程度已经达到了可以用的水平。在这期间还接触到了micro-gui库和lvgl库,但由于时间紧没有深入学习。
②图片显示效率低
官方例程中有一段for循环显示硬禾logo的程序,在使用时我发现这个是逐行刷新而且运行缓慢,放在while中不现实。因此我又想了很多其他方法,最后利用mpy中的framebuf库,创建帧缓冲区,提前将图片加载好再将数据发送给屏幕,这样图片显示会高效很多。另外framebuf中还有一个blit函数可以在当前缓冲区上绘制另一个缓冲区且可以指定一个透明颜色,意味着鼠标图片可以只显示黑色的鼠标,四周白色的背景可以去除,在屏幕上移动时不会有突兀感,可以提升整体显示效果。不过由于时间关系我的工程中也没有用到这个函数,仅仅只是完成了题目要求。
③如何与电脑通信控制鼠标
板子刚上手时,我对mpy和树莓派一无所知,也不知道如何通过rp2040来控制电脑的鼠标,只看到有各种各样的库,却不知道哪个可以用,也不会移植库,只知道cpy可以控制鼠标,但cpy中又缺少其他库来完成其他功能。直到后来刷上老师发的带usb_hid的固件后,我才利用hid驱动实现了鼠标的移动。
④如何使鼠标移动更丝滑
摇杆处直接读出来的两个adc值没有经过滤波是不稳定的,致使鼠标的移动也会不稳定。我一开始想的办法也是用各种滤波方法,对ad值进行处理,但后来略感复杂,想到了一种很直接的方法,那就是直接除以一个数再加减一个数,将adc值归一到一定范围内,最简单就是-1~1这个区间,再通过设置一个dx和dy与之相乘即可达到比较满意的效果。最后发现实践起来鼠标上下左右移动都较好,甚至可以往左上角移动,但又不可以往右下角移动,不过ad值刷新得比较快,用起来其实感知不强,整体还算是比较丝滑了。
6.可提供验证的代码(百度云)
链接:https://pan.baidu.com/s/1e54DZWtXfyvAIA6Bs8tA6Q
提取码:1234
实际上这块板子可玩性很高,加上键帽再优化程序后,使鼠标更加丝滑说不定能达到游戏手柄的效果。但由于其过于小巧,我认为加块电池做一个掌上游戏机是最好的选择,不过移植游戏对目前的我来说难度太高,因此我暂时没有选择做这个游戏机。建议大家可以多移植几款游戏,最终集成到一起,实现一机多玩的功能。未来如果有机会我争取将板上的每个外设学习一遍,做出一个多功能的游戏机。