基于STEP pico的简单反应测试仪
项目介绍
基于STEP pico的嵌入式学习平台,板载有WS2812、MMA7660三轴姿态传感器、蜂鸣器、一块spi驱动的OLED显示器、两个按键等等。此项目使用micropython进行开发,实现了一个简单的反应测试仪器。此项目的目的在于学习micropython语言,进一步学习嵌入式系统编程思想。本项目采用板载的WS2812和oled作为辅助显示,通过调用定时器计数和按键中断来完成测试的流程。
设计思路
通过板载的两个按键作为输入设备,12个led为操作指示,oled为辅助显示。通过python内置的随机数生成函数生成随机的灯的位数个等待时间,通过定时器计时,在随机生成的灯亮起时记录一次定时器的累加值,在K1按下后延时3s开始随机闪烁12个led中的任意一颗,时间在0.5s-0.7S。最多4次错误灯光后,要求的了的led点亮,此时定时器开始计数,在k2按下后在中断函数中获取第二次累加值并失能定时器。计算出中间的时间差显示在oled屏幕上。
程序框图
程序代码
1.全局定时器计数
这里的定时器中断是1ms。
tim = machine.Timer()#创建定时器实例
def timer_callback(timer):
global cycles_num
cycles_num = cycles_num+1
2.pin1按键中断程序
def pin1_callback(pin):#k1回调函数
global interruptCounter,APP_State#声明为全局变量
interruptCounter = interruptCounter+1
if (APP_State == 3)|(APP_State == 4):
wb.off_all()
f.text(display=oled, string="准备好!", font_size=16, x=20,y=10,show=True)
f.text(display=oled, string="马上开始!", font_size=16, x=20,y=30,show=True)
APP_State = 1;
tim.init(period=1, mode=machine.Timer.PERIODIC, callback=timer_callback)
elif APP_State == 5:
APP_State = 0
oled.poweron()
在此回调函数中,会判断系统状态标志位,执行点亮屏幕、开始测试和重新测试的任务。
3.pin2按键中断函数
def pin2_callback(pin):#k2回调函数
global test_num_f,cycles_num,test_num_s,pass_flag,APP_State#声明为全局变量
if APP_State == 3:
if pass_flag == 1:#判断k2是否可被按下
pass_flag=0
test_num_f = cycles_num
tim.deinit()
wb.off_all()
cycles_num = 0
test_num_f = float((test_num_f - test_num_s)/1000)
f.text(display=oled, string="所用时间:"+str(test_num_f)+"s", font_size=16, x=0,y=0,show=True)
f.text(display=oled, string="按k1重新测试", font_size=16, x=0,y=20,show=True)
f.text(display=oled, string="按k2退出", font_size=16, x=0,y=40,show=True)
sleep_ms(500)
APP_State = 4
在没有按下标志位时,pin是不工作的,以避免抢答;获取定时器的值,计算反应时间并显示在屏幕上,最后设置状态位为结束状态。
4.按键中断使能
p12 = machine.Pin(12, machine.Pin.IN, machine.Pin.PULL_UP)#引脚编号、引脚模式下降沿以及是否存在相关拉电阻
p12.irq(trigger=machine.Pin.IRQ_FALLING, handler=pin1_callback)#触发中断,回调模式
p13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)#引脚编号、引脚模式下降沿以及是否存在相关拉电阻
p13.irq(trigger=machine.Pin.IRQ_FALLING, handler=pin2_callback)#触发中断,回调模式
5.主循环
while True:
if APP_State == 0:
APP_State = 3
oled.fill(0)
f.text(display=oled, string="规则:在按下k1后\n按要求在对应的灯\n亮起时按下k2", font_size=16, x=0,y=0,show=True)
elif APP_State ==1:
oled.fill(0)
f.text(display=oled, string="倒计时:", font_size=16, x=20,y=20,show=True)
f.text(display=oled, string="3s", font_size=16, x=20,y=35,show=True)
sleep(1)
f.text(display=oled, string="2s", font_size=16, x=20,y=35,show=True)
sleep(1)
f.text(display=oled, string="1s", font_size=16, x=20,y=35,show=True)
sleep(1)
oled.fill(0)
oled.show()
APP_State =2
elif APP_State == 2:
APP_State = 3
oled.fill(0)
light_num = random.randint(1,12)
f.text(display=oled, string="请在"+str(light_num)+"蓝灯时\r\n按下k2", font_size=16, x=0,y=0,show=True)
oled.show()
# sleep_ms(random.randint(500,3000))
sleep_ms(random.randint(400,800))
for i in range(random.randint(2,8)):
wb.off_all()
aa=random.randint(1,12)
if aa == light_num:
if aa == 12:
aa = 1
else:
aa = aa + 1
wb.on(aa, "#0000ff")
sleep_ms(random.randint(400,800))
pass_flag = 1
wb.off_all()
wb.on(light_num, "#0000ff")
test_num_s = cycles_num
在主循环中多次使用随机数生成函数产生点亮灯的时间、个数,达到随机测试的目的。
硬件介绍
1.ws2812
WS2812 是一个集控制电路与发光电路于一体的智能外控 LED 光源,外形一般为 5050 封装,每个 LED 灯珠为一个像素点,支持 RGB 无极调色,同时每颗灯珠内部集成有智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,有效保证了像素点光的颜色高度一致。
据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN 端接受从控制器传输过来的数据,首先送过来的 24bit 数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过 DO 端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少 24bit。像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求。
ws2812通讯时序图
2.oled
OLED 显示屏是利用有机电自发光二极管制成的显示屏。由于具备自发光有机电激发光二极管,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
本文采用的就是如下图所示 OLED 屏幕。通信方式为 SPI。
效果展示
1.开机后显示此测试仪使用方法
2.按下k1后程序运行
3结果显示
总结:
本次使用的是raspberry pico micropython去做的开发,起初花费时间对python的基础语法做的温习。后基于micropython强大的开源生态,完善了ws2812、oled、按键等等外设的驱动。这让任务变得非常简单,micropython同时还有freertos、lvgl等有趣的开源ui和操作系统。有时间会继续摸索micropython。