一,板卡介绍
-
采用树莓派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连接器用于供电、程序下载
-
- 功能框图:
二,项目介绍
1,官方描述:
“
项目1 - 能控制LCD和电脑界面的“鼠标”
”
2,设计思路:
这是程序框图,主要利用了板子上的四向摇杆按键,AB按键,LCD屏幕,USB端口。
通过RP2040读取摇杆按键ADC数值和AB按键引脚状态,然后在屏幕上进行输出,鼠标的显示,移动等等,下面给大家介绍一下具体项目思路。
首先考虑的是鼠标的设计,根据硬禾学堂官方提供的固件,其中封装了st7789c的调用函数,查阅方法得知有一个polygon函数,polygon意为多边形,其作用为在屏幕上绘制一个多边形,于是“鼠标”就诞生了
当然,你还可以让它填充成为红色,使用以下fill_polygon函数就可以了,就像上边那样。值得注意的是,polygon使用方法
x,y为图形坐标,这样就可以引入坐标系统,实现其位移。
其次,鼠标的移动会在原位置留下残影,所以在移动之前要先擦除原图形,方法可以是在画一边与背景颜色一样的图形,达到擦除的目的,我在程序里封装了一个update_mouse(),其可以实现鼠标位置的计算和移动。另外,板子上自带了四向摇杆按键和AB两个按键,可以通过检测遥杆和按键的值来判断位置的移动,于是,鼠标的基本功能都已具备,第一小条基本完成。
然后,第二小条,通过鼠标进行菜单选择和参数控制,这个不难实现,可以利用坐标系统和按键检测来达到目的。首先是构造一个菜单,可以利用tft.text(),tft.hline()来绘制菜单,如下图所示
点击第一个是显示冰墩墩图片,第二个是显示文本,第三个是实现硬禾学堂的公众号,也可以利用自带蜂鸣器来实现播放音乐。参数控制我设置的是改变鼠标的灵敏度,鼠标移动到相应的位置并按击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的控制 ,最重要的是图形界面的绘制,图片文件的显示,但是学习中还有很多不足,比如到现在还没弄明白的红外发射,屏幕的流畅显示,总之,这次收获颇多,下次再来。