1.项目需求
随机点亮板上的一个LED,按下板上的一个按键,在OLED显示屏上显示出从灯亮到按键之间的时间。
2.硬件介绍
基于树莓派Pico的嵌入式系统学习平台,包括树莓派Pico扩展板一块,以及硬禾版本树莓派Pico核心模块一份,可以通过C/C++以及MicroPython编程。其核心板引脚图如下。
Step pico模块为兼容树莓派官方Pico的核心模块,在其基础上增加了4个WS2812彩色灯,以及一个复位按键,USB端口也改成了Type C。它是一款低成本,高性能的微控制器开发板,具有灵活数字接口(完全兼容Raspberry Pi Pico)。
硬件上,Step pico采用Raspberry Pi官方自主研发的RP2040微控制器芯片,搭载了ARM Cortex MO+双核处理器,高达133MHz的运行频率,内置了264KB SRAM 和2MB闪存,还板载有多达26个多功能的GPIO引脚。
软件上,可选择树莓派提供的C/C++SDK,或者使用MicroPython进行开发,且配套有完善的开发资料教程,可方便快速入门开发并嵌入到产品中。
3.设计思路
程序由点灯、按键与显示三个主要功能组成,当用户开始使用时,程序启动并在随机的时间内点亮板上的随机一个led灯,用户按下按键以后,处理器计算从点亮灯到接收到按键之间的时间差,并在OLED上显示结果。程序流程图如下。
4.功能实现
(1)用户引导
当程序开始运行时,OLED屏上会显示“Press K2 button to start”,提示用户进行操作。
当用户按下K2按钮后,OLED屏上会显示“Please press K1 button when the led light is on”,提醒用户进行操作。
等待约2秒后,进入反应测试。
(2)随机灯亮起
在测试过程中,OLED屏下的四个LED灯会随机亮起,同时OLED屏清屏。如下图所示。
(3)显示测试结果
当用户在led灯亮起时按下K1按钮,则OLED屏会显示此次用户的反应时间,如下图所示。
(4)防呆设计
当用户操作过于频繁或误操作时(例如在灯未亮起时按下K1按钮),OLED屏会显示“Error!”提醒用户规范操作。如下图所示。
(5)结束测试
再次按下K2按钮,即可退出测试。
5.主要代码片段及说明
(1)点灯、灭灯操作
from led import r,g,b,y
def Led_off(): #灭灯
y.off()
r.off()
g.off()
b.off()
def Led_on(): #随机点灯
seed = random.randint(1,4)
if seed == 1:
y.on()
elif seed == 2:
r.on()
elif seed == 3:
g.on()
elif seed == 4:
b.on()
首先用random
模块产生一个随机数seed来实现随机点灯的效果,通过seed的值来调用封装好的点灯、灭灯函数。其中y、r、g、b分别指代四个led灯,led灯的定义在led.py中,代码如下。
from board import pin_cfg
import time
from machine import Pin
r = Pin(pin_cfg.red_led, Pin.OUT)
g = Pin(pin_cfg.green_led, Pin.OUT)
b = Pin(pin_cfg.blue_led, Pin.OUT)
y = Pin(pin_cfg.yellow_led, Pin.OUT)
可以看到四个led灯其实可以看做machine
模块下的四个Pin
对象。machine
模块包含与特定板上硬件相关的特定功能。该模块中的大多数功能允许实现对系统硬件块(如 CPU、定时器、总线等)的直接和不受限制的访问和控制。machine.pin
类是 machine
模块下面的一个硬件类,用于对引脚的配置和控制,提供对 Pin
设备的操作方法。Pin
对象用于控制输入/输出引脚(也称为 GPIO
)。Pin
对象通常与一个物理引脚相关联,他可以驱动输出电压和读取输入电压。Pin
类中有设置引脚模式(输入/输出)的方法,也有获取和设置数字逻辑(0
或 1
)的方法。而物理引脚的定义在board
模块中,代码如下。
class pin_cfg:
yellow_led = 20
blue_led = 21
green_led = 22
red_led = 26
buzzer = 19
mic = 27
i2c0_scl = 17
i2c0_sda = 16
i2c1_scl = 15
i2c1_sda = 14
spi1_mosi = 11
spi1_sck = 10
spi1_dc = 9
spi1_rstn = 8
spi1_cs = 29
adc0 = 26
adc1 = 27
k1 = 12
k2 = 13
pot = 28
(2)检测按钮动作
当按下K1按钮时调用该部分,计算用户反应时间同时输出结果到OLED屏上,同时加入了防呆措施。具体代码如下。
from button import button,k2
lock = False
timer_start = 0 #初始化
def Error(): #防呆
msg = "Error!"
print(msg)
oled.init_display()
oled.text(msg,0,32)
oled.show()
def k1_callback(pin):
global timer_start
global lock
if not lock:
Error()
return
timer_reaction = time.ticks_ms() - timer_start # ticks_diff
oled.text('Your reaction', 0, 20, 1)
oled.text('time was ' + str(timer_reaction) + 'ms', 0, 40, 1)
oled.show()
Led_off()
lock = False
k1 = button(pin_cfg.k1, k1_callback, trigger=Pin.IRQ_FALLING)
可以看出K1按钮其实是一个button对象,button对象的具体定义在button
模块中,在实例化一个button对象时必须传入的参数如下:
def __init__(self, pin, callback=None, trigger=Pin.IRQ_RISING, min_ago=200):
可以直观地看出,K1按钮的引脚定义在board
模块中,而每当我们按下一次K1按钮都会触发一次callback,于是我们可以在k1_callback这个函数中写入防呆和输出功能。当lock被触发时,会触发error函数提醒用户误操作,而正常工作时则会在OLED上显示用户的反应间隔。
(3)OLED屏显示
OLED有关的定义在oled.py中,具体代码如下。
from machine import Pin, SPI
from ssd1306 import SSD1306_SPI
import framebuf
from board import pin_cfg
spi = SPI(1, 100000, mosi=Pin(pin_cfg.spi1_mosi), sck=Pin(pin_cfg.spi1_sck))
oled = SSD1306_SPI(128, 64, spi, Pin(pin_cfg.spi1_dc),Pin(pin_cfg.spi1_rstn), Pin(pin_cfg.spi1_cs))
由于这块板子上是一个常见的SSD1306驱动0.96寸OLED,于是写法上也没有什么新奇的地方,我参考了一些常见的写法,实例化了一个oled对象。
6.未来的计划
该项目已经成功实现了反应测试器的功能,预期表现良好,然而还有许多可以提升与扩展的部分:
1.在一次灯熄灭到第二次灯亮起时,可以在OLED屏上显示倒计时。
2.在按下按钮时,可以有声音反馈。
3.可以在多次测试后自动退出,并在OLED屏上显示平均反应时间以达到更精确的测量。