基于树莓派RP2040制作能控制LCD和电脑界面的“鼠标”
通过microython进行编写,在树莓派RP2040芯片中实现鼠标的功能:鼠标的移动和电机,并且在LCD屏幕上进行显现。
标签
嵌入式系统
测试
显示
2020寒假在家练
树莓派RP2040
典狱长先生
更新2022-03-04
北京理工大学
695

1.项目需求

   能控制LCD和电脑界面的“鼠标”

  FtwqMrLcMoWyaPjLgtzr6TlRjfhM

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

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

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

 

2.完成的功能以及达到的性能

   本项目主要通过使用thonny开发软件实现,使用的是micropython进行编写。

 

   在项目完成过程中,实现了项目需求中要求的三个需求。可以通过摇杆和案件配合来实现鼠标的功能,虽然在使用中功能体验比不上现实生活中的鼠标,但是基本款鼠标拥有的功能都可以实现,可以使用左键点击、右键点击召唤菜单、左键长按选定范围、右键长按选定范围进行操作、以及滚轮的操作。

   同时在LCD屏幕上可以进行菜单的选择以及参数控制(鼠标灵敏度的选择),并且设置了欢迎界面和准备等待界面。

   可以通过usb接口控制pc屏幕上的光标移动和点击操作,同时摇杆的前后左右移动对应在LCD屏幕上光标的上下左右移动,注意观察的话LCD屏幕上鼠标图样的移动和PC屏幕上鼠标光标的移动是同步的。

3.实现思路

   项目的主要设计思路可以通过一个流程图的进程来表示

  Fmly78_O4WFxaC9m82mGdJEXQdO2

   首先:1.设计欢迎界面,待机时长2秒,两秒后进入等待准备界面。。

      Fj4731NGZWqB4s2i19A7PNc7KkEA

  

  1. 设计等待准备界面,使用者准备好后可以通过点击B键来继续下一步进程

   FnHVHI7DXx9tUNMyG03Wl1caaJpE

   3.灵敏度选择界面,可以通过遥感上下移动选择不同的鼠标灵敏度,灵敏度从高到低 依次为10-20-30三个挡位

   FpXmlEghtaQYfG_a6yscEUeIm20d

   4.程序正式运行页面,页面上方显示的是当前状态,分为 clicking状态、holding状态 以及sliding状态,分别对应待命/点击、长按、滚轮三组不同的状态。

   按键B/A长按对应holding状态即鼠标左键/右键长按

   FnzPqS1idjpm6Orm8JcpJtvUyAp3

   先长按B键后长按A键进入sliding状态即滚轮状态(注意应先长按B再长按A)

   Ft6tpOYSnKL9AVgYJk18oMznDZTC

   鼠标移动示意图(在演示视频中较为清晰明了)

   FoIO-Tp06PvRLLDEC4-hL1wlGBQX   

   此时可以通过点击B键和A键来进行鼠标左键/右键点按的操作

   Fpsg3HHA6bo3DmeT92NsRbvqo7G1

4.实现过程

  1. 实现过程主要分为几个不同的部分:流程链接部分、功能实现部分、辅助函数调用部分、项目变量声明部分
  2. 主函数部分代码如下:

   流程链接部分:主要通过调用poutput函数对屏幕进行刷新和显示,来达到实现思路中不同流程之间的转换,例如在等待准备界面,点击buttonB按键调用poutput函数,刷新屏幕并且打印以进入下一个灵敏度选择界面

  

#欢迎界面设计,再屏幕上显示 welcome to use the mouse project made by RP2040 author: XuZhe
pr =3
poutput()
# # 延迟1秒钟
utime.sleep_ms(2000)

#准备界面设计,再屏幕上显示 are you ready to start? you can click buttonb to start
pr =4
poutput()

#按下buttonB开始运行,出现loading加载界面
while True:
    if  buttonB.value() == 0:
        display.fill(st7789.WHITE)
        pr =5
        poutput()
        #display.text(font, "Loading....", 30, 105, st7789.BLACK, st7789.WHITE)
        break
# 延迟2秒
utime.sleep_ms(2000)

   功能实现部分:主要通过while语句进行运行,首先对摇杆移动得到的x_value和y_value的数值进行计算,通过上一步灵敏度选择界面选择的灵敏度DPI值一起进行数学运算,得到了实际鼠标移动的dx,dy数值,之后就可以通过先前声明的实例mouse来对pc鼠标进行操作。并且在板子的LCD屏幕上同步显示光标的移动。

   灵敏度选择部分:

  

#菜单选择,方向键上下滑动切换不同的鼠标速度,按下buttonB选择当前鼠标速度
while True:
    y_value = yAxis.read_u16()
    if y_value >= 30000 and y_value <=35000:
        dy = 0
    else:
        dy = int(80 * (y_value - 32400) / 32400)
    #打开图片文件
    mouse_image = open(mouseimage_file, 'rb')
    #读取像素字节
    buf = mouse_image.read(1152)
    #在板子的局部显示鼠标图片
    display.blit_buffer(buf, 200, 108+dy, 24, 24)
    utime.sleep_ms(20)
    #用白色矩形刷掉上次鼠标痕迹
    display.fill_rect(200,0,40,240,st7789.WHITE)
    #坐标判断鼠标位置,达到菜单选择的效果
    if buttonA.value() == 0 or buttonB.value() == 0:
        if dy >= 50:
            DPI = 10
            break
        if dy <= -50:
            DPI = 30
            break
        DPI = 20
        break

   鼠标指针移动部分:

  

#     鼠标指针移动设计
    x_value = xAxis.read_u16()
    y_value = yAxis.read_u16()
    if x_value >= 30000 and x_value <=35000:
        dx = 0
    else:
        dx = int(DPI * (x_value - 32400) / 32400) 
    if y_value >= 30000 and y_value <=35000:
        dy = 0
    else:
        dy = int(DPI * (y_value - 32400) / 32400)
    mouse_image = open(mouseimage_file, 'rb')
    buf = mouse_image.read(1152)
    #在板子的局部显示鼠标图片
    display.blit_buffer(buf, 110+dx*3, 120+dy*3, 24, 24)
    #移动PC鼠标
    mouse.move(dx,dy,0,0)
    utime.sleep_ms(20)
#   进行刷新
    display.fill_rect(110+dx*3,120+dy*3,24,24,st7789.WHITE) 
    dx=0
    dy=0

   后半部分是对buttonA和button B两个按键的操作进行计算,通过对feedback函数的调用,两个案件 从 holding到clicking状态的且款,并且通过全局变量tag来进行主函数与子函数之间的传递。最后当检测到两个按键同时按下的时候,状态回切换到sliding状态并且通过调用poutput函数在屏幕上方显示出来。

   鼠标点击和长按功能部分:

  

if buttonB.value() == 0:
        if buttonA.value() != 0:
            mouse.press(mouse.BUTTON_LEFT)
            if tag == 0:
                
                pr = 1
                poutput()
                #display.text(font, "mode:hold ", 10, 10, st7789.BLUE, st7789.WHITE)
                tag = 1
            timing.init(mode=Timer.PERIODIC, period=100, callback=feedback)      
    if buttonA.value() == 0:
        if buttonB.value() == 0:
#           同时长按打开滚轮操作功能
            
            pr = 2
            poutput()
            #display.text(font, "mode:slide", 10, 10, st7789.BLUE, st7789.WHITE)
            while buttonA.value() == 0 and buttonB.value() == 0:
                print("get_in")#验证是否进入循环,如果进入此循环就可以使用
                x_value = xAxis.read_u16()
                y_value = yAxis.read_u16()
                if x_value >= 30000 and x_value <= 35000:
                    dh = 0
                else:
                    dh = int(DPI * (x_value - 32400) / 32400)
                if y_value >= 30000 and y_value <= 35000:
                    dv = 0
                else:
                    dv = int(DPI * (y_value - 32400) / 32400)
                display.fill_rect(110 + dh * 3, 120 + dv * 3, 20, 20, st7789.BLACK)
                mouse.move(0, 0, dv, dh)  
                # 移动滚轮
                utime.sleep_ms(20)
                display.fill_rect(110 + dh * 3, 120 + dv * 3, 20, 20, st7789.WHITE)
                dv = 0
                dh = 0
            print("get_out_ready")#循环条件成立的验证
            pr = 0
            poutput()
            #display.text(font, "mode:click", 10, 10, st7789.BLUE, st7789.WHITE)
            continue    
        print("get_out")#循环条件成立的验证
        # 向PC发送按键按下信号
        mouse.press(mouse.BUTTON_RIGHT)  
        if tag == 0:
            
            pr = 1
            poutput()
            #display.text(font, "mode:hold ", 10, 10, st7789.BLUE, st7789.WHITE)
            tag = 1
        timing.init(mode=Timer.PERIODIC, period=100, callback=feedback) 

   辅助函数部分:两个辅助函数主要通过条件判断语句if来进行不同状态的返回。例如让pr为3的时候在屏幕上打印欢迎界面相关的图样。

  

#辅助功能设计:
#设计反馈函数用于判断是否完成了左键和右键长按的工作
def feedback(timing):
    if buttonA.value() == 1 :
        #向PC发送松开的信号
        mouse.release(mouse.BUTTON_RIGHT) 
        global tag
        tag = 0
        #display.text(font, "mode:click", 10, 10, st7789.BLUE, st7789.WHITE)
    if buttonB.value() == 1:
        #向PC发送松开的信号
        mouse.release(mouse.BUTTON_LEFT)
        global tag
        tag = 0    
    global pr
    pr = 0
    poutput()
    timing.deinit()
#设计输出函数用于进行屏幕上的打印操作
def poutput():
    if pr == 0 :
        display.fill(st7789.WHITE)
        display.text(font, "clicking   ", 10, 10, st7789.BLUE, st7789.WHITE)
    if pr == 1 :
        display.fill(st7789.WHITE)
        display.text(font, "holding    ", 10, 10, st7789.BLUE, st7789.WHITE)
    if pr == 2 :
        display.fill(st7789.WHITE)
        display.text(font, "sliding    ", 10, 10, st7789.BLUE, st7789.WHITE)
    if pr == 3 :
        display.fill(st7789.WHITE)
        display.text(font, "Welcome to use", 10, 20, st7789.BLACK, st7789.WHITE)
        display.text(font, "the mouse", 6, 60, st7789.BLACK, st7789.WHITE)
        display.text(font, "project made", 10, 100, st7789.BLACK, st7789.WHITE)
        display.text(font, "by RP2040", 10, 143, st7789.BLACK, st7789.WHITE)
        display.text(font, "author:XuZhe", 10, 190, st7789.BLACK, st7789.WHITE)
    if pr == 4 :  
        display.fill(st7789.WHITE)
        display.text(font, "AER YOU READY TO START?", 10, 20, st7789.BLACK, st7789.WHITE)
        display.text(font, "you can click ", 10, 100, st7789.BLACK, st7789.WHITE)
        display.text(font, "buttonB", 10, 143, st7789.BLACK, st7789.WHITE)
        display.text(font, "to start", 10, 190, st7789.BLACK, st7789.WHITE)
    if pr == 5 :
        display.text(font, "Loading....", 30, 105, st7789.BLACK, st7789.WHITE)
    if pr == 6 :
        display.fill(st7789.WHITE)
        display.text(font, "speed1-30", 0, 35, st7789.BLACK, st7789.WHITE)
        display.text(font, "speed2-20", 0, 105, st7789.BLACK, st7789.WHITE)
        display.text(font, "speed3-10", 0, 175, st7789.BLACK, st7789.WHITE)       
    if pr == 7 :
        display.fill(st7789.WHITE)
        display.text(font, "clicking    ", 10, 10, st7789.BLUE, st7789.WHITE)

   项目变量声明部分:主要对项目中各个变量进行声明,简化了在项目完成工程中的工作量,同时也避免了不必要的麻烦。

#初始化.
st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_width,
                          reset=machine.Pin(st7789_res, machine.Pin.OUT),
                          dc=machine.Pin(st7789_dc, machine.Pin.OUT),
                          xstart=0, ystart=0, rotation=0)


# 各种变量的初始化部分
#实例化鼠标类
mouse = Mouse() 
#按键A,B的初始化,PULL_UP是设置为上拉,按键A,B没被按下时检测到高电平
buttonA = Pin(6,Pin.IN,Pin.PULL_UP)
buttonB = Pin(5,Pin.IN,Pin.PULL_UP)
#摇杆引脚初始化,给它ADC的功能
xAxis = ADC(Pin(29)) 
yAxis = ADC(Pin(28)) 
#偏移量的初始化
dx = 0
dy = 0
dv = 0
dh = 0
DPI = 0
tag = 0
#读取文件地址
mouseimage_file = "mouse.bin"
timing = Timer()
pr = 0

 

 

5.遇到的主要难题

   在本次项目中遇到的主要难题就是对一门新的语言的变成理解,虽然在之前的学习中有接触过python语言,但是对语言的了解其实并不深刻,并且在thonny软件中需要对库文件进行加载,使得我有些原本使用过的函数在这里因为库函数并不了解,导致走了很多弯路,加上本身对python语言的学习就不是很扎实,导致我在编写代码的过程中,总是会出现一些低级错误,但是在我上网搜索和询问老师同学的过程中,我将这些问题都一一解决了。

   同样的,遇到的第二个问题就是在代码编写的过程中,因为对全局变量的忽视,导致我广泛的使用子函数而没有设置相关的全局变量,主函数和子函数之间的数值传递出现了很大的问题,同时没有考虑到持续操作的问题,使得在项目开始之初,我的代码会出现点击鼠标左键自动结束进程的问题。感谢老师和同学朋友的帮助,我在对这些问题的解决过程中,十分深刻的认识到了我的缺陷和不足,并且加深了印象,巩固了只是,使得我在项目编程的过程中越走越顺。

 

6.未来的计划建议

   在我看来python语言的开发难度要低于其他的语言,易于上手,所以在以后的学习和生活中,应该巩固对python语言的运用,通过这次的开发,我对python语言有了一些浅显的理解,但同样也有很多的不足,我应该主动接受其他的项目的编写,将这些项目积累的宝贵经验加以运用。

 

附件下载
mouse.bin
鼠标图像文件
mouse.py
程序代码文件
mouse.rar
包含项目运行所需的文件压缩包
团队介绍
徐喆-北京理工大学
团队成员
徐喆
北京理工大学2019级本科生
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号