基于RP2040实现的反应监测器
2023年寒假一起练活动(1),使用raspberry pico实现的反应速度测试器
标签
RP2040
2023寒假一起练
反应测试
vic
更新2023-03-29
1033

1.项目介绍

本文展示的是一个基于RP2040芯片作为核心实现的一个反应测试器。

在系统启动之后,OLED会显示3秒倒计时,倒计时结束之后,会随机选择12个RGB灯中的一个使用随机颜色点亮,此时用户需要按下K1、K2中的一个,0~5个LED点亮时,需要按下右边的按键K2;当6~12个LED点亮时,需要按下左边的按键K1。当按下对应的按键之后,单片机会停止计时,如果从亮灯到按下正确按键的时间间隔小于500ms时,OLED屏幕上会提示GOOD;如果按下按键的时间超过500ms则OLED会显示:emmm...

2.硬件连接

由于RP2040核心板有对应的扩展地板,所以硬件链接比较简单,如下为硬件链接示意图。RP2040作为主控制器链接128*64的OLED、12个RGB WS2812、2个独立按键。

128*64的OLED与RP2040之间通过SPI进行通信;WS2812通过一个GPIO与RP2040进行通信;独立按键分别链接RP2040的两个端口,通过读取这两个端口的电平值来获取当前按键是按下还是非按下。

FtE72NQ_mTnn__Dmv2hLwYvkFNkA

3.代码说明

整个代码使用MicroPython进行编写,使用Thonny进行文件上传以及测试。

3.1.初始化

如下代码为初始化部分代码,首先加载需要用到的库,库的相关用途如下

  • neopixel:用于控制WS2812
  • random:用于生成随机数
  • time:用于延时以及获取当前启动时间
  • machine:PICO外设相关,这里主要使用到了Pin、SPI
  • ssd1306:用于驱动OLED 12864的库

初始化完毕之后,分别针对OLED 12864、WS2812、按键1、按键2创建对应的变量,便于后续进行操作。

import neopixel
import random
import time
from machine import Pin, SPI
from ssd1306 import SSD1306_SPI

# 创建oled对象,并清空显示
oled = SSD1306_SPI(128, 64, SPI(1, 100000, mosi=Pin(11), sck=Pin(10)), Pin(9), Pin(8), Pin(29))
oled.rotate(1)
oled.fill(0)
oled.show()

# 创建环形LED对象,并关闭所有显示
n = neopixel.NeoPixel(Pin(18), 12)
n.fill((0, 0, 0))
n.write()

# 创建按键对象
k1 = Pin(13, Pin.IN, Pin.PULL_UP)
k2 = Pin(12, Pin.IN, Pin.PULL_UP)

3.2.准备界面

如下所示,为准备界面,该部分流程的主要逻辑是:每隔一秒钟在OLED上显示剩余等待秒数,在倒计时完成时,在屏幕上显示START字样,表示游戏开始。

    # 启动倒计时
    for count in range(3, 0, -1):
        oled.fill(0)
        oled.text('Countdown: %d' % (count), 0, 0)
        oled.show()
        time.sleep(1)
    else:
        oled.fill(0)
        oled.text('Start', 0, 0)
        oled.show()

3.3.点亮LED

如下代码的主要目的是,从0~12中任意选择一个LED进行点亮,点亮的颜色也是随机的,R、G、B分别从0~60中选择一个数进行组合。在设置完毕之后,使用write方法进行显示

    light_led = random.randrange(12)
    n[light_led] = (random.randrange(60), random.randrange(60), random.randrange(60))
    n.write()

3.4.检测按键

如下代码的目的为:记录LED点亮的时间戳,使用系统启动时间,单位为毫秒,然后等待对应的按键被按下,如果是0~6LED被点亮,则检查K1按键是否被按下;如果是7~12 LED被点亮,则检查K2按键是否被按下。如果按下,则记录了当前系统启动时间,通过结束时间减去起始时间以此来获取玩家的反应速度。

  # 获取当前时间作为起始时间
    time_begin = time.ticks_ms()

    while True:
        if 0 <= light_led and light_led < 6 and 0 == k1.value():
            break
        elif 6 <= light_led and light_led < 12 and 0 == k2.value():
            break

    # 获取当前时间作为结束时间
    time_end = time.ticks_ms()
    time_interval = time_end - time_begin

3.5.结果展示

如代码主要逻辑为关闭LED、在OLED上展示游戏结果,展示数据包含:起始时间戳、结束时间戳、间隔时间。当间隔时间小于500ms时提示:Very Good、当间隔时间大于500ms小于1000ms时提示:Good,当间隔时间大于1000ms时,提示:emmm....

# 关闭LED
    n[light_led] = (0, 0, 0)
    n.write()

    # 显示结果
    # 显示起始时间
    oled.text('B: %d ms' % (time_begin), 0, 0)
    # 显示结束时间
    oled.text('E: %d ms' % (time_end), 0, 12)
    # 显示间隔时间
    oled.text('I: %d ms'% (time_interval), 0, 24)

    if time_interval <= 500:
        oled.text('Very Good', 0, 36)
    elif time_interval <= 1000:
        oled.text('Good', 0, 36)
    else:
        oled.text('emmm...', 0, 36)
    oled.show()

4.功能展示

系统启动之后或者在游戏结束以后按下任意键都会自动进入到准备阶段,该界面如下图所示,会在OLED上进行倒计时,从3倒计时到0,此时用于给玩家集中注意力以及做好准备。

FhBNvSr4U5QZeEdW8YjfQq8Q-g4F

 

在倒计时结束之后,游戏开始,会在OLED屏幕上面显示:START字样,同时会使用随机的颜色点亮12个LED中的一个。此时玩家需要快速按键LED对应的按键,在游戏设计中,以蜂鸣器、OLED所在的中线作为分界线,左边6个OLED对应的按键是左边的按键K1;右边6个OLED对应的按键是右边的按键K2。

Fhd_yvW6xuqPw6ttO5oSWp3MR-D0

 

在玩家拿下正确按键之后,屏幕上就会展示出对应的状态,B表示游戏开始的时间,单位是毫秒,E表示按下正确按键的时间,单位是毫秒,I表示从游戏开始到按下正确按键的间隔时间,单位是毫秒。

当按下的间隔时间少于600ms时,认为反应速度比较快,会提示Good;反之会显示:emmm....

Fuyq-zp_vqutTFRINoc4f7KleMhT

玩家在结果显示页面任意按下一个按键,游戏会再次开始,进入到如下的倒数页面。

FhBNvSr4U5QZeEdW8YjfQq8Q-g4F

5.心得

通过这次活动,接触到了树莓派基金会推出的RP2040这款双核MCU,其使用MicroPython的方式直接进行开发,操作简单,省去了传统单片机开发的复杂IDE以及很长的编译时间,大大提升了开发速度,并且该单片机集成了树莓派一贯生态丰富,参考资源众多的特点,特别适合进行快速原型开发。

但是使用Micropython以外的开发方式就比较复杂,通过Micropython如果需要添加复杂外设编程就比较复杂。

后续可以尝试复刻一下网上的一些基于树莓派的有意思的项目,例如示波器、逻辑分析仪等。

 

 

附件下载
main.py
MicroPython程序代码
团队介绍
一个参加了4个寒假一起练,最贵板卡当股东的菜鸡
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号