用基于树莓派RP2040的嵌入式系统学习板制作鼠标
本次是用基于树莓派RP2040的嵌入式系统学习板制作鼠标,运用其上的240*240分辨率的彩色IPS LCD,SPI接口,ST7789控制器,四向摇杆和2个轻触按键等实现模拟鼠标点击滑动等功能。
标签
嵌入式系统
RP2040
2022寒假在家练
模拟鼠标
micro python
JJGong
更新2022-03-02
四川大学
1233

1 项目需求

1.1.利用板上的四向摇杆和按键设计一款“鼠标”

1.2.在240*240的LCD屏幕内可以通过该鼠标进行菜单选择和参数控制(在屏幕上要有图形化的箭头形状)

1.3.通过USB端口可以控制PC屏幕上的光标移动和点击操作,行使电脑鼠标的功能

 

2 硬件介绍

本次使用到的是基于树莓派RP2040的嵌入式系统学习板,运用其上的240*240分辨率的彩色IPS LCD,SPI接口,ST7789控制器,四向摇杆和2个轻触按键。

 

3 完成的功能及达到的性能

3.1 “顶流”冰墩墩的问好

初始页面在rp2040的lcd屏上加载了一张2022年北京冬奥会吉祥物冰墩墩的照片,并配文“Bing Dwen Dwen:welcome!”

Fi8oa-zWHRtbvFK7s9vumxG1HkSM

3.2 LCD屏幕内菜单

在照片停留数秒之后将在LCD屏幕上显示两排字,分别是“click”(点击)和“slide”(滑动),对应的是鼠标移动和点击功能,以及滑轮滚动功能。

FluMMWtBDu_FVA4WtrFU5gyiLqui

3.3 LCD屏内光标移动控制

进入菜单界面后,左上角会有一个初始光标,在四向摇杆控制下能进行上下左右四向移动,当其运动到“click”所在行或者“slide”所在行时,对应行会变为白色,对应字母会变为蓝色。当对应行亮起时,可以按下A键,则进入到相应模式。

FjrPTB1ogv-36z4LEQvhrNBxWa99Fot8PT8hp7cGQOTh_5mBI0l1zPNf

3.4 click功能介绍

在click模式下,A键模拟为鼠标左键,B键模拟为鼠标右键,四向摇杆可操纵电脑光标360°移动,并且可以根据摇杆相对中心的偏离大小调整电脑光标移动速度。在按下A键时,为鼠标左键点击功能,按下不动可继续摇动摇杆实现长串字符的选择;按下B键时,为鼠标右键的点击功能,再摇动摇杆选择,按A键即可实现对应复制、粘贴等功能。如果要退回菜单,则需先按住A键,再同时按下B键,在依次松开A、B键。下图为长串字符选择的展示:

FvX06QKPAN8YaPDpa8Op7s7z0aEV

3.5 slide功能介绍

在slide模式下,四向摇杆的上下两个方向模拟了鼠标滚轮,当摇杆向下摇动时,电脑页面向上移动;当摇杆向上摇动时,电脑页面向下移动。如果要退回菜单,则需按下B键。

 

4 实现思路

4.1 摇杆在左右上下四个方向摇动时,将会通过ADC采集摇杆电位,返回对应的x、y值,且摇动幅度越大,对应值的绝对值越大,摇动方向不同,则对应值的正负不同,用对应的返回值即可实现光标移动的速度调整。

4.2 A、B键按下返回值可用于判定确定、返回。

4.3流程图

FoYHxxFTlAw0SeRl8tDqd7AbEHvf

5 实现过程

5.1 冰墩墩展示部分代码,此处主要用了库函数,用了延时

f_image = open(image_file0, 'rb')
for column in range(1,240):
    buf=f_image.read(480)
    blit_buffer(buf, 1, column, 240,1)
sleep(2)
text(font2,"Bing Dwen Dwen:",0,120,st7789.WHITE,st7789.BLACK)
sleep(0.5)
text(font2,"welcome!",80,170,st7789.WHITE,st7789.BLACK)
sleep(2)

5.2 lcd屏幕光标移动菜单选择部分代码,通过返回电位判断摇杆方向、倾斜度,返回的数据即用作光标图像位置移动的依据

fill(st7789.BLACK)
text(font2,"     click     ",0,30,st7789.WHITE,st7789.BLACK)
text(font2,"     slide     ",0,80,st7789.WHITE,st7789.BLACK)
xValue = xAxis.read_u16()
yValue = yAxis.read_u16()
if(xValue>60000):
    x=x+10
elif(xValue<400):
    x=x-10
if(yValue>60000):
    y=y+10
if(yValue<400):
    y=y-10
f_image = open(image_file1, 'rb')
    forcolumn in range(x,240):
    buf=f_image.read(480)
    blit_buffer(buf, y, column, 10, 1)

5.3 光标移到click(slide同理)上使其高亮部分代码,当光标位置到了相应行的范围时,将会将click、slide显示的颜色做出改变。

while(x>10 and x<55):
    display.fill(st7789.BLACK)
    display.text(font2,"     click     ",0,30,st7789.BLUE,st7789.WHITE)
    display.text(font2,"     slide     ",0,80,st7789.WHITE,st7789.BLACK)
    xValue = xAxis.read_u16()
    yValue = yAxis.read_u16()
    if(xValue>60000):
        x=x+10
    if(yValue>60000):
        y=y+10
    if(xValue<400):
        x=x-10
    if(yValue<400):
        y=y-10
    f_image = open(image_file1, 'rb')
    for column in range(x,240):
       buf=f_image.read(480)
       display.blit_buffer(buf, y, column, 10, 1)

5.4 点击选择click模式(slide模式同理)代码

while(xValue>20000and xValue<40000 and yValue>20000 and yValue<40000):
    buttonValueA = buttonA.value()
    if(buttonValueA==0):
    click()

5.5 click模式,模拟鼠标左右键及控制屏幕光标过程代码,同样是用ADC读取摇杆电位用来做鼠标移动方向、大小的参照,同时用到按钮A、B内部拉高电阻检测低电平,返回的数据用来做点击的判断。

def click(): 
    xAxis = ADC(Pin(28))
    yAxis = ADC(Pin(29))
    buttonA = Pin(6,Pin.IN, Pin.PULL_UP)
    buttonB = Pin(5,Pin.IN, Pin.PULL_UP)
    a=Mouse()
    while True:
        xValue = xAxis.read_u16()
        yValue = yAxis.read_u16()
        buttonValueA = buttonA.value()
        buttonValueB = buttonB.value()
        xStatus = 0
        yStatus = 0
        while(buttonValueA == 0 and buttonValueB == 1):
            if(buttonValueB == 0):
                break
            a.press(1)
            buttonValueA = buttonA.value()
            buttonValueB = buttonB.value()
            xValue = xAxis.read_u16()
            yValue = yAxis.read_u16()
            if(yValue>34000 or yValue<33000 or xValue>33200 or xValue<32000):
                a.move(yValue//5000-6, xValue//5000-26, v=0, h=0)
        a.release(1)
        while(buttonValueB == 0 and buttonValueA == 1):
            a.press(2)
            xValue = xAxis.read_u16()
            yValue = yAxis.read_u16()
            buttonValueA = buttonA.value()
            buttonValueB = buttonB.value()  
        a.release(2)
        if(yValue>34000 or yValue<33000 or xValue>33200 or xValue<32000):
            a.move(yValue//5000-6, xValue//5000-6, v=0, h=0)
        if(buttonValueA == 0 and buttonValueB == 0):
            a.release(2)
            break

5.6 slide模式模拟鼠标滑轮部分代码

def slide():
    buttonB = Pin(5,Pin.IN, Pin.PULL_UP)
    buttonValueB = 1
    xAxis = ADC(Pin(28))
    a=Mouse()
    while True:
        xValue = xAxis.read_u16()
        if(xValue>33200 or xValue<32000):
            a.move(0, 0, xValue//30000-1, 0)
        xValue = 0
        buttonValueB = buttonB.value()
        if(buttonValueB == 0):
            break

 

6 遇到的主要难题及问题处理亮点

6.1 lcd屏上光标的移动难题

任务要求lcd屏上也要有光标,并对菜单上的模式进行选择,相比控制电脑光标,其没有库用来直接对本就模拟好的鼠标直接操控。为了实现目标,只好将光标图往屏幕上贴,并实时控制并反馈光标图位置,将此位置信息作为模式选择的依据。但移动光标图(即改变图像生成位置)前不将上次的光标图清除,将会出现多个图共存,所以不得不清屏后再次生成包括菜单、光标在内的图像。

6.2 click模式下,退回到菜单难题

退回菜单操作在slide模式下很容易,直接按下B键,但在click模式下,A、B键均被占用,使用单一按键极不方便退回。刚开始想用双按方案,即同时按下A、B键,但由于要实现长字符的截取,在按下A键后必须进入while循环,保证A键按住的同时只有光标位置在刷新,导致同时按下时大概率进入循环,而不能进行if判断退出。后来想到在A键按下后的循环里加一条if语句,即在按下A键后若再按下B键则break退出while,此时用if判断两个键是否同时按下。值得注意的是,在按下B退出A循环后,为了避免陷入原本按下B要进入的循环,我将进入循环的条件改为了B按下、A不按下,这样这个问题就顺利解决了。此问题具体流程图如下

Fs1h3GFfs3j63h70k-ES4-OexzsO

6.3 模块化处理

在编写click、slide模式下的程序时,直接将其定义为库函数,在主程序中进行应用,大大提升了主程序的可读性,也便于后续修改。

6.4 参数调整目标的创造性改变

为了完成选题中参数控制的目标,最初的方案是设定speed速度变量,在菜单中新增setting模式,进入该模式用摇杆调整speed大小,在click模式下移动电脑屏幕光标时,对应速度参数直接用speed函数。该方法可行,但感觉较笨拙。在权衡之后,我相处用摇杆偏移后的返回值直接用来做速度参数,偏移越大返回值越大,速度参数就越大,光标移动也就越快,这样做增强了实用性,减去了不必要的流程。

6.5 光标移动到相应位置时高亮处理

6.6 萌萌的冰墩墩增添了乐趣

 

7 后续可改进之处

7.1 还未做出说明书,只是自己,最多游戏手柄使用者能直接上手使用(游戏手柄A、B键逻辑在任务中有所体现)。

7.2 由于还没弄明白汉字的转换,所以菜单上还没有显示出汉字,只是全英文。

7.3 还可以在A、B按键按下时控制蜂鸣器发出声音,实现炫酷音效。

7.4 菜单实用但太单调,可以加上背景图,其他灯效等。

附件下载
代码.rar
完整代码压缩包
团队介绍
四川大学
团队成员
龚俊吉
四川大学电气类
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号