树莓派PICO——基于树莓派pico游戏机实现LCD屏幕和电脑鼠标的控制
1.利用板上的四向摇杆和按键设计一款“鼠标” 2.在240*240的LCD屏幕内可以通过该鼠标进行菜单选择和参数控制(在屏幕上要有上图中图形化的箭头形状) 3.通过USB端口可以控制PC屏幕上的光标移动和点击操作,行使电脑鼠标的功能
标签
嵌入式系统
树莓派PICO
2022寒假在家练
好喝的娃哈哈
更新2022-03-03
济南大学
2617

一,板卡介绍

  • 采用树莓派Pico核心芯片RP2040:

    • 双核Arm Cortex M0+内核,可以运行到133MHz

    • 264KB内存
    • 性能强大、高度灵活的可编程IO可用于高速数字接口

    • 片内温度传感器、并支持外部4路模拟信号输入,内部ADC采样率高达500Ksps、12位精度

    • 支持MicroPython、C、C++编程

  • 板上功能:

    • 240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789

    • 四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制

    • 板上外扩2MB Flash,预刷MicroPython的UF2固件

    • 一个红外接收管 + 一个红外发射管

    • 一个三轴姿态传感器MMA7660
    • 一个蜂鸣器

    • 双排16Pin连接器,有SPI、I2C以及2路模拟信号输入

    • 可以使用MicroPython、C、C++编程

    • USB Type C连接器用于供电、程序下载
  • 功能框图:

Fo_bQewUYVRVxvSA5ClIGJ8PyagJ

二,项目介绍

1,官方描述:

项目1 - 能控制LCD和电脑界面的“鼠标”

Fp3-L4lWql73GPmsccdKO2kVZ30Q

1.利用板上的四向摇杆和按键设计一款“鼠标”
2.在240*240的LCD屏幕内可以通过该鼠标进行菜单选择和参数控制(在屏幕上要有上图中图形化的箭头形状)
3.通过USB端口可以控制PC屏幕上的光标移动和点击操作,行使电脑鼠标的功能

2,设计思路:

这是程序框图,主要利用了板子上的四向摇杆按键,AB按键,LCD屏幕,USB端口。

通过RP2040读取摇杆按键ADC数值和AB按键引脚状态,然后在屏幕上进行输出,鼠标的显示,移动等等,下面给大家介绍一下具体项目思路。

FguEr1AohpsH0SS1cHLWH4yAMZb2

首先考虑的是鼠标的设计,根据硬禾学堂官方提供的固件,其中封装了st7789c的调用函数,查阅方法得知有一个polygon函数,polygon意为多边形,其作用为在屏幕上绘制一个多边形,于是“鼠标”就诞生了

FldS7hN5QMlMDn2PAzrjHR_idkbcFi1-5APK4faljJ5E-qwps5pryb-d

当然,你还可以让它填充成为红色,使用以下fill_polygon函数就可以了,就像上边那样。值得注意的是,polygon使用方法

FqcMGrSCGkcUkcRPMCDSY9iRdCUd

FoO9UnEMuSZyXjuHd31ulq4iUXqb

x,y为图形坐标,这样就可以引入坐标系统,实现其位移。

其次,鼠标的移动会在原位置留下残影,所以在移动之前要先擦除原图形,方法可以是在画一边与背景颜色一样的图形,达到擦除的目的,我在程序里封装了一个update_mouse(),其可以实现鼠标位置的计算和移动。另外,板子上自带了四向摇杆按键和AB两个按键,可以通过检测遥杆和按键的值来判断位置的移动,于是,鼠标的基本功能都已具备,第一小条基本完成。

然后,第二小条,通过鼠标进行菜单选择和参数控制,这个不难实现,可以利用坐标系统和按键检测来达到目的。首先是构造一个菜单,可以利用tft.text(),tft.hline()来绘制菜单,如下图所示

FuqU3KtkyOP5AKlOgMO33Fh39nGp

点击第一个是显示冰墩墩图片,第二个是显示文本,第三个是实现硬禾学堂的公众号,也可以利用自带蜂鸣器来实现播放音乐。参数控制我设置的是改变鼠标的灵敏度,鼠标移动到相应的位置并按击B键,就可以改变,每一次改变需要0.5秒,防止改变过多。自此,项目一二条基本实现。

 

最后,是通过控制游戏机遥杆和按键来控制电脑鼠标,硬禾学堂固件里面封装了HID函数,在circuitPython中可以查到这个库,对于小白的我来说完全不知道怎么移植到micropython,真是善解人意,里面有一些基本功能,移动,点击,滑动,还可以控制键盘。通过按键检测来实现鼠标的移动,由于摇杆是ADC读数,可以实现推的幅度越大,移动的越快,推的越小,移动的越慢,还可以对初始数据缩小100倍,来减小误差,当然,本着尽可能简单的原则,我没有这么做。只是实现了一个简单的匀速(龟速)移动。自此,全部功能基本实现。

三,主要代码介绍

Poly()

class Poly():             #建立鼠标对象,将poly函数封装并添加一些功能  
    def __init__(
            self,
            polygon,
            x=None,
            y=None,
            v_x=None, #x方向速度
            v_y=None, #y方向速度
            angle=None,
            scale=None,
            max_velocity=100):
        self.polygon = (
                polygon if scale is None else [(int(scale*x[0]), int(scale*x[1])) for x in polygon])
        self.x = 120 if x is None else x
        self.y = 120 if y is None else y
        self.angle = 180.0 if angle is None else angle
        self.velocity_x = 0 if v_x is None else v_x
        self.velocity_y = 0 if v_y is None else v_y
        self.max_velocity = max_velocity

    def move(self):
        self.x += int(self.velocity_x)
        self.y += int(self.velocity_y)
        self.x %= tft.width()     #超出边界从另一侧出来,也可以设置最大值,将其限制在屏幕内
        self.y %= tft.height()

    def draw(self, color):
        '''
        Draw the polygon
        '''                       #原型是polygon函数
        
        tft.polygon(self.polygon, self.x, self.y, color, self.angle, 0, 0)
        
    def fill_poly(self , color):  #原型为fill_polygon函数,可以每次只输入颜色,减少输入
        tft.fill_polygon(self.polygon,self.x,self.y,color,self.angle,0,0)

Update_mouse()

def update_mouse():            #更新鼠标位置并画出
        '''
        Update mouse velocity and limit to max_velocity
        '''
        # Limit mouse velocity to +/- max_velocity
        if mouse.velocity_x > mouse.max_velocity:
            mouse.velocity_x = mouse.max_velocity
        elif mouse.velocity_x < -mouse.max_velocity:
            mouse.velocity_x = -mouse.max_velocity

        if mouse.velocity_y > mouse.max_velocity:
            mouse.velocity_y = mouse.max_velocity
        elif mouse.velocity_y < -mouse.max_velocity:
            mouse.velocity_y = -mouse.max_velocity

        #if mouse is moving very slowly, stop it
        # move the mouse and draw it
        mouse.move()
        mouse.draw(st7789c.RED)
        mouse.velocity_x=0
        mouse.velocity_y=0

首页lcd_init0()

def lcd_init0():         #首页
    tft.text(font2,'Bingdundun',10,8,st7789c.RED,st7789c.WHITE)
    tft.text(font2,'Text',10,48,st7789c.RED,st7789c.WHITE)
    tft.text(font2,'EETree',10,88,blue,white)
    for i in range (1,5):
        tft.hline(0,i*40,240,st7789c.RED)
        tft.hline(0,i*40+1,240,st7789c.RED)
    tft.text(font2,"+",224,208,red,white)
    tft.text(font2,"-",0,208,red,white)
    tft.text(font2,str(mouse_accel_frame),100,208,red,white)

冰墩墩lcd_init1()及其它次级页面

def lcd_init1():          #冰墩墩
    tft.jpg(
    "bingdundun.jpg",
    0,
    0,
    st7789c.SLOW)
def lcd_init2():          #文本
    tft.text(font2,"ABCDEFG",10,100,red,white)
def lcd_init3():         #硬禾学堂
    tft.jpg("硬禾学堂.jpg",0,0,st7789c.SLOW)

判读摇杆方向及跟新鼠标位置坐标

def judge():                #判断鼠标移动方向
    if xValue<250 and yValue>250 and yValue<450:
        d_y=mouse_accel_frame
        mouse.velocity_y-=d_y
    if xValue>450 and yValue>250 and yValue <450:
        d_y=mouse_accel_frame
        mouse.velocity_y+=d_y
    if xValue>300 and xValue<400 and yValue>450:
        d_x=mouse_accel_frame
        mouse.velocity_x+=d_x
    if xValue>250 and xValue<450 and yValue<250:
        d_x=mouse_accel_frame
        mouse.velocity_x-=d_x
while True:
    if k%2==0:              #k如果为偶数,则控制单片机
        if i==0:
            lcd_init0()
            mouse.draw(white)       #擦除上一帧鼠标图形
            xValue = xAxis.read_u16()    #读取单片机摇杆X方向数值
            yValue = yAxis.read_u16()
            xValue=xValue//100             #X方向数值缩小100倍,减小误差
            yValue=yValue//100
            last_frame=utime.ticks_ms()  #记录这一帧开始时时间
            judge()                          #判断遥杆方向
            update_mouse()#更新鼠标图像        
        if i==1 :
            lcd_init1()               #通过i=多少来判断页面
        if i==2:
            lcd_init2()
    
        if i==3:
            lcd_init3()
        
        if mouse.y<45 and buttonB.value()==0:#根据鼠标所在位置和按键是否按下共同判断i值是否变化
            i=1                              
            utime.sleep(0.5)
        if mouse.y>45 and mouse.y<90 and buttonB.value()==0:
            i=2
            tft.fill(white)
        if mouse.y>90 and mouse.y<135 and buttonB.value()==0:
            i=3
        if mouse.y>160 and mouse.x<120 and buttonB.value()==0:
            mouse_accel_frame-=1
            utime.sleep(0.5)
            
        if mouse.y>160 and mouse.x>120 and buttonB.value()==0:
            mouse_accel_frame+=1
            utime.sleep(0.5)
        if buttonA.value()==0:  #返回并刷新背景
            i=0
            tft.fill(white)
        if buttonSelect.value()==0:
            k+=1
            utime.sleep(0.5)        #切换控制设备
        while utime.ticks_ms() - last_frame < frame_time:  #判断一帧时间,如果时间没到则等待
            pass
    else:
        xValue = xAxis.read_u16()       #控制电脑鼠标
        yValue = yAxis.read_u16()
        xValue=xValue//100
        yValue=yValue//100
        if xValue<250 and yValue>250 and yValue<450: 
            Mouse.move(0,-2)
            xValue=300
            yValue=300
        if xValue>450 and yValue>250 and yValue <450:
            Mouse.move(0,+2)
            xValue=300
            yValue=300
        if xValue>250 and xValue<450 and yValue<250:
            Mouse.move(-2,0)
            xValue=300
            yValue=300
        if xValue>300 and xValue<400 and yValue>450:
            Mouse.move(2,0)
            xValue=300
            yValue=300
        if buttonB.value() ==0:
            Mouse.click(hid.Mouse.BUTTON_LEFT)
            utime.sleep(0.1)
        if buttonA.value() ==0:
            Mouse.click(hid.Mouse.BUTTON_RIGHT)
            utime.sleep(0.1)
        if buttonSelect.value()==0:
            k+=1                      #通过K是否为偶数来判读是否为单片机还是电脑

另外,该程序还有一些BUG,不过不影响运行,就不做更改了

四,总结陈述

非常感谢硬禾学堂给提供的这次机会,学习过程中碰到了许多难题,也认识了许多有趣的人,初步学习了micropython,circuitpython,树莓派温度传感器的使用,红外传感器的使用,HID的控制 ,最重要的是图形界面的绘制,图片文件的显示,但是学习中还有很多不足,比如到现在还没弄明白的红外发射,屏幕的流畅显示,总之,这次收获颇多,下次再来。

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