1 硬件平台
STEP Pico是一款低成本,高性能的微控制器开发板,具有灵活数字接口(完全兼容Raspberry Pi Pico)。硬件上,采用Raspberry Pi官方自主研发的RP2040微控制器芯片,搭载了ARM Cortex MO+双核处理器,高达133MHz的运行频率,内置了264KB SRAM和2MB闪存,还板载有多达26个多功能的GPIO引脚。软件上,可选择树莓派提供的C/C++SDK,或者使用MicroPvthon进行开发且配套有完善的开发资料教程,可方便快速入门开发并嵌入到产品中。
2 项目要求
利用Step Pico板卡制作一个反应测试器:随机点亮板上的一个LED,在LED亮起后马上按下板上的k1按键,并在显示屏上和pc端上显示出从灯亮到按键之间的所用时间,这是心理学上的一个重要实验。
3 计划实现的功能
最基本的功能为:在测试开始后随机等待2-5秒,然后亮起12个LED灯中随机的一个,灯亮起后按下k1便可在oled和pc端上同时显示出被测试者从灯亮起到按下按键所用的反应时间;
拓展功能为:在一次测试结束后,按下k2按键便可重新开始新一轮的测试,并同时在oled和pc端上显示该次测试的次数。
4 功能实现的具体方式和流程
对于基本功能,我设计的程序流程和使用的方式如下:
4.1随机点亮LED
在程序启动后,首先产生两个随机数,第一个随机数n用来决定被点亮的LED的序号,而第二个随机数用来控制测试开始后过多久时间来点亮板上的LED。该部分代码如下所示:
while True:
n=random.uniform(1,12)
for i in range(13):
if(n-i<0.5):
n=i
break
ws2812b.off_all()
time.sleep(random.uniform(2,5))
ws2812b.on(n, color = "#000010")
其中for循环用来对随机数n取整,因为random.uniform函数产生的随机数并非整数,而ws2812b.on函数所需要的LED序号参数为整数。
4.2按下k1后测试反应时间
在LED被点亮之后,我们先记录一次当前时间:
timer_start = time.ticks_ms()
随后进入time.sleep中等待k1的按下:
for i in range(400):
if(a==1):
break
time.sleep(0.25)
a = 0
上面这段代码用于等待k1按下,总计等100s,若100s后无反应则重新进入主循环开始新的测试。其中a的作用将在下文进行解释。
若我们在这100s内按下k1,则k1会执行以下代码:
def k1_callback(pin):
global timer_start
global flag
oled.fill(0)
timer_reaction = time.ticks_ms() - timer_start
flag = 0
print_result("Time: " + str(timer_reaction) + "ms")
time.sleep(1)
flag = 1
print_result("Again?")
k1 = button(pin_cfg.k1, k1_callback, trigger=Pin.IRQ_FALLING)
程序将再次记录一次时间,该次时间便是按下按键时的时刻,用该时刻减去之前LED灯亮起时记录的时刻,我们便可以得出被测试者从灯亮起到按下按键所用的反应时间。对于反应时间,我们使用老师所给的print_result函数将其同时显示在oled和pc上。从显示结果起过1s后,程序将再次利用print_result函数在oled和pc端上显示“again?”字样,询问被测试者是否再来一次测试。对于print_result函数我做了一点修改,利用一个变量flag来决定字符在oled上显示的位置,从而使反应时间结果和“again?”字符上下错位显示而不会混叠,如下所示:
def print_result(msg):
print(msg)
if(flag == 0):
oled.text(msg,0,26)
if(flag == 1):
oled.text(msg,0,42)
oled.show()
4.3 按下k2后进行新一轮测试
对于k2,我设置了以下一段程序,其将会在按下k2后执行:
def k2_callback(pin):
global a
global b
global flag
a = 1
b = b+1
flag = 0
oled.fill(0)
print_result("Test " + str(b))
k2 = button(pin_cfg.k2, k2_callback, trigger=Pin.IRQ_FALLING)
该代码的主要思路为:4.1中展示的主循环函数末端的for循环在每次循环时都会对a的值进行一次检测,若a值为1则跳出循环。而按下k2后,上面这段代码会将全局变量a的值置1,从而使该段for循环中0.25s的time.sleep结束后跳出循环,随后主循环将a重新归0,并开始新的一次主循环,也就是进行一次新的测试。此外,按下k2后会将初值为1的全局变量b的值加1,b的值用来在按下k2后在oled和pc端显示新一轮测试的序号次数。。
4.4 程序运行流程综述
综上所述,在程序开始运行后等待2-5s后板卡上十二个LED会随机亮起一个,在LED亮起后若测试者按下k1,则显示反应时间;若LED亮起后100s内无操作,则进行新一轮测试。在按下k1显示反应时间后,若我们再按下k2,则可跳过100s的等待时间,直接进行新一轮的测试,同时显示测试的序号次数。
程序整体流程框图如下:
5 遇到的问题与难点
在本次项目中,我遇到的难点是在oled屏幕上显示字符后,第二次再显示字符会与第一次显示的字符混叠起来,导致根本看不清显示出来的是什么。对于这个问题,我的解决方法是利用百度到的一个函数:oled.fill(0),该函数可以填满oled屏幕,括号内的值表示填满的颜色,若为0,则用黑色填满屏幕,也就是与清空屏幕一样的效果。利用此函数,我顺利解决了该难点。
6 未来的计划
在本次项目中,我第一次接触到了python语言和树莓派板卡,所做的项目也比较简单,但是我也从中学到了很多东西,不管是硬件方面还是软件方面,我都获取了很多之前从未学习过的新知识,这也为我打开了一扇新世界的大门。我计划在将来继续参与类似的项目,提升自己对硬件构造的认知,同时也可以提升自己的编程水平。