这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Let'sdo第3期-拾色播放器DIY】--拾色播放器DIY活动成果帖

共1条 1/1 1 跳转至

【Let'sdo第3期-拾色播放器DIY】--拾色播放器DIY活动成果帖

助工
2025-12-14 16:28:32     打赏
【拾色播放器DIY活动成果帖】

大家好,我是EEPW论坛的网友 EMU 8086,很高兴在这里与大家分享我参与“拾色播放器DIY活动”的最终成果。本项目基于ESP32-S3开发板,完整实现了颜色感知、视觉反馈与音频播放的交互链条。下一、项目概述与硬件核心本期活动的核心任务有三:

  1. 使用颜色传感器获取环境色彩数据,并显示在屏幕上。


  2. 用板载RGB LED实时显示当前感知到的颜色。


  3. 驱动蜂鸣器,根据颜色播放对应的八阶音符。


我使用的主控是活动提供的ESP32-S3开发板,它集成了TFT屏幕和三个功能按键,极大方便了交互与调试。核心外设包括:

  • 颜色传感器:TCS3200(可编程彩色光频转换器)。


  • 输出设备:有源蜂鸣器(用于发声)、一个接近开关(用于触发)。


  • 连接方式:由于开发板可用的Digital IO数量有限(仅7个),我使用杜邦线和面包板进行连接,并精心规划了引脚。
    a825320a6998025dbeee80fe5288223.jpg


二、系统设计与引脚规划为了解决IO口紧张的问题,我对TCS3200传感器的工作模式进行了优化配置,形成了如下图的连接与逻辑框图:系统工作框图:

7e2dc98dd1ead4cdd0cd21a5c098d15.png

三、核心功能实现与代码逻辑整个程序围绕状态机按键扫描来组织,通过不同按键切换工作模式:

  1. 模式一:颜色读取与可视化


    • 操作:按下对应按键。


    • 逻辑:程序初始化传感器和RGB LED后,循环读取TCS3200输出的R、G、B三原色的频率值。将这些频率值映射到0-255的区间,然后直接驱动RGB LED发出相应颜色的光,实现“所见即所显”。


    • 串口/屏幕打印:同时,将读取到的原始频率值或映射后的RGB值打印在串口监视器和开发板的TFT屏幕上,便于调试。


  2. 模式二:八阶音符播放


    • 操作:按下另一个对应按键。


    • 逻辑:程序内置一个对应“Do-Re-Mi-Fa-So-La-Si-Do”的固定频率数组。当触发时,蜂鸣器会以PWM方式依次播放这些频率的音符,每个音符持续一个可配置的时长后停止。92b1bc08b3d964f05ebb349d67b3546.png


四、代码供大家参考

import time

import board

import digitalio

import neopixel

import pwmio


pwm = pwmio.PWMOut(board.D10,duty_cycle=0, frequency=440, variable_frequency=True)

note_names = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5']  

frequencies = [261, 293, 329, 349, 392, 440, 493, 523]  

DEBOUNCE_TIME = 0.2  

NOTE_DURATION = 0.5  

def play_note(note_index):  

    if 0 <= note_index < len(note_names):  

        freq = frequencies[note_index]  

        pwm.frequency = int(freq)  

        pwm.duty_cycle = 2 ** 15  

def stop_playing():  

    pwm.duty_cycle = 0  

    

class TCS3200:


    def __init__(self,s2_in,s3_in,out_pin_in):

        self.s2         =   digitalio.DigitalInOut(s2_in)

        self.s3         =   digitalio.DigitalInOut(s3_in)

        self.out_pin    =   digitalio.DigitalInOut(out_pin_in)


        self.s2.direction       =   digitalio.Direction.OUTPUT

        self.s3.direction       =   digitalio.Direction.OUTPUT

        self.out_pin.direction  =   digitalio.Direction.INPUT


    def set_color_filter(self,color):

        if color == 'R':

            self.s2.value   =   False

            self.s3.value   =   False

        elif color == 'G':

            self.s2.value   =   True

            self.s3.value   =   True

        elif color == 'B':

            self.s2.value   =   False

            self.s3.value   =   True

        else:

            self.s2.value   =   True

            self.s3.value   =   False


    def measure_frequency_one_channel(self,number_of_cycle=10):

        timestamps = []

        last_state = self.out_pin.value

        while len(timestamps) < number_of_cycle:

            current_state   =   self.out_pin.value

            if current_state != last_state:

                timestamps.append(time.monotonic_ns())

                last_state  =   current_state

                time.sleep(0.01)


        periods = []

        for i in range(4,len(timestamps),2):

            periods_ns  =   timestamps[i] - timestamps[i-2]

            periods.append(periods_ns)


        avg_period_ns   =   sum(periods)/len(periods)

        freq            =   1_000_000_000 / avg_period_ns

        return  freq


color_senser    =   TCS3200(board.D13,board.D12,board.D11)

def get_color_freq(cs):

    color_freq_array = []

    cs.set_color_filter('R')

    color_freq_array.append(cs.measure_frequency_one_channel())

    cs.set_color_filter('G')

    color_freq_array.append(cs.measure_frequency_one_channel())

    cs.set_color_filter('B')

    color_freq_array.append(cs.measure_frequency_one_channel())

    return color_freq_array


def display_RGB_freq(color_freq_array):

    print(f"Red freq = {color_freq_array[0]}")

    print(f"Green freq = {color_freq_array[1]}")

    print(f"Blue freq = {color_freq_array[2]}")


button = digitalio.DigitalInOut(board.D1)

button.switch_to_input(pull=digitalio.Pull.DOWN)


pixel = neopixel.NeoPixel(board.NEOPIXEL,1)

pixel.brightness = 0.1

pixel.fill((255,255,255))  # 初始化颜色


d2_button = digitalio.DigitalInOut(board.D2)  

d2_button.switch_to_input(pull=digitalio.Pull.DOWN)  


note_index = 0  

note_start_time = time.monotonic()  

previous_button_state = button.value

last_d2_state = d2_button.value

while True:

    

    current_button_state = button.value

    d2_current = d2_button.value

    if previous_button_state and not current_button_state:

#task 1:print color

        c_f_a   =   get_color_freq(color_senser)

        display_RGB_freq(c_f_a)

        c_f_a[0] = (c_f_a[0]/48) * 255

        if c_f_a[0] > 255:

            c_f_a[0] = 255

        c_f_a[1] = (c_f_a[1]/44) * 255

        if c_f_a[1] > 255:

            c_f_a[1] = 255

        c_f_a[2] = (c_f_a[2]/42) * 255

        if c_f_a[2] > 255:

            c_f_a[2] = 255

        display_RGB_freq(c_f_a)

#task2: sample color and show in LED

        pixel.fill((c_f_a[0],c_f_a[1],c_f_a[2]))

#task3: bibibi

    if d2_current and not last_d2_state:  

        stop_playing()  

        play_note(note_index)  

        note_index = (note_index + 1) % len(note_names)  

        note_start_time = time.monotonic()  

        time.sleep(DEBOUNCE_TIME)  

        stop_playing()  

    last_d2_state = d2_current

    previous_button_state = current_button_state  # 更新状态

    time.sleep(0.05)  # 短暂延迟,减少CPU占用并帮助消抖


五、总结本项目成功利用有限的IO资源,完成了ESP32-S3对TCS3200颜色传感器的驱动、数据获取、实时可视化(RGB LED)以及音频反馈(蜂鸣器)的完整功能。关键在于优化传感器配置以节省引脚,以及通过按键管理多个任务。这个“拾色播放器”不仅是一个有趣的桌面玩具,也为理解传感器应用、嵌入式系统设计提供了绝佳的实践案例。后续,可以考虑加入接近开关来实现无接触触发,或利用ESP32-S3的Wi-Fi功能,将颜色数据上传至服务器,拓展更多物联网应用可能。



b站视频链接

【Let'sdo第3期-拾色播放器DIY】_哔哩哔哩_bilibili




关键词: 拾色     播放器     成果    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]