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

共1条 1/1 1 跳转至

【Let'sdo第3期-拾色播放器DIY】--过程帖(3)实现蜂鸣器驱动,并播放八阶音符

菜鸟
2025-12-09 18:56:07     打赏

    跟着官方给的手册成功搭建环境后我们就可以在Mu编辑器上写我们的程序了。本贴是驱动TCS3200颜色传感器并且识别颜色后控制蜂鸣器输出音符

一:接线部分

image.png

如代码配置所示,将TCS3200上的引脚照着板子上的引脚用杜邦线连接起来。

S0 -> D12, S1 -> D11, S2 -> D10, S2 -> D9, OUT -> D6, LED -> D5

蜂鸣器:绿色的为信号线,将绿色那根线接到D13上

二:代码部分:

    三色灯初始化:调用从官方下载的库,下载链接:NeoPixel LED | Adafruit ESP32-S2 Reverse TFT Feather | Adafruit Learning System

调用pixel.fill函数,将颜色传感器读取到的三色数据传参,即可控制三色灯的颜色

import neopixel  

# Neo三色灯初始化  
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)  
pixel.brightness = 0.3
pixel.fill((R_Val, G_Val, B_Val))


    颜色传感器初始化:和上篇帖子一样

class TCS3200:
    def __init__(self, s0, s1, s2, s3, out_pin):
        self.s0 = s0
        self.s1 = s1
        self.s2 = s2
        self.s3 = s3
        self.out = out_pin

        # 设置引脚方向
        self.s0.direction = digitalio.Direction.OUTPUT
        self.s1.direction = digitalio.Direction.OUTPUT
        self.s2.direction = digitalio.Direction.OUTPUT
        self.s3.direction = digitalio.Direction.OUTPUT
        self.out.direction = digitalio.Direction.INPUT

        # 设置100%频率
        self.set_frequency(2)

        # 固定校准值 - 基于提供的白色和黑色读数
        self.max_values = {'red': 526.4, 'green': 436.9, 'blue': 464.8}  # 白色参考值
        self.min_values = {'red': 177.4, 'green': 153.3, 'blue': 169.6}  # 黑色参考值

        print("使用固定校准值:")
        print(f"白色参考 - R:{self.max_values['red']}, G:{self.max_values['green']}, B:{self.max_values['blue']}")
        print(f"黑色参考 - R:{self.min_values['red']}, G:{self.min_values['green']}, B:{self.min_values['blue']}")

    def set_frequency(self, freq_mode):
        if freq_mode == 0:
            self.s0.value = False
            self.s1.value = False
        elif freq_mode == 1:
            self.s0.value = False
            self.s1.value = True
        elif freq_mode == 2:
            self.s0.value = True
            self.s1.value = False
        else:
            self.s0.value = True
            self.s1.value = True

    def set_filter(self, filter_mode):
        if filter_mode == 0:  # Red
            self.s2.value = False
            self.s3.value = False
        elif filter_mode == 1:  # Blue
            self.s2.value = False
            self.s3.value = True
        elif filter_mode == 2:  # Clear
            self.s2.value = True
            self.s3.value = False
        elif filter_mode == 3:  # Green
            self.s2.value = True
            self.s3.value = True

    def measure_frequency(self, num_cycles=10):
        """测量输出频率"""
        timestamps = []
        last_state = self.out.value

        start_time = time.monotonic()
        while len(timestamps) < num_cycles * 2 and (time.monotonic() - start_time < 1.0):
            current_state = self.out.value
            if current_state != last_state:
                timestamps.append(time.monotonic_ns())
                last_state = current_state

        if len(timestamps) < 4:
            return 0

        # 计算周期
        periods = []
        for i in range(2, len(timestamps), 2):
            period_ns = timestamps[i] - timestamps[i-2]
            periods.append(period_ns)

        if not periods:
            return 0

        avg_period_ns = sum(periods) / len(periods)
        frequency = 1_000_000_000 / avg_period_ns
        return frequency

    def read_color_raw(self):
        """读取原始RGB颜色值"""
        # 读取红色分量
        self.set_filter(0)  # Red filter
        time.sleep(0.01)
        red = self.measure_frequency(5)

        # 读取蓝色分量
        self.set_filter(1)  # Blue filter
        time.sleep(0.01)
        blue = self.measure_frequency(5)

        # 读取绿色分量
        self.set_filter(3)  # Green filter
        time.sleep(0.01)
        green = self.measure_frequency(5)

        return red, green, blue

    def read_color_calibrated(self):
        """读取校准后的RGB颜色值 (0-255范围) - 使用固定校准值"""
        red, green, blue = self.read_color_raw()

        # 应用线性映射到0-255范围
        red_norm = int(255 * (red - self.min_values['red']) / (self.max_values['red'] - self.min_values['red']))
        green_norm = int(255 * (green - self.min_values['green']) / (self.max_values['green'] - self.min_values['green']))
        blue_norm = int(255 * (blue - self.min_values['blue']) / (self.max_values['blue'] - self.min_values['blue']))

        # 限制在0-255范围内
        red_norm = max(0, min(255, red_norm))
        green_norm = max(0, min(255, green_norm))
        blue_norm = max(0, min(255, blue_norm))

        return red_norm, green_norm, blue_norm, red, green, blue

    def detect_color(self):
        """检测颜色类型 - 使用校准后的RGB值"""
        red_norm, green_norm, blue_norm, red_raw, green_raw, blue_raw = self.read_color_calibrated()

        # 颜色判断阈值 - 基于校准后的RGB值
        # 白色: 所有值都很高
        if red_norm > 200 and green_norm > 200 and blue_norm > 200:
            return 'white', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

        # 黑色: 所有值都很低
        elif red_norm < 50 and green_norm < 50 and blue_norm < 50:
            return 'black', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

        # 黄色: 红色和绿色都很高,蓝色很低
        elif red_norm > 180 and green_norm > 180 and blue_norm < 100:
            return 'yellow', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

        # 紫色: 红色和蓝色都很高,绿色很低
        elif red_norm > 150 and blue_norm > 150 and green_norm < 100:
            return 'purple', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

        # 橙色: 红色很高,绿色中等,蓝色很低
        elif red_norm > 180 and green_norm > 100 and blue_norm < 80:
            return 'orange', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm
        # 红色: 红色分量最高且足够高
        elif red_norm > green_norm and red_norm > blue_norm and red_norm > 150:
            return 'red', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

        # 绿色: 绿色分量最高且足够高
        elif green_norm > red_norm and green_norm > blue_norm and green_norm > 150:
            return 'green', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

        # 蓝色: 蓝色分量最高且足够高
        elif blue_norm > red_norm and blue_norm > green_norm and blue_norm > 150:
            return 'blue', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm



        # 未知颜色
        else:
            return 'unknown', red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm

# 初始化传感器
try:
    s0 = digitalio.DigitalInOut(board.D12)
    s1 = digitalio.DigitalInOut(board.D11)
    s2 = digitalio.DigitalInOut(board.D10)
    s3 = digitalio.DigitalInOut(board.D9)
    out_pin = digitalio.DigitalInOut(board.D6)

    led1 = digitalio.DigitalInOut(board.D5)  
    
    
    led1.direction = digitalio.Direction.OUTPUT  
    led1.value = False  

    color_sensor = TCS3200(s0, s1, s2, s3, out_pin)
    print("Color sensor initialized with fixed calibration")

    蜂鸣器代码

# 初始化蜂鸣器
pwm = pwmio.PWMOut(board.D13, 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]

    主函数:

while True:
    current_button_state = button.value

    # 按钮按下时检测颜色并播放音符
    if not current_button_state and last_button_state:
        if color_sensor:
            detected_color, red_raw, green_raw, blue_raw, red_norm, green_norm, blue_norm = color_sensor.detect_color()

            # 显示原始值和校准后的RGB值
            print(f"Raw - R:{red_raw:.1f}, G:{green_raw:.1f}, B:{blue_raw:.1f}")
            print(f"RGB - R:{red_norm}, G:{green_norm}, B:{blue_norm}, Color: {detected_color}")

            if detected_color in color_notes:
                note_index = color_notes[detected_color]
                stop_playing()
                play_note(note_index)
                time.sleep(0.5)
                stop_playing()

        time.sleep(0.3)

    last_button_state = current_button_state
    time.sleep(0.1)


由于成果演示需要视频,这里就不做演示了。现象是按下按键后识别到对应的颜色后,根据该颜色提前设置的输出频率来控制蜂鸣器的音色。

红色->C4, 绿色->E4, 蓝色->G4, 黄色->B4

白色->D4, 黑色->F4, 紫色->A4, 橙色->C5





关键词: 拾色     播放器     过程          实现     蜂鸣器     八阶     音符         

共1条 1/1 1 跳转至

回复

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