项目介绍:基于树莓派Pico的嵌入式系统学习平台,利用板上的四向摇杆和按键设计一款“鼠标”,在240*240的LCD屏幕内可以通过该鼠标进行电脑鼠标移动速度的变化,电脑鼠标速度分为三种模式:最慢,慢,快。最后通过USB端口可以控制PC屏幕上的光标移动和点击操作,行使电脑鼠标的功能
设计思路:大体思路如下。通过板子上的ADC获取四向遥感的数据和按键状态,最后交给芯片rp2040进行处理。通过spi协议驱动st7789屏幕显示鼠标以及参数,最后通过USB数据线传递指令使鼠标移动。
软件思路:程序初始化,然后进入主循环,在主循环下面进行模式判断,模式分别为鼠标速度的快慢,最后结束。
游戏机的硬件信息:
树莓派Pico核心芯片RP2040,双核Arm Cortex M0+内核,可以运行到133MHz,
同时支持MicroPython编程。同时拥有240*240分辨率的彩色IPS,LCD,SPI接口,
控制器为ST7789。四向摇杆和3个轻触按键用做输入控制。另外板上外扩2MB Flash,
可以预刷MicroPython的UF2固件,USB Type C连接器用于供电、程序下载,以及数据的传输。
代码实现了电脑鼠标移动速度的选择,控制电脑鼠标移动速度分三个挡位,效果图如下
程序main代码如下:其作用我将用注释
#引用一些必须的库
from machine import Pin, SPI, ADC
import utime
from hid import Mouse#鼠标库
import st7789c#st7789屏幕驱动库
from board import game_kit#游戏机板子按键
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2#以上两个为字库
import framebuf
xAxis = ADC(Pin(28))
yAxis = ADC(Pin(29))
buttonB = Pin(5,Pin.IN, Pin.PULL_UP) #B
buttonA = Pin(6,Pin.IN, Pin.PULL_UP) #A
buttonStart = Pin(7,Pin.IN, Pin.PULL_UP)
buttonSelect = Pin(8,Pin.IN, Pin.PULL_UP)
mouse=Mouse()
spi = SPI(0, baudrate=31250000, polarity=1, phase=1,
sck=Pin(game_kit.lcd_sck, Pin.OUT),
mosi=Pin(game_kit.lcd_sda, Pin.OUT))
tft = st7789c.ST7789(
spi,
240,
240,
reset=Pin(game_kit.lcd_rst, Pin.OUT),
dc=Pin(game_kit.lcd_dc, Pin.OUT),
rotation=0)
tft.init()
def draw_shubiao(x,y,T):#画鼠标
tft.hline(0,160,230,st7789c.WHITE)
tft.hline(0,165,230,st7789c.WHITE)
tft.text(font1, "Sensitivity:", 10, 130)
tft.text(font2, "-", 130, 120)
tft.text(font2, "+", 210, 120)
tft.text(font1, "Press A to confirm", 10, 100)
tft.text(font2, "LCD_PC control", 10, 50)
f_image = open("/logo2.bin", 'rb')
for column in range(y,y+40):
buf=f_image.read(80)
tft.blit_buffer(buf, x,column, 40, 1)
class Bat:
def __init__(self, x):
self.x = x
class Bat1:
def __init__(self, y):
self.y = y
bat = Bat(0)
bat1 = Bat1(0)
#main loop
while True:
a=5
T=0
in_min,in_max,out_min,out_max = (0, 65000, -a, a)#-2 2 10 -10
filter_joystick_deadzone = lambda x: int((x - in_min) * \
(out_max - out_min) / (in_max - in_min) + out_min) if abs(x - 32768) > 500 else 0
xValue = xAxis.read_u16()
yValue = yAxis.read_u16()
A = buttonA.value()
B = buttonB.value()
buttonValueSelect = buttonSelect.value()
#获取的摇杆电压数据进入函数处理得到鼠标移动的数字
x_offset = filter_joystick_deadzone(xValue)
y_offset = filter_joystick_deadzone(yValue)
# mouse.move(y_offset, x_offset,0 ,0)#鼠标移动函数
#lcd mouse through
if y_offset==a :
tft.fill(st7789c.BLACK)
bat.x = bat.x +1
if bat.x>200:
bat.x=10
if y_offset==-(a-1):
tft.fill(st7789c.BLACK)
bat.x = bat.x -1
if bat.x<0:
bat.x=200
if x_offset==(a-1) :
bat1.y = bat1.y +1
if bat1.y>240:
bat1.y=1
if x_offset==-(a-1) :
tft.fill(st7789c.BLACK)
bat1.y = bat1.y -1
if bat1.y<0:
bat1.y=230
#progress bar
if bat.x<80 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slowest", 150, 130)
tft.fill_rect(80, 160, 150, 5, st7789c.WHITE)
tft.fill_rect(2, 160, 80, 5, st7789c.RED)
T=1
elif bat.x>80 and bat.x<110 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slow", 150, 130)
tft.fill_rect(2, 160, 80, 5, st7789c.WHITE)
tft.fill_rect(80, 160, 80, 5, st7789c.RED)
tft.fill_rect(160, 160, 70, 5, st7789c.WHITE)
T=2
elif bat.x>110 and bat.x<230 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Fast", 150, 130)
tft.fill_rect(160, 160, 70, 5, st7789c.RED)
tft.fill_rect(20, 160, 160, 5, st7789c.WHITE)
T=3
# debug print(bat.x,bat1.y)
draw_shubiao(bat.x,bat1.y,T)
utime.sleep(0.01)
if A==0 and T==1:
while True:
a=2
tft.text(font1, "Slowest", 150, 130)
in_min,in_max,out_min,out_max = (0, 65000, -a, a)#-2 2 10 -10
filter_joystick_deadzone = lambda x: int((x - in_min) * \
(out_max - out_min) / (in_max - in_min) + out_min) if abs(x - 32768) > 500 else 0
xValue = xAxis.read_u16()
yValue = yAxis.read_u16()
A = buttonA.value()
B = buttonB.value()
buttonValueSelect = buttonSelect.value()
x_offset = filter_joystick_deadzone(xValue) #获取的摇杆电压数据进入函数处理得到鼠标移动的数字
y_offset = filter_joystick_deadzone(yValue)
#lcd mouse through
if y_offset==a :
tft.fill(st7789c.BLACK)
bat.x = bat.x +1
if bat.x>200:
bat.x=10
if y_offset==-(a-1):
tft.fill(st7789c.BLACK)
bat.x = bat.x -1
if bat.x<0:
bat.x=200
if x_offset==(a-1) :
bat1.y = bat1.y +1
if bat1.y>240:
bat1.y=1
if x_offset==-(a-1) :
tft.fill(st7789c.BLACK)
bat1.y = bat1.y -1
if bat1.y<0:
bat1.y=230
#progress bar
if bat.x<80 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slowest", 150, 130)
tft.fill_rect(80, 160, 150, 5, st7789c.WHITE)
tft.fill_rect(2, 160, 80, 5, st7789c.RED)
T=1
elif bat.x>80 and bat.x<110 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slow", 150, 130)
tft.fill_rect(2, 160, 80, 5, st7789c.WHITE)
tft.fill_rect(80, 160, 80, 5, st7789c.RED)
tft.fill_rect(160, 160, 70, 5, st7789c.WHITE)
T=2
elif bat.x>110 and bat.x<230 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Fast", 150, 130)
tft.fill_rect(160, 160, 70, 5, st7789c.RED)
tft.fill_rect(20, 160, 160, 5, st7789c.WHITE)
T=3
# debug print(bat.x,bat1.y)
mouse.move(y_offset, x_offset,0 ,0)#鼠标移动函数
draw_shubiao(bat.x,bat1.y,T)
utime.sleep(0.01)
if A==0:
mouse.click(Mouse.BUTTON_RIGHT)#鼠标右键
tft.text(font2, "BUTTON_RIGHT ", 10, 10)
if B==0:
mouse.press(Mouse.BUTTON_LEFT)
tft.text(font2, "BUTTON_LEFT ", 10, 10)
else:
mouse.release(Mouse.BUTTON_LEFT)
buttonValueSelect = buttonSelect.value()
if buttonValueSelect==0:
tft.text(font2, "BUTTON_MIDDLE", 10, 10)
mouse.move(0, 0,-x_offset,y_offset)
if A==0 and T!=1:
break
if A==0 and T==3:
while True:
a=50
# tft.text(font1, "BUTTON_RIGHT ", 10, 10)
tft.text(font1, "Fast", 150, 130)
in_min,in_max,out_min,out_max = (0, 65000, -a, a)#-2 2 10 -10
filter_joystick_deadzone = lambda x: int((x - in_min) * \
(out_max - out_min) / (in_max - in_min) + out_min) if abs(x - 32768) > 500 else 0
xValue = xAxis.read_u16()
yValue = yAxis.read_u16()
A = buttonA.value()
B = buttonB.value()
buttonValueSelect = buttonSelect.value()
x_offset = filter_joystick_deadzone(xValue) #获取的摇杆电压数据进入函数处理得到鼠标移动的数字
y_offset = filter_joystick_deadzone(yValue)
#lcd mouse through
if y_offset==a :
tft.fill(st7789c.BLACK)
bat.x = bat.x +1
if bat.x>200:
bat.x=10
if y_offset==-(a-1):
tft.fill(st7789c.BLACK)
bat.x = bat.x -1
if bat.x<0:
bat.x=200
if x_offset==(a-1) :
bat1.y = bat1.y +1
if bat1.y>240:
bat1.y=1
if x_offset==-(a-1) :
tft.fill(st7789c.BLACK)
bat1.y = bat1.y -1
if bat1.y<0:
bat1.y=230
#progress bar
if bat.x<80 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slowest", 150, 130)
tft.fill_rect(80, 160, 150, 5, st7789c.WHITE)
tft.fill_rect(2, 160, 80, 5, st7789c.RED)
T=1
elif bat.x>80 and bat.x<110 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slow", 150, 130)
tft.fill_rect(2, 160, 80, 5, st7789c.WHITE)
tft.fill_rect(80, 160, 80, 5, st7789c.RED)
tft.fill_rect(160, 160, 70, 5, st7789c.WHITE)
T=2
elif bat.x>110 and bat.x<230 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Fast", 150, 130)
tft.fill_rect(160, 160, 70, 5, st7789c.RED)
tft.fill_rect(20, 160, 160, 5, st7789c.WHITE)
T=3
# debug print(bat.x,bat1.y)
print(y_offset, x_offset,bat.x,bat1.y)
if x_offset==-3 or x_offset==-2 or x_offset==-4 or x_offset==-1:
x_offset=0
mouse.move(y_offset, x_offset,0 ,0)#鼠标移动函数
# tft.text(font1, "X= "+str(y_offset), 10, 210)
# tft.text(font1, "Y= "+str(x_offset), 10, 220)
draw_shubiao(bat.x,bat1.y,T)
utime.sleep(0.01)
if A==0:
mouse.click(Mouse.BUTTON_RIGHT)#鼠标右键
tft.text(font2, "BUTTON_RIGHT ", 10, 10)
if B==0:
mouse.press(Mouse.BUTTON_LEFT)
tft.text(font2, "BUTTON_LEFT ", 10, 10)
else:
mouse.release(Mouse.BUTTON_LEFT)
buttonValueSelect = buttonSelect.value()
if buttonValueSelect==0:
tft.text(font2, "BUTTON_MIDDLE", 10, 10)
mouse.move(0, 0,-x_offset,y_offset)
if A==0 and T!=3:
break
if A==0 and T==2:
while True:
a=10
tft.text(font1, "Slow", 150, 130)
in_min,in_max,out_min,out_max = (0, 65000, -a, a)#-2 2 10 -10
filter_joystick_deadzone = lambda x: int((x - in_min) * \
(out_max - out_min) / (in_max - in_min) + out_min) if abs(x - 32768) > 500 else 0
xValue = xAxis.read_u16()
yValue = yAxis.read_u16()
A = buttonA.value()
B = buttonB.value()
buttonValueSelect = buttonSelect.value()
x_offset = filter_joystick_deadzone(xValue) #获取的摇杆电压数据进入函数处理得到鼠标移动的数字
y_offset = filter_joystick_deadzone(yValue)
#lcd mouse through
if y_offset==a :
tft.fill(st7789c.BLACK)
bat.x = bat.x +1
if bat.x>200:
bat.x=10
if y_offset==-(a-1):
tft.fill(st7789c.BLACK)
bat.x = bat.x -1
if bat.x<0:
bat.x=200
if x_offset==(a-1) :
bat1.y = bat1.y +1
if bat1.y>240:
bat1.y=1
if x_offset==-(a-1) :
tft.fill(st7789c.BLACK)
bat1.y = bat1.y -1
if bat1.y<0:
bat1.y=230
#progress bar
if bat.x<80 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slowest", 150, 130)
tft.fill_rect(80, 160, 150, 5, st7789c.WHITE)
tft.fill_rect(2, 160, 80, 5, st7789c.RED)
T=1
elif bat.x>80 and bat.x<110 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Slow", 150, 130)
tft.fill_rect(2, 160, 80, 5, st7789c.WHITE)
tft.fill_rect(80, 160, 80, 5, st7789c.RED)
tft.fill_rect(160, 160, 70, 5, st7789c.WHITE)
T=2
elif bat.x>110 and bat.x<230 and bat1.y>130 and bat1.y<170:
tft.text(font1, "Fast", 150, 130)
tft.fill_rect(160, 160, 70, 5, st7789c.RED)
tft.fill_rect(20, 160, 160, 5, st7789c.WHITE)
T=3
# debug print(bat.x,bat1.y)
print(y_offset, x_offset,bat.x,bat1.y)
mouse.move(y_offset, x_offset,0 ,0)#鼠标移动函数
draw_shubiao(bat.x,bat1.y,T)
utime.sleep(0.01)
if A==0:
mouse.click(Mouse.BUTTON_RIGHT)#鼠标右键
tft.text(font2, "BUTTON_RIGHT ", 10, 10)
if B==0:
mouse.press(Mouse.BUTTON_LEFT)
tft.text(font2, "BUTTON_LEFT ", 10, 10)
else:
mouse.release(Mouse.BUTTON_LEFT)
buttonValueSelect = buttonSelect.value()
if buttonValueSelect==0:
tft.text(font2, "BUTTON_MIDDLE", 10, 10)
mouse.move(0, 0,-x_offset,y_offset)
if A==0 and T!=2:
break
未来希望可以将鼠标更多参数添加,如在LCD屏幕上实现鼠标可以点击效果。同时拓展一个屏幕实现鼠标移动。
在项目开始之初,我遇到最大的难题在于树莓派rp2040的学习,以及micro python语言的学习,这些都是自己不熟悉的,好在只要自己坚持与努力,这些一边学一边做,最后成功完成该项目,在项目之中,听取老师和群友意见,网上查阅资料,后上机验证,最后移植到自己的程序。未来打算将屏幕刷新率做一些改善。同时扩展其他的新功能。如菜单切换,返回上一级等等。