一.任务要求
- .通过软件产生随机数,程序启动以后在随机数控制的时间下点亮板上的WS2812b
- 灯带颜色变化时,被测试者迅速按下按键,处理器计算从点亮灯到接收到按键之间的时间差
- 3将时间差通过USB显示在PC端和OLED屏幕。
- 将当前时间,温度显示在OLED屏幕。
- 蜂鸣器响作为背景音乐
二.环境配置
- Thonny 特征: 简单的调试器 代码补全 易于上手 下载后的安装非常简单,并且其中自带了 Python 解释器。也就是说,事先并不需要安装 Python,并且它的安装包大小比 Python 安装文件还小了接近一半。安装过程过于简单也不会有勾选环境变量之类的操作,唯一的选项就是在安装完之后提示是否创建快捷方式,勾选即可。
- 硬禾学堂“2023年寒假一起练”平台 2023寒假一起练平台(1)- 基于STEP Pico的嵌入式系统学习平台 - 电子森林 (eetree.cn)
三.板卡介绍
- 核心模块原理图https://www.eetree.cn/wiki/_media/stepico1.0.pdf
- 项目开源代码https://gitee.com/picospuch/eetree-mpy-lecture-code
- 项目案例https://www.eetree.cn/project/detail/103
四.Micropython
Damien George是一名计算机工程师,他每天都要使用Python语言工作,同时也在做一些机器人项目。有一天,他突然冒出了一个想法:能否用Python语言来控制单片机,进行实现对机器人的操控呢?Python是一款比较容易上手的脚本语言,而且有强大的社区支持,一些非计算机专业领域的人都选它作为入门语Python是一种易于学习,使用广泛且富有表现力的编程语言。用简洁简单的代码在Python中编写你的程序很容易。此外,Python蓬勃发展,因为它拥有一个组织良好,积极主动,多样化和热情的全球社区。 MicroPython是Python 3的完全重新实现。除了在后面的段落中描述的一些差异之外,您对Python的了解也适用于MicroPython 。
五.代码实现
将板卡连接到我们电脑上,打开Thonny,新建一个项目,导入相应的库(这一步可以理解为准备好做菜的材料)
import ws2812b
from oled import oled
from button import button
from board import pin_cfg
import font6
import freesans20
from writer import Writer
import time
from machine import Pin,PWM,RTC
import random
PWM模块
参考资料:https://blog.csdn.net/weixin_51684355/article/details/127033184
脉冲宽度调制是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中PWM最重要的两个参数就是频率和占空比,在这个历程中,频率决定的是蜂鸣器音调的高低,占空比的区间为0-65535
- PWM.freq([值]): 设置PWM输出频率函数。value: PWM输出频率,数值应符合PWM频率计算公式
- PWM.duty_u16([value]): 设定计数器比较值, value: 设置占空比比例,数值应在0-65536间
pwm = PWM(Pin(pin_cfg.buzzer)) #PWM对象构造函数 #其作用是指定GPIO重新初始化,并设置为PWM输出 def pitch(frequency, duration=0): pwm.freq(frequency) #PWM输出频率设置函数 #根据参数value自动计算分频器参数和TOP寄存器参数 #注意value数值应符合PWM频率计算公式,过大或过小都会导致分辨率变小 pwm.duty_u16(3000) #PWM占空比设置函数 #value数值应在0-65536间 #根据参数value自动计算出相对应的数值并赋予CC寄存器 #当计数器数值小于CC寄存器时,PWM输出高电平,反之输出低电平 time.sleep_ms(duration)
range (start, stop[, step])分别是起始、终止和步长,如果步长不设置则默认为1。
for freq in range(880, 1760, 16):
pitch(freq, 6)
for freq in range(1760, 880, -16):
pitch(freq, 6)
ADC模块
(参考博客)https://blog.csdn.net/q1009020096/article/details/124618759
- 树莓派Pico内置5个ADC引脚,其中4引脚接入了内置的温度传感器。通过ADC通道4,读取芯片内部温度。在此过程中,使用手触摸Pi Pico表面加热,或者使用酒精喷洒芯片表面进行降温。
- reading的数值是电压值,单位是v。
- ADC(analogue-digital converter) 也即模拟数字转换器,也就是把模拟信号转换为数字信号。
- mpy最常处理的数据是2个字节16位 RP2040芯片上搭载的ADC能够支持12比特的数模转换:
- RP2040工作电压范围为: 0~3.3V。
- 最后一行是经验公式,我们可以在rp2040的数据手册中查找到,只能大概得到一个温度值,因为温度和电压其实并不是呈现完全线性关系的。 提高精度的两种办法:一是提高参考电压的准确度;而是产生表格进行校准。 测量了5次温度取平均值,大大提高了精确度
-
#温度 temp_a = 0 sensor_temp = machine.ADC(4) #初始化对应的ADC通道 参数为使用的ADC通道,可以使用Pin对象,也可直接指定为ADC通道 #指定初始化ADC通道4,其对应片内温度传感器 conversion_factor = 3.3 / 65535 time.sleep(0.01) for i in range(5): reading = sensor_temp.read_u16() * conversion_factor #ADC电压公式 读取ADC通道4的电压 temperature = 27 - (reading - 0.706)/0.001721 #读取相应温度 temp_a += temperature a=temp_a/5.0
OLED模块
-
OLED是Organic Light-Emitting Diode 的简称,中文名是有机发光二极管。 OLED由外部OLED显示单元和夹在其中的发光材料组成,包括阴极、发射层、导电层、阳极和底基。每个OLED的显示单元都能受控制地产生三种不同颜色的光。
-
函数的定义以关键字def开头,后面接函数名称和圆括号。括号中放入函数需要的参数。 通过冒号和缩进控制函数内容。
-
参考博客https://blog.csdn.net/qq_51226542/article/details/127224270
def print_result(msg): print(msg) oled.text(msg,0,32) oled.text(str(temperature),50,10) oled.show()
时间模块
-
我们必须导入其他的库,eg writer库才能进行字体样式的修改。
#时间的显示 rtc = RTC()#实例化RTC wri = Writer(oled, freesans20)#实例化一个writer hour = rtc.datetime()[4]#小时 minute = rtc.datetime()[5]#分钟 wri.set_textpos(oled, 0, 0)#设置文字输出的位置 wri.printstring(str(hour) + ":" + str(minute))#将时间和分钟输出出来
WS2812b模块
- 1.十六进制颜色码就是在软件中设定颜色值的代码。
- 2.我们使用的延迟时间不是固定的,而是通过调用urandom库生成的随机时间 - 暂停程序3到5秒之间-“均匀”部分指的是这两个数字之间的均匀分布。在这个模块中运用到了python的random.uniform(x, y)方法将随机生成一个实数,它在 [x,y] 范围内。需要导入 random 模块。
- 3.点亮灯带用到是的 ws2812b.on_all()函数,关闭等待用到的是 ws2812b.off_all()函数
green = "#00ff00" red = "#ff0000" yellow = "#fff00" blue = "#0000ff" purple = "#800080" ws2812b.on_all(red) time.sleep(random.uniform(3,5)) ws2812b.off_all(red) timer_start = time.ticks_ms() ws2812b.on_all(yellow) time.sleep(random.uniform(3,5)) ws2812b.off_all(yellow) timer_start = time.ticks_ms() ws2812b.on_all(green) time.sleep(random.uniform(3,5)) ws2812b.off_all(green) timer_start = time.ticks_ms() ws2812b.on_all(blue) time.sleep(random.uniform(3,5)) ws2812b.off_all(blue) timer_start = time.ticks_ms() ws2812b.on_all(purple) time.sleep(random.uniform(3,5)) ws2812b.off_all(purple) timer_start = time.ticks_ms()
按键模块
- time.ticks_diff(old_t, new_t):计算两次调用 ticks_ms(), ticks_us(), 或 ticks_cpu()之间的时间.
- 按键的使用方式一共有两种:一种是队列,另外一种是直接处理中断的方式 中断有高低电平触发,边沿触发(上升沿,下降沿) timer_start是我们的起始时间(全局变量) 在这个项目中,我采用的是中断请求(IRQ),这种方式更加灵活。首先为中断定义一个处理程序,即回调函数 k1_callback(pin) 是中断触发时运行的代码 ,第二步在回调函数中检查被按下K1按键的状态,然后设置为True以忽略进一步的按键按压(从而结束游戏)。第三步引入全局变量开始时间timer_start,创建了timer_reaction变量(实际触发中断的时间),使用time.ticks.diff()函数进行反应时间的计算(触发这行代码的时间与开始时间timer_start的差值),并进行格式化的打印。
- 最后因为该程序中,我们的触发信号为IRQ_FALLING,当中断被触发时,引脚的值会从高到低。在bsp中我们可以明确button的用法,我们将其中的参数传入进去,就可以进行button的初始化。
-
def k1_callback(pin):#回调函数 按下K1按键立马执行 中断的优先级比较高 global pressed if not pressed: pressed=True global timer_start timer_reaction= time.ticks_diff(time.ticks_ms(), timer_start) print_result(" time " + str(timer_reaction) + "ms") k1 = button(pin_cfg.k1, k1_callback, trigger=Pin.IRQ_FALLING)
使用Python时,好几次遇到错误提示:return' outside function 原因基本都是这样的: 因为Python是从第一行开始执行,因此没有把代码封装成函数(不好的编程习惯),还仍然在输出时使用return。 结果出现了上述错误提示。 此时应该使用print()函数。 原文链接:https://blog.csdn.net/dududududou/article/details/100109068
优化:
- 可以播放不同的背景音乐,但是这个功能我单独实现了,合并到一起并没有成功,相关资料参考博客https://shenlb.blog.csdn.net/article/details/121624682
- OLED显示屏幕可以制作更加美观,加上一些图案
- 运用一些文件操作,可以把采集到的反应时间生成文档,实现记录仪功能。