系列目录
2. 过程帖,动手时刻
效果展示

项目功能设计

上面是 此次活动的基础任务, 其中 任务1 和 任务2 的细分任务以及在开箱完成, 其中基础任务 2 由于开发板被完全包裹, 无法f方便的查看到 neo-rgb 灯的情况。
基于上述基础任务,扩展出如下功能场景:
干簧管控制 彩色传感器识别和矫正的功能。
TFT 屏幕输出颜色用于矫正传感器。
TFT 图像形象显示被测试的物件的颜色色块。
存留识别到的色彩的记录并且可以支持切换显示。
TFT 屏幕根据录制的乐曲周期切换不同颜色的图片后 让颜色传感器感应后,播放对应的音乐。
系统框图

接线框图
因为需要用上所有购得的物件,因此干脆所有物件接上再说,从功能看,有干簧管 和 色彩传感器作为输入,那 ESP32 的 neo RGB 和 蜂鸣器 以及 TFT 显示屏作为输出,这完全足够开发丰富多样的交互场景。

功能原理
色彩传感器原理以及使用说明
包含 8x8 阵列的光电二极管,每个像素是110um X 110um 的尺寸。按照 16个像素分成了四组,分别是 没有遮罩和有 蓝/绿/红 遮罩的像素,通过 两个 pin 脚 (S2,S3) 切换四组不同的组别使能切换。
其输出是使用一个 out 引脚,按照频率的形式输出对应通道的数值,这个频率也是 通过两个引脚了(S0, S1) 来做频率的缩放,具体对应关系参考:(注:S0/S1/S2/S3 都是有上拉电阻,不接的情况下默认是 H)

从规格说明书可以看到,这个芯片的工作电压是 2.7 ~ 5.5
输出色彩信号频率范围如下:(频率范围适合用 frequencyio 获取数值, 主控芯片频率是 240 MHz)
文档有给出使用建议:全速的情况下,每毫秒可以收集到1-2个数据。

编码任务实现工程骨架
此处涉及多个业务环节,其实播放器播放过程中不能影响检测,因此需要 事件驱动的形式组合相关业务逻辑,通过串口调试信息输出需要的数据。
事件驱动 包含:gpio 中断 、 timer 中断 两类,板子资源包括 按钮、输入输出、TFT 显示屏、neo-rgb。
需要引入如下包:
displayio:用于 TFT 显示绘制功能, 厂商参考 https://learn.adafruit.com/esp32-s3-reverse-tft-feather/displayio-example, 详细说明 https://learn.adafruit.com/circuitpython-display-support-using-displayio,https://docs.circuitpython.org/en/latest/shared-bindings/displayio/index.html
board:用于通过引脚别名获取 object, https://docs.circuitpython.org/en/latest/shared-bindings/board/index.html#module-board
neopixel:用于板载 neo-rgb 灯驱动,厂商参考 https://learn.adafruit.com/esp32-s3-reverse-tft-feather/neopixel, https://docs.circuitpython.org/projects/neopixel/en/latest/
alarm :用于实现 timer 事件驱动,https://docs.circuitpython.org/en/latest/shared-bindings/alarm/index.html#module-alarm
frequencyio: 用于获取 颜色传感器的频率,避免 python 虚拟机的延迟导致精度丢失。 https://docs.circuitpython.org/en/latest/shared-bindings/frequencyio/index.html
下面是主要事件驱动的骨架代码
通过时间和pin脚事件驱动方便实现多功能并行(主要是想实现音量控制, 和多按键的功能)
import alarm
def runFunc(callback, *args):
callback(*args)
class Interrupt():
def __init__(self, desc, func, *args):
self.callback = func
self.args = args
self.desc = desc
def exec(self):
#print(f"run interrupt:{self.desc} func:{self.callback} args:{self.args}")
runFunc(self.callback, *self.args)
class Timer(Interrupt):
def __init__(self, desc, delay, interval, func, *args):
super().__init__(desc, func, *args)
''' delay and interval with second union'''
self.delay = delay
self.interval = interval
self.time_next = 0
def __eq__(self, timer):
if (self.desc == timer.desc and self.func == timer.func and self.interval == timer.interval):
return True
return False
class PinHandle(Interrupt):
def __init__(self, desc, pin, pull_up, func,*args):
super().__init__(desc, func, *args)
self.pin = pin
self.last_action_time = time.monotonic() #second
self.value = 0
self.pull_up = pull_up
self.getValue()
self.default_value = self.value
print(f"create Pin handle:{desc}, pin:{pin} default_value:{self.default_value}")
def getValue(self):
with digitalio.DigitalInOut(self.pin) as gpio:
if self.pull_up:
gpio.switch_to_input(pull=digitalio.Pull.UP)
else:
gpio.switch_to_input(pull=digitalio.Pull.DOWN)
gpio.direction = digitalio.Direction.INPUT
self.value = gpio.value
def checkValueChange(self):
old = self.value
self.getValue()
if old != self.value:
self.exec()
self.last_action_time = time.monotonic()
return self.value
def __eq__(self, other):
return (self.pin == other.pin)
class EventLoop:
def __init__(self):
self.timers = []
self.pins = []
self.status_runing = 1
self.status_stop = 0
self.status = self.status_stop
self.deadline = 0
self.deadlineTimer = None
self.start_time = 0
self.pin_timer = None
def updateTimerNextTime(self, timer):
if timer.delay > 0:
timer.time_next = time.monotonic_ns() + timer.delay * 1e9
timer.delay = 0
print(f'first run timer:{timer}')
elif timer.interval > 0:
timer.time_next = time.monotonic_ns() + timer.interval * 1e9
else:
self.rmTimer(timer)
def addTimer(self, timer):
if self.status == self.status_runing:
self.updateTimerNextTime(timer)
self.timers.append(timer)
print(f'add timer:{timer}')
def rmTimer(self, timer):
if timer in self.timers:
self.timers.remove(timer)
print(f'remove timer:{timer}')
def getDeadLine(self):
self.deadline = self.timers[0]
for timer in self.timers:
if self.deadline.time_next > timer.time_next:
self.deadline = timer
#print(f'get deadline:{self.deadline}')
return self.deadline
def addPin(self, pin):
self.rmPin(pin)
if len(self.pins) == 0 and self.pin_timer == None:
self.pin_timer = Timer("pin scanner", 0, 0.005, self.triverPinStatus)
self.addTimer(self.pin_timer)
pin.checkValueChange()
self.pins.append(pin)
def rmPin(self, pin):
if pin in self.pins:
if len(self.pins) == 1 and self.pin_timer != None:
self.rmTimer(self.pin_timer)
self.pin_timer = None
self.pins.remove(pin)
def triverPinStatus(self):
for p in self.pins:
p.checkValueChange()
#print(f'button:{p.desc} value:{p.value}')
def run(self):
self.start_time = time.monotonic_ns()
self.status = self.status_runing
for i in self.timers:
self.updateTimerNextTime(i)
while True:
# timer interrupt
next = self.getDeadLine()
now = time.monotonic_ns()
if next.time_next <= now + 1e9:
#print(f'time exec: {next.desc}')
next.exec()
self.updateTimerNextTime(next)
else:
next_timer = alarm.time.TimeAlarm(monotonic_time = next.time_next/1e9)
alarm.light_sleep_until_alarms(next_timer)mainloop = EventLoop()
g_volume_manager = VolumManager()
pin_volum_up = PinHandle("volum up", board.BUTTON, True, g_volume_manager.volumButtonUp)
pin_volum_down = PinHandle("volum down", board.D2, False, g_volume_manager.volumButtonDown)
g_volume_manager.pin_up = pin_volum_up
g_volume_manager.pin_down = pin_volum_down
mainloop.addPin(pin_volum_up)
mainloop.addPin(pin_volum_down)
mainloop.run()蜂鸣器播放《两只老虎》
通过 简谱 编码蜂鸣器的音调变化, 以 0.5s 为节拍完成蜂鸣器的 频率切换。
two_tigger = [1,2,3,1,1,2,3,1, 3, 4,5,3,4,5,5,6,5,4,3,1,5,6,5,4,3,1,2,5,1,0,2,5,1,0]
two_tigger_len = len(two_tigger)
note_name = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5']
note_frequencies = [0, 261, 293, 329, 349, 392, 440, 490, 523]
note_len = len(note_frequencies)
pin_pwm = pwm.PWMOut(board.D13, duty_cycle=0, frequency=440, variable_frequency=True)
g_volume = 1024
def playNote(note):
global note_frequencies
global note_len
global pin_pwm
global g_volume
if note < note_len:
freq = note_frequencies[note]
if freq == 0:
pin_pwm.duty_cycle = 0
else:
pin_pwm.frequency = freq
pin_pwm.duty_cycle = g_volume
else:
print(f'Unknow note id:{note}')
def playNotify(sleep=0.5):
playNote(3)
time.sleep(float(sleep))
playNote(0)颜色传感器数据获取
上述文档总结可以得知 通过 frequency 模块完全可以胜任颜色数据获取。在此对比 开箱时刻按照老师提供的文档编写的统计方法,可以看到 frequency 可以在 2-3 ms 内获取到一个通道的数据,而基于统计的方法需要采样多个周期时间是 几百ms 左右, 数值看起来,也是 frequency 模块统计的比较稳定, 但是这个模块有个要求,就是频率需要大于 1khz 才能监控, 所以弱光环境会直接变成 0.
经过对比验证, 通过统计获取到的数据 最大范围是40khz, 在这个范围内,数值也很不稳定。是 frequency 获取到的两倍 (由于统计的是上升沿+下降沿), 而 frequency 的范围是 0 到 700k (red 和 clear 的确可以达到),但是它的精度有限只能 500 梯度 变化, 如果光照比较合适的情况下应该是可以正常使用。
(第二列是 frequency 获取到的颜色数值,第三列是其获取过程耗时)
色彩传感器的驱动关键代码
def get_channel_value(self, channel):
# 获取某个颜色值,通过 frequencyio 获取
self.set_rgb_channel(channel)
time.sleep(0.001)
value = 0
# for new api
with frequencyio.FrequencyIn(self.out_pin) as frequency:
frequency.capture_period = 1
time.sleep(0.008)
value = frequency.value
return value
def get_rgba_raw_value(self):
start = time.monotonic_ns()
red = self.get_channel_value("RED")
blue = self.get_channel_value("BLUE")
green = self.get_channel_value("GREEN")
clear = self.get_channel_value("CLEAR")
dt = (int)(time.monotonic_ns() - start)/1000000
print(f"raw Red:{red} Blue:{blue} Green:{green} Clear:{clear} Time:{dt}ms")
return [red, green, blue, clear]
def calibration_max(self):
# 标定最大值 获取每个梯度的颜色范围, 因为没有lut 所以只能大概颜色范围
value = self.get_rgba_raw_value()
for i in range(len(self.calibration)):
self.calibration[i] = value[i] / 256.0
print(f'calibration get scale:{self.calibration}')
def get_rgb(self):
# 根据标定的梯度值获取实际值
value = self.get_rgba_raw_value()
ret =[0, 0, 0]
for i in range(3):
scale = self.calibration[i]
if ( scale == 0):
print(f"Warning get rgb without calibration, just retrun raw value")
scale = 1
ret[i] = max(min(value[i] / scale,255),0)
return ret按键功能
音量控制 以及 补光控制 功能,使用 D0 / D2 短按来实现 音量增加和减少, 使用 D1 短按完成关闭补光
g_button_stable_s = 0.2
class VolumManager():
def __init__(self):
self.volume = 1024
self.pin_down = None
self.pin_up = None
def volumStepChange(self, up):
if up:
self.volume = min(self.volume * 2, 2**16-1)
print(f'volume up, curr:{self.volume}')
else:
self.volume = max(self.volume / 2, 2)
print(f'volume down, curr:{self.volume}')
playNotify(0.5)
def volumButton(self, up):
global g_button_stable_s
pin = self.pin_down
if up:
pin = self.pin_up
if pin.value == pin.default_value and time.monotonic() - pin.last_action_time > g_button_stable_s:
# button release
print(f'volum button released')
self.volumStepChange(up)
def volumButtonUp(self):
self.volumButton(True)
def volumButtonDown(self):
self.volumButton(False)
...
g_volume_manager = VolumManager()
pin_volum_up = PinHandle("volum up", board.BUTTON, True, g_volume_manager.volumButtonUp)
pin_volum_down = PinHandle("volum down", board.D2, False, g_volume_manager.volumButtonDown)
g_volume_manager.pin_up = pin_volum_up
g_volume_manager.pin_down = pin_volum_down
...
def onLEDButton(self):
global g_button_stable_s
if self.button_led.value == self.button_led.default_value and time.monotonic() - self.button_led.last_action_time > g_button_stable_s:
# button release
print(f'LED button released')
self.set_led(not self.led.value)
...
pin_LED = PinHandle('LED control', board.D1, False, color.onLEDButton)
color.button_led = pin_LED
mainloop.addPin(pin_LED)干簧管控制代码
def onMagicButton():
global g_button_stable_s,pin_Magic,color
if pin_Magic.value == pin_Magic.default_value:
if (time.monotonic() - pin_Magic.last_action_time) > (4 * g_button_stable_s):
# button long press
print('Magic button long released, calibration...')
color.calibration_max()
elif (time.monotonic() - pin_Magic.last_action_time) > g_button_stable_s:
# button release
print('Magic button released,record color:' '{:x}'.format(color.rgb888))
g_color_record.append(color.get_rgb())
pin_Magic = PinHandle('Magic control', board.A0, True, onMagicButton)
mainloop.addPin(pin_Magic)完整代码
import board
import digitalio
import time
import pwmio as pwm
import frequencyio
import alarm
import displayio
from adafruit_display_text import label
import terminalio
import neopixel
g_button_stable_s = 0.1 # short press time, long press time is x4
two_tigger = [1,2,3,1,1,2,3,1, 3, 4,5,3,4,5,5,6,5,4,3,1,5,6,5,4,3,1,2,5,1,0,2,5,1,0]
lubinghua = [1, 1, 6, 5, 5, 1, 1, 6, 5, 5, 6, 6, 6, 1, 6, 5, 5, 3, 5, 5, 3, 2, 3, 2, 2, 7, 6, 5, 7,
6, 6, 6, 6, 3,6, 3, 2, 1, 3, 3, 1, 1, 2, 3, 5, 6, 3, 2, 6, 6, 1, 6, 5, 5, 3, 5, 3, 2,
3, 2, 2, 7, 6, 5, 7, 6, 1, 6,5, 5, 1, 1, 6, 5, 5, 6, 6, 1, 6, 5, 5, 3, 5, 5, 3, 2]
two_tigger_len = len(two_tigger)
note_name = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5']
note_frequencies = [0, 261, 293, 329, 349, 392, 440, 490, 523]
note_len = len(note_frequencies)
pin_pwm = pwm.PWMOut(board.D13, duty_cycle=0, frequency=440, variable_frequency=True)
def runFunc(callback, *args):
callback(*args)
class Interrupt():
def __init__(self, desc, func, *args):
self.callback = func
self.args = args
self.desc = desc
def exec(self):
#print(f"run interrupt:{self.desc} func:{self.callback} args:{self.args}")
runFunc(self.callback, *self.args)
class Timer(Interrupt):
def __init__(self, desc, delay, interval, func, *args):
super().__init__(desc, func, *args)
''' delay and interval with second union'''
self.delay = delay
self.interval = interval
self.time_next = 0
def __eq__(self, timer):
if (self.desc == timer.desc and self.func == timer.func and self.interval == timer.interval):
return True
return False
class PinHandle(Interrupt):
def __init__(self, desc, pin, pull_up, func,*args):
super().__init__(desc, func, *args)
self.pin = pin
self.last_action_time = time.monotonic() #second
self.value = 0
self.pull_up = pull_up
self.getValue()
self.default_value = self.value
print(f"create Pin handle:{desc}, pin:{pin} default_value:{self.default_value}")
def getValue(self):
with digitalio.DigitalInOut(self.pin) as gpio:
if self.pull_up:
gpio.switch_to_input(pull=digitalio.Pull.UP)
else:
gpio.switch_to_input(pull=digitalio.Pull.DOWN)
gpio.direction = digitalio.Direction.INPUT
self.value = gpio.value
def checkValueChange(self):
old = self.value
self.getValue()
if old != self.value:
self.exec()
self.last_action_time = time.monotonic()
return self.value
def __eq__(self, other):
return (self.pin == other.pin)
class EventLoop:
def __init__(self):
self.timers = []
self.pins = []
self.status_runing = 1
self.status_stop = 0
self.status = self.status_stop
self.deadline = 0
self.deadlineTimer = None
self.start_time = 0
self.pin_timer = None
def updateTimerNextTime(self, timer):
if timer.delay > 0:
timer.time_next = time.monotonic_ns() + timer.delay * 1e9
timer.delay = 0
print(f'first run timer:{timer}')
elif timer.interval > 0:
timer.time_next = time.monotonic_ns() + timer.interval * 1e9
else:
self.rmTimer(timer)
def addTimer(self, timer):
if self.status == self.status_runing:
self.updateTimerNextTime(timer)
self.timers.append(timer)
print(f'add timer:"{timer.desc}" interval:{timer.interval}s')
def rmTimer(self, timer):
if timer in self.timers:
self.timers.remove(timer)
print(f'remove timer:{timer}')
def getDeadLine(self):
self.deadline = self.timers[0]
for timer in self.timers:
if self.deadline.time_next > timer.time_next:
self.deadline = timer
#print(f'get deadline:{self.deadline}')
return self.deadline
def addPin(self, pin):
self.rmPin(pin)
if len(self.pins) == 0 and self.pin_timer == None:
self.pin_timer = Timer("pin scanner", 0, 0.005, self.triverPinStatus)
self.addTimer(self.pin_timer)
pin.checkValueChange()
self.pins.append(pin)
def rmPin(self, pin):
if pin in self.pins:
if len(self.pins) == 1 and self.pin_timer != None:
self.rmTimer(self.pin_timer)
self.pin_timer = None
self.pins.remove(pin)
def triverPinStatus(self):
for p in self.pins:
p.checkValueChange()
#print(f'button:{p.desc} value:{p.value}')
def run(self):
self.start_time = time.monotonic_ns()
self.status = self.status_runing
for i in self.timers:
self.updateTimerNextTime(i)
while True:
# timer interrupt
next = self.getDeadLine()
now = time.monotonic_ns()
if next.time_next <= now + 1e9:
#print(f'time exec: {next.desc}')
next.exec()
self.updateTimerNextTime(next)
else:
next_timer = alarm.time.TimeAlarm(monotonic_time = next.time_next/1e9)
alarm.light_sleep_until_alarms(next_timer)
class VolumManager():
def __init__(self):
self.volume = 2**12
self.pin_down = None
self.pin_up = None
def volumStepChange(self, up):
if up:
self.volume = min(self.volume * 2, 2**16-1)
print(f'volume up, curr:{self.volume}')
else:
self.volume = max(self.volume / 2, 2)
print(f'volume down, curr:{self.volume}')
playNotify(0.5)
def volumButton(self, up):
global g_button_stable_s
pin = self.pin_down
if up:
pin = self.pin_up
if pin.value == pin.default_value and time.monotonic() - pin.last_action_time > g_button_stable_s:
# button release
print(f'volum button released')
self.volumStepChange(up)
def volumButtonUp(self):
self.volumButton(True)
def volumButtonDown(self):
self.volumButton(False)
def playNote(note):
global note_frequencies
global note_len
global pin_pwm
global g_volume_manager
if note < note_len:
freq = note_frequencies[note]
if freq == 0:
pin_pwm.duty_cycle = 0
else:
pin_pwm.frequency = freq
pin_pwm.duty_cycle = int(g_volume_manager.volume)
else:
print(f'Unknow note id:{note}')
class ColorSensor:
def __init__(self, s0, s1, s2, s3, led, out):
self.s0 = s0
self.s1 = s1
self.s2 = s2
self.s3 = s3
self.led = led
self.out_pin = out
s0.direction = digitalio.Direction.OUTPUT
s1.direction = digitalio.Direction.OUTPUT
s2.direction = digitalio.Direction.OUTPUT
s3.direction = digitalio.Direction.OUTPUT
led.direction = digitalio.Direction.OUTPUT
self.set_frequency(0)
self.calibration = [0, 0, 0, 0]
self.button_led = None
self.last_rgb = [0, 0, 0]
self.rgb888 = 0
def set_frequency(self, mode):
print(f"frequency not support for product")
return
frequency = [[False,False], [False,True],[True, False],[True, True]]
if mode in range(len(frequency)):
self.s0.value = frequency[mode][0]
self.s1.value = frequency[mode][1]
else:
print(f'wrong frequency mode:{mode}, it need in range:0-{len(frequency)}')
def set_rgb_channel(self, color):
colors = {
"RED": [False,False],
"BLUE": [False, True],
"CLEAR": [True, False],
"GREEN": [True, True]
}
if color in colors:
self.s2.value = colors[color][0]
self.s3.value = colors[color][1]
else:
print(f'wrong color: {color}, you need use {colors} only')
def set_led(self, value):
self.led.value = value
print(f'set led:{value}')
def onLEDButton(self):
global g_button_stable_s
if self.button_led.value == self.button_led.default_value:
if (time.monotonic() - self.button_led.last_action_time) > (4 * g_button_stable_s):
# button long press
print('LED button long released, calibration...')
self.calibration_max()
elif (time.monotonic() - self.button_led.last_action_time) > g_button_stable_s:
# button release
print('LED button released')
self.set_led(not self.led.value)
def get_channel_value(self, channel):
self.set_rgb_channel(channel)
time.sleep(0.001)
value = 0
# for new api
with frequencyio.FrequencyIn(self.out_pin) as frequency:
frequency.capture_period = 1
time.sleep(0.008)
value = frequency.value
return value
def get_rgba_raw_value(self):
start = time.monotonic_ns()
red = self.get_channel_value("RED")
blue = self.get_channel_value("BLUE")
green = self.get_channel_value("GREEN")
clear = self.get_channel_value("CLEAR")
dt = (int)(time.monotonic_ns() - start)/1000000
#print(f"raw Red:{red} Blue:{blue} Green:{green} Clear:{clear} Time:{dt}ms")
return [red, green, blue, clear]
def calibration_max(self):
value = self.get_rgba_raw_value()
for i in range(4):
self.calibration[i] = value[i] / 256.0
print(f'calibration get scale:{self.calibration}')
def get_rgb(self):
value = self.get_rgba_raw_value()
for i in range(3):
scale = self.calibration[i]
if (scale == 0):
#print(f"Warning get rgb without calibration, just retrun raw value")
scale = 1
self.last_rgb[i] = max(min(int(value[i] / scale),255),0)
new = self.last_rgb
value = (int(new[0]) << 16) + int(new[2]) + (int(new[1]) << 8)
value = min(value, 0xFFFFFF)
#if value != self.rgb888:
#print(f"[Color update] Red:{new[0]} Blue:{new[1]} Green:{new[2]}")
self.rgb888 = value
return self.rgb888
class TFTDisplay:
def __init__(self):
self.MODE_CALIBRATION = 1
self.mode = self.MODE_CALIBRATION
self.curr_color = 0x0
def showColor(self, color):
global pixel
if color == self.curr_color:
return
self.curr_color = color
red = self.curr_color >>16
green = (self.curr_color & 0xFF00) >> 8
blue = self.curr_color & 0xFF
pixel.fill((red, green, blue))
root = displayio.Group()
screen = board.DISPLAY
screen.root_group = root
bitmap = displayio.Bitmap(screen.width, screen.height, 1)
palette = displayio.Palette(1)
tileGrid = displayio.TileGrid(bitmap, pixel_shader=palette)
root.append(tileGrid)
palette[0] = color
bitmap.fill(0)
txt = f"R:{red} G:{green} B:{blue}"
textView = label.Label(terminalio.FONT, text=txt, color=0x123456, scale=2)
textView.x = 10
textView.y = 10
root.append(textView)
screen.refresh()
def showColor(color):
# without calibration
value = color.get_rgb()
print(f"Red:{value[0]} Blue:{value[1]} Green:{value[2]}")
def playLuBinHua():
index = 0
global two_tigger, two_tigger_len
while index < two_tigger_len:
playNote(two_tigger[index])
index=index + 1
time.sleep(0.5)
def playNotify(sleep=0.5):
playNote(3)
time.sleep(float(sleep))
playNote(0)
mainloop = EventLoop()
g_volume_manager = VolumManager()
pin_volum_up = PinHandle("volum up", board.BUTTON, True, g_volume_manager.volumButtonUp)
pin_volum_down = PinHandle("volum down", board.D2, False, g_volume_manager.volumButtonDown)
g_volume_manager.pin_up = pin_volum_up
g_volume_manager.pin_down = pin_volum_down
mainloop.addPin(pin_volum_up)
mainloop.addPin(pin_volum_down)
g_color_record = []
color = ColorSensor(digitalio.DigitalInOut(board.D6), digitalio.DigitalInOut(board.D9),
digitalio.DigitalInOut(board.D10), digitalio.DigitalInOut(board.D11),
digitalio.DigitalInOut(board.D12), board.D5)
color.set_frequency(3)
color.set_led(True)
pin_LED = PinHandle('LED control', board.D1, False, color.onLEDButton)
color.button_led = pin_LED
mainloop.addPin(pin_LED)
def onMagicButton():
global g_button_stable_s,pin_Magic,color
if pin_Magic.value == pin_Magic.default_value:
if (time.monotonic() - pin_Magic.last_action_time) > (4 * g_button_stable_s):
# button long press
print('Magic button long released, calibration...')
color.calibration_max()
elif (time.monotonic() - pin_Magic.last_action_time) > g_button_stable_s:
# button release
print('Magic button released,record color:' '{:x}'.format(color.rgb888))
#g_color_record.append(color.rgb888)
pin_Magic = PinHandle('Magic control', board.A0, True, onMagicButton)
mainloop.addPin(pin_Magic)
color_timer = Timer("color get", 0, 0.1, color.get_rgb)
mainloop.addTimer(color_timer)
time.sleep(1)
playNotify()
# for task 1 and 2 only
'''
g_display = TFTDisplay()
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
def showColorOnScreen():
global g_display, color
g_display.showColor(color.rgb888)
task1_timer = Timer("show color", 0, 0.2, showColorOnScreen)
mainloop.addTimer(task1_timer)
'''
#for task 3 only
index = 0
g_display = TFTDisplay()
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
def showMusicColorOnScreen():
global two_tigger, two_tigger_len,index,g_display
note = two_tigger[index]
step = 256 / 3
value = int(((note%3)*step)*(2**8)**(int(note / 3)))
index = (index+1)%two_tigger_len
print(f"show index:{index} note:{note} color:{value}")
g_display.showColor(value)
#playNote(note)
def playMusicWithColor():
global color
max = 0
index = 0
for i in range(len(color.last_rgb)):
if max < color.last_rgb[i]:
index = i
max = color.last_rgb[i]
step = 256 / 3
index = index * 3 + int(max / step)
print(f"play color:{color.rgb888}, index:{index}")
playNote(index)
task2_timer = Timer("show color", 0, 2, showMusicColorOnScreen)
mainloop.addTimer(task2_timer)
task2_play_timer = Timer("play color", 0, 1, playMusicWithColor)
mainloop.addTimer(task2_play_timer)
mainloop.run()参考
我要赚赏金
