基于树莓派RP2040实现鼠标功能
使用RP2040micropython模拟实现鼠标功能,利用mma7660三轴姿态传感器实现滚轮效果,显示屏显示鼠标大概位置
标签
嵌入式系统
MicroPython
mma7660
2022寒假在家练
rp2040鼠标
SPI接口240*240彩色显示屏
listeningsnow
更新2022-03-03
燕山大学里仁学院
1207

硬禾学堂2022寒假在家练-使用树莓派RP2040实现鼠标功能

一 项目简介:

该项目是使用树莓派RP2040模拟鼠标功能,并且在树莓派显示屏幕上大致显示鼠标位置。使用micropython开发基于RP2040的嵌入式学习平台。

实现的功能和大致方法如下:

  • 树莓派摇杆控制鼠标移动,A、B键分别模拟鼠标右键和左键。
  • 利用内置三轴姿态传感器实现竖向和横向翻页(模拟鼠标滚轮)
  • 利用树莓派的显示器显示鼠标所在屏幕的大致位置
  • 通过树莓派上另外的select和start按键实现鼠标速度的改变

二 设计思路:

  • 鼠标移动:判断摇杆的电位与中值电位的比较来判断摇杆位置,并以此电位值关联鼠标位置改变量dx、dy。由于我使用的函数是相对上次位置进行移动,也就是每次赋值给函数dx与dy两个值来达到移动的效果。
  • 鼠标滚轮:利用自带的三轴姿态传感器输出的(x,y,z)姿态数据判断是否执行滚轮的操作。
  • 图形化显示:与鼠标移动不同,图形显示需要绝对位置。首先我想到分别用新旧两个列表来储存新旧x、y坐标,用新坐标显示鼠标前,用旧坐标覆盖前一个坐标来达到刷新的效果。为了使鼠标更形象,我用了坐标相差适当的两个正方形,背景色的正方形覆盖显示鼠标的正方形。在屏幕上方做鼠标速度的图形化显示,通过改变显示色与背景色矩形的宽度来达到速度图形化的效果。

三 软件流程图:

FsseAOlDj8WgPtsLunHi9TY1hhxl

 

FmtLUBhCmES_NKyT14tbJWU-zVm-

 

四 简单的硬件介绍

  • 采用树莓派Pico核心芯片RP2040:
  • 240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789
  • 四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制
  • 板上外扩2MB Flash,预刷MicroPython的UF2固件
  • 一个红外接收管 + 一个红外发射管
  • 一个三轴姿态传感器MMA7660
  •  一个蜂鸣器
  • 双排16Pin连接器,有SPI、I2C以及2路模拟信号输入
  • USB Type C连接器用于供电、程序下载

五 实现的功能及图片展示:

  • 利用显示屏显示鼠标速度和光标在电脑上的大致位置,速度大小用条形蓝色矩形显示,光标类似电脑光标形状:

Ft-jw5MxettxFByW6Kc7uCRlP6-4

FuQ9wc5ku8ZsGYdLeKYcKR4q46mb

  • 按键B和A模拟鼠标的左键和右键,长按B键拖动与鼠标左键拖动选中文本功能一致:

FrCUrXt0qThBz51uNFN691DUB-3K

  • 利用姿态传感器实现鼠标滚轮效果,前倾向上翻页,后倾向下翻页,左右倾斜实现左右翻页:

Fn2Wyblo7tClpE3z6Klfm-xLA1Vi

  • 按下select键实现鼠标速度减,按下start键实现速度加:

FqK5TqbV6v5kRjmFsPzpzYoQ7NQyFl9tyHIygDNXYrfyqOsyUEe89fCX

六 主要代码片段及说明:

  • 图形化显示速度函数,速度大小为y,分为五档,每增加一档显示矩形的长加48像素;背景色刷新矩形横坐标加48像素,长减小48像素;并在(0,0)位置显示“speed”字样
def boy(y):
    display.fill_rect(0, 0, 48 * y, 10, st7789.color565(0, 0, 255))
    display.fill_rect(48 * y, 0, 240 - 48 * y, 10, st7789.color565(0, 0, 0))
    display.text(font1, "speed", 0, 0)
  • pico鼠标显示函数,dplay_1为上一个坐标数据,用来刷新上一个显示的光标,使光标做到移动的效果;dplay_2是光标坐标数据,并在此基础上x,y分别加3,再填充背景色正方形,以更形象显示光标形状
    def m_display():
        global dplay_1
        global dplay_2
        display.fill_rect(dplay_1[0]*2, dplay_1[1]*2, 8, 8, st7789.color565(0, 0, 0))
       display.fill_rect(dplay_2[0]*2, dplay_2[1]*2, 8, 8, st7789.color565(255, 255, 255))
        display.fill_rect(dplay_2[0]*2+3, dplay_2[1]*2+3, 8, 8, st7789.color565(0, 0, 0))
        dplay_1 = dplay_2[:]​
  • 摇杆数据转换鼠标移动,摇杆电位与摇杆中值电位的差的变化,来作为下次鼠标移动的变化,以达到”轻微拨动摇杆---->轻微移动光标”的效果。

        if 30000<=xValue<= 35000:
            dx = 0
        else:
            dx = dx = int(speed * (xValue -32400)/32400)
            
        if 30000<=yValue <= 35000:
            dy = 0
        else:
            dy = int(speed * (yValue -32400)/32400)
  • pico鼠标坐标更新,同样使用摇杆数据,并累加(减)进鼠标坐标数据;

        dplay_2[0] += int(display_speed*(xValue -32400)/32400)
        dplay_2[1] += int(display_speed*(yValue -32400)/32400)
        if dplay_1[0] != dplay_2[0] or dplay_1[1] != dplay_2[1]: # 防止pico显示的鼠标闪烁

七 遇到的主要难题及解决方法:

  •  pico显示的鼠标光标变成画笔,移动轨迹不擦除:

      解决办法:生成新鼠标坐标数据和上一个鼠标坐标数据,新鼠标坐标数据生成副本赋值给上一个鼠标坐标数据,用上一个鼠标数据显示背景色的正方形覆盖掉“轨迹”。

  • pico显示的鼠标光标闪烁:

原因:新坐标赋值给旧坐标实时发生,导致旧坐标虽然未改变,但是不断刷新

解决方法:加入判断语句

    if dplay_1[0] != dplay_2[0] or dplay_1[1] != dplay_2[1]: # 防止pico显示的鼠标闪烁

八 未来计划:

  1. 深入对pico的了解,学习各模块工作原理,从而在编译时能够得心应手。
  2. 更加深入学习python以及更多的代码,来加强自己的计算机语言的语感,减少编译时的错误和改善代码的计算速度和简洁性。
  3. 运用rp2040来做更多的项目以及拓展与一些功能,发挥出它应有的性能。

 

 

 

import hid
from machine import Pin, ADC, I2C
import utime
import uos
import machine
import st7789 as st7789
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2
import framebuf
from board import pin_cfg
from time import sleep
from mma7660_2 import MMA7660
from ws2812b import PixelDisplay

i2c1 = I2C(1, scl=Pin(pin_cfg.i2c1_scl), sda=Pin(pin_cfg.i2c1_sda))
acc = MMA7660(i2c1)
acc.on(True)
d = bytearray(3)
r = [0 for x in range(3)]
mouse = hid.Mouse()


dplay_1 = [0,5] # 白块旧(x,y) -> 覆盖上一个坐标的显示
dplay_2 = [0,10] # 白块新(x,y) -> 显示
speed = 18
level = 1.3 # 电脑鼠标速度与pico显示鼠标速度关联值
display_speed = speed/10*level
a = 3 # 速度屏幕图形化显示初始值


st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width / 2)
CENTER_X = int(disp_height / 2)
print(uos.uname())
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)
#
print(spi0)
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)
display.fill(st7789.BLACK)

display.text(font2, "Hello!", 5, 10)
display.text(font2, "This Pico is", 5, 50)
display.text(font2, "used as a", 5, 80)
display.text(font2, "simple mouse", 5, 110)
display.text(font2, "by Deng", 110, 200)

utime.sleep(1)
display.fill(st7789.BLACK)

display.text(font2, "Please put you", 5, 10)
display.text(font2, "mouse in the", 5, 45)
display.text(font2, "top left ", 45, 90)
display.text(font2, "to get ", 5, 135)
display.text(font2, "accurate", 50, 170)
display.text(font2, "position", 110, 205)
utime.sleep(3)
display.fill(st7789.BLACK)

# 初始速度图形化显示
display.fill_rect(0, 0, 3*48, 10, st7789.color565(0, 0, 255))
display.text(font1, "speed", 10, 0)

xAxis = ADC(Pin(29))
yAxis = ADC(Pin(28))
button = Pin(6, Pin.IN, Pin.PULL_UP)
button_b = Pin(5, Pin.IN, Pin.PULL_UP)
start = Pin(7, Pin.IN, Pin.PULL_UP)
select = Pin(8, Pin.IN, Pin.PULL_UP)

# 图形化显示速度函数
def boy(y):
    display.fill_rect(0, 0, 48 * y, 10, st7789.color565(0, 0, 255))
    display.fill_rect(48 * y, 0, 240 - 48 * y, 10, st7789.color565(0, 0, 0))
    display.text(font1, "speed", 0, 0)

# pico鼠标显示函数
def m_display():
    global dplay_1
    global dplay_2
    display.fill_rect(dplay_1[0]*2, dplay_1[1]*2, 8, 8, st7789.color565(0, 0, 0))
    display.fill_rect(dplay_2[0]*2, dplay_2[1]*2, 8, 8, st7789.color565(255, 255, 255))
    display.fill_rect(dplay_2[0]*2+3, dplay_2[1]*2+3, 8, 8, st7789.color565(0, 0, 0))
    dplay_1 = dplay_2[:]
    return dplay_1


def twos_compliment(n, nbits):
    sign_bit = 1 << nbits - 1
    sign = 1 if n & sign_bit == 0 else -1
    val = n & ~sign_bit if sign > 0 else sign * ((sign_bit << 1) - n)
    return val

def thumb_filter(a):
    return a


while True:
    acc.getSample(d)
    xValue = xAxis.read_u16()
    yValue = yAxis.read_u16()
    buttonValue = button.value()
    button_bValue = button_b.value()

    startValue = start.value()
    selectValue = select.value()

    if 30000<=xValue<= 35000:
        dx = 0
    else:
        dx = dx = int(speed * (xValue -32400)/32400)
        
    if 30000<=yValue <= 35000:
        dy = 0
    else:
        dy = int(speed * (yValue -32400)/32400)

    if buttonValue == 0:  # A---左击
        mouse.press(2)
    else:
        mouse.release(2)
    if button_b.value() == 0:  # B---右击
        mouse.press(1)
    else:
        mouse.release(1)
    if start.value() == 0:  # start---速度+
        a += 1
        level +=0.2
        boy(a)
        speed += 3
        print(speed)
        utime.sleep(0.2)
    if select.value() == 0:  # select---速度—
        a -= 1
        level -=0.2
        boy(a)
        speed -= 3
        print(speed)
        utime.sleep(0.2)
    
    # pico鼠标坐标更新
    dplay_2[0] += int(display_speed*(xValue -32400)/32400)
    dplay_2[1] += int(display_speed*(yValue -32400)/32400)
    if dplay_1[0] != dplay_2[0] or dplay_1[1] != dplay_2[1]: # 防止pico显示的鼠标闪烁
        m_display()
    # 设置屏幕边界
    if dplay_2[0] >240:
        dplay_2[0] = 240
        
    if dplay_2[0] <0:
        dplay_2[0] = 0
        
    if dplay_2[1] >240:
        dplay_2[1] = 240
        
    if dplay_2[1] <10:
        dplay_2[1] = 10
    # 滚轮竖向和横向
    
    for i in range(3):
        r[i] = twos_compliment(d[i], 6)
    # 竖向
    
    if r[0] >= 18:
        dv = 1
        utime.sleep(0.01)
    elif r[0] <=-18:
        dv = -1
        utime.sleep(0.01)
    else:
        dv = 0
    
    # 横向
    
    if r[1] >= 18:
        dh = 1
        utime.sleep(0.01)
    elif r[1] <=-20:
        dh = -1
        utime.sleep(0.01)
    else:
        dh = 0
    mouse.move(dx,dy,v=dv,h=dh)






 

附件下载
mouse_deng.zip
团队介绍
团队成员
listeningsnow
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号