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

共1条 1/1 1 跳转至

Let'sDo2025第3期任务-拾色播放器-任务二

高工
2025-12-14 23:30:26     打赏

实现板载RGB的全彩控制,实时显示当前获取的颜色;

1、硬件

 image.pngimage.png

TCS3200是一款基于光频转换技术的颜色传感器,通过内置的8×8光电二极管阵列,含红、绿、蓝及透明滤波器,检测光线颜色。每个滤波器对应16个光电二极管,可单独选择以测量特定颜色光强。传感器将光强转换为频率信号50%占空比方波,频率与光强成线性关系,便于微控制器处理。

 

ESP32原理图

image.png

电源与滤波

功能:为整个系统提供稳定的电源,通过滤波电路去除电源中的噪声和干扰,确保各模块获得纯净的电源供应。

重要性:稳定的电源是电子设备正常工作的基础,滤波电路能有效减少电源波动对系统性能的影响。

功能:电源开关用于控制整个系统的电源通断,重置电路可在系统出现异常时,通过硬件触发使系统恢复到初始状态。

重要性:方便用户对设备进行开关机操作,以及在系统死机等情况下进行复位操作,提高设备的可靠性。

USB - C接口与电源管理

功能:USB - C接口不仅用于数据传输,还可为设备充电。电源管理芯片负责管理电池的充电过程,确保充电安全高效,同时为系统提供合适的电压。

重要性:满足设备的充电需求,实现数据交互,同时保护电池和系统电路。

LIPO充电管理(LIPO CHARGING

功能:专门针对锂聚合物电池(LIPO)的充电管理模块,能够根据电池状态自动调整充电电流和电压,实现恒流 - 恒压充电过程,防止电池过充、过放和过流。

重要性:延长锂聚合物电池的使用寿命,保障电池安全,避免因不当充电导致的电池损坏甚至危险。

ESP32 - S3主控芯片

功能:作为整个系统的核心,ESP32 - S3是一款集成了Wi - Fi和蓝牙功能的微控制器。它负责处理各种数据,控制其他模块的工作,实现系统的各种功能,如与外部设备通信、处理传感器数据等。

重要性:是系统的大脑,决定了系统的性能和功能扩展能力。

NEOPIXEL接口

功能:用于连接NEOPIXEL LED灯带或其他兼容的智能LED产品。通过该接口,主控芯片可以控制LED的颜色、亮度和显示效果。

重要性:为设备添加了丰富的灯光显示功能,可用于状态指示、装饰等。

按键输入

功能:提供用户与设备交互的接口,用户可以通过按下按键向系统发送指令,如确认、返回、切换模式等。

重要性:增强了设备的操作性和用户体验,使设备能够根据用户的输入做出相应的响应。

TFT显示屏接口

功能:用于连接反向TFT显示屏,主控芯片通过该接口向显示屏发送图像数据,控制显示屏显示各种内容,如文字、图片、图形界面等。

重要性:实现设备的可视化输出,是用户获取信息的重要途径。

通用SPI TFT接口(Generic SPI TFT

功能:提供了一种通用的SPI(串行外设接口)连接方式,用于连接支持SPI协议的TFT显示屏,扩展了显示屏的兼容性。

重要性:使设备能够适配更多类型的显示屏,提高了硬件的通用性和灵活性。

引脚扩展接口

功能:提供额外的引脚接口,方便用户扩展其他功能模块,如传感器、执行器等,增强了系统的可扩展性。

重要性:使设备能够根据不同的应用需求进行功能扩展,满足多样化的使用场景。

二、代码

import time

import board

import digitalio

import displayio

import terminalio

from adafruit_display_text import label

import neopixel

import pwmio

 

初始化NeoPixel

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

pixel.brightness = 0.3

 

-----------------------

TCS3200 传感器类

-----------------------

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

 

        # 白平衡校准值

        self.white_r = 1.0

        self.white_g = 1.0

        self.white_b = 1.0

 

        # 颜色校正参数

        self.color_threshold = 0.15

 

    def set_frequency(self, freq_mode):

        if freq_mode == 0:  # 2%

            self.s0.value = False

            self.s1.value = False

        elif freq_mode == 1:  # 20%

            self.s0.value = False

            self.s1.value = True

        elif freq_mode == 2:  # 100%

            self.s0.value = True

            self.s1.value = False

        else:

            self.s0.value = True

            self.s1.value = True

 

    def set_color_channel(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

 

    def calibrate_white(self, out_pin):

        # 测量白色表面的RGB频率

        self.set_color_channel('R')

        time.sleep(0.2)

        self.white_r = measure_frequency(out_pin)

 

        self.set_color_channel('G')

        time.sleep(0.2)

        self.white_g = measure_frequency(out_pin)

 

        self.set_color_channel('B')

        time.sleep(0.2)

        self.white_b = measure_frequency(out_pin)

 

        print(f"白平衡校准完成: R={self.white_r:.1f}, G={self.white_g:.1f}, B={self.white_b:.1f}")

 

    def frequency_to_rgb(self, freq_r, freq_g, freq_b):

        # 避免除以0

        if self.white_r <= 0: self.white_r = 1

        if self.white_g <= 0: self.white_g = 1

        if self.white_b <= 0: self.white_b = 1

 

        # 计算相对值并转换为0-255范围

        r = min(255, int(255 * freq_r / self.white_r))

        g = min(255, int(255 * freq_g / self.white_g))

        b = min(255, int(255 * freq_b / self.white_b))

 

        # 颜色校正

        max_val = max(r, g, b)

        if max_val > 0:

            threshold = max_val * self.color_threshold

            if g < threshold: g = 0

            if b < threshold: b = 0

            if r < threshold: r = 0

 

        return (r, g, b)

 

-----------------------

频率测量

-----------------------

NUM_CYCLES = 10

 

def measure_frequency(out_pin):

    timestamps = []

    last = out_pin.value

    while len(timestamps) < NUM_CYCLES:

        current = out_pin.value

        if current != last:

            timestamps.append(time.monotonic_ns())

            last = current

 

    periods = []

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

        period = timestamps[i] - timestamps[i-2]

        periods.append(period)

 

    avg_period = sum(periods) / len(periods)

    return 1_000_000_000 / avg_period

 

-----------------------

蜂鸣器逻辑

-----------------------

buzzer = pwmio.PWMOut(board.A0, duty_cycle=0, frequency=440, variable_frequency=True)

 

def play_tone(frequency, duration):

    if frequency == 0:

        buzzer.duty_cycle = 0

    else:

        buzzer.frequency = frequency

        buzzer.duty_cycle = 32768

        time.sleep(duration)

        buzzer.duty_cycle = 0

        time.sleep(0.05)

 

音调频率表

yifu_f = [262, 360, 460, 569, 760, 860, 960,

        1060, 1160, 1260, 1360, 1460, 1560, 1660]

 

-----------------------

八阶音符定义

-----------------------

八阶音符频率 (C4-C5 八度)

低音到高音: C4, D4, E4, F4, G4, A4, B4, C5

对应的颜色映射: , , , 绿, , , ,

note_frequencies = [262, 294, 330, 349, 392, 440, 494, 523]  # 单位: Hz

 

音符时长定义

QUARTER_NOTE = 0.2  # 四分音符时长

EIGHTH_NOTE = 0.1   # 八分音符时长

 

def get_note_for_color(r, g, b):

    """根据RGB值确定要播放的音符和时长"""

    # 确定主色调

    max_val = max(r, g, b)

    if max_val == 0:

        return 0, QUARTER_NOTE  # 黑色,无声

 

    # 计算颜色比例

    r_ratio = r / max_val

    g_ratio = g / max_val

    b_ratio = b / max_val

 

    # 根据颜色确定音符

    if r_ratio > 0.8 and g_ratio < 0.3 and b_ratio < 0.3:  # 红色

        return note_frequencies[0], QUARTER_NOTE

    elif r_ratio > 0.8 and g_ratio > 0.5 and b_ratio < 0.3:  # 橙色/黄色

        return note_frequencies[1], QUARTER_NOTE

    elif r_ratio > 0.7 and g_ratio > 0.7 and b_ratio < 0.3:  # 黄色

        return note_frequencies[2], QUARTER_NOTE

    elif r_ratio < 0.3 and g_ratio > 0.8 and b_ratio < 0.3:  # 绿色

        return note_frequencies[3], QUARTER_NOTE

    elif r_ratio < 0.3 and g_ratio > 0.8 and b_ratio > 0.8:  # 青色

        return note_frequencies[4], QUARTER_NOTE

    elif r_ratio < 0.3 and g_ratio < 0.3 and b_ratio > 0.8:  # 蓝色

        return note_frequencies[5], QUARTER_NOTE

    elif r_ratio > 0.7 and g_ratio < 0.3 and b_ratio > 0.7:  # 紫色

        return note_frequencies[6], QUARTER_NOTE

    elif r_ratio > 0.7 and g_ratio > 0.7 and b_ratio > 0.7:  # 白色/灰色

        return note_frequencies[7], QUARTER_NOTE

    else:  # 其他颜色,根据亮度决定音符

        # 亮度值映射到音符

        brightness = (r + g + b) / 3

        note_index = int((brightness / 255) * 7)

        note_index = max(0, min(7, note_index))

        duration = QUARTER_NOTE if brightness > 127 else EIGHTH_NOTE

        return note_frequencies[note_index], duration

 

def play_melody(r, g, b):

    """播放八阶音符组成的旋律"""

    # 获取基本音符

    base_freq, base_duration = get_note_for_color(r, g, b)

 

    if base_freq == 0:  # 无声

        time.sleep(base_duration)

        return

 

    # 播放简单的旋律:主音符 + 上方三度 + 主音符

    # 计算三度音程

    third_freq = int(base_freq * 1.25)  # 大三度

 

    # 播放旋律

    play_tone(base_freq, base_duration)

    play_tone(third_freq, base_duration * 0.5)

    play_tone(base_freq, base_duration * 0.5)

 

-----------------------

TFT 显示设置 - 简化版

-----------------------

display = board.DISPLAY

splash = displayio.Group()

display.root_group = splash

 

创建全屏的颜色块

color_bitmap = displayio.Bitmap(display.width, display.height, 1)

color_palette = displayio.Palette(1)

color_palette[0] = 0x000000  # 初始黑色

 

将颜色块填满整个屏幕

color_tilegrid = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)

splash.append(color_tilegrid)

 

-----------------------

硬件引脚分配

-----------------------

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)

 

校准按键 (D1)

calibrate_button = digitalio.DigitalInOut(board.D1)

calibrate_button.direction = digitalio.Direction.INPUT

 

sensor = TCS3200(s0, s1, s2, s3, out_pin)

sensor.set_frequency(2)  # 100% 模式

 

-----------------------

串口输出函数

-----------------------

def print_color_data(freq_r, freq_g, freq_b, r, g, b):

    """通过串口输出颜色信息"""

    # 格式:频率值(Hz)RGB(0-255)

    print(f"Frequency: R={freq_r:6.1f}Hz, G={freq_g:6.1f}Hz, B={freq_b:6.1f}Hz | RGB: ({r:3}, {g:3}, {b:3})")

 

-----------------------

主循环

-----------------------

 

开机启动音效 - 播放八阶音符

print("播放启动音效...")

for freq in note_frequencies:

    play_tone(freq, 0.1)

time.sleep(0.5)

 

播放一个简单的启动旋律

play_tone(note_frequencies[0], 0.2)  # C4

play_tone(note_frequencies[2], 0.2)  # E4

play_tone(note_frequencies[4], 0.2)  # G4

play_tone(note_frequencies[7], 0.4)  # C5

 

启动时执行白平衡校准

sensor.calibrate_white(out_pin)

time.sleep(1)

 

print("颜色识别系统启动,开始读取颜色...")

print("D1按键可重新进行白平衡校准")

 

主循环

while True:

    # 检查是否需要重新校准

    if calibrate_button.value:

        time.sleep(0.05)

        if calibrate_button.value:

            print("开始白平衡校准...")

            sensor.calibrate_white(out_pin)

            print("白平衡校准完成")

            # 播放校准完成提示音

            play_tone(note_frequencies[7], 0.2)  # 高音C

            play_tone(note_frequencies[4], 0.2)  # G

            play_tone(note_frequencies[0], 0.4)  # 低音C

            while calibrate_button.value:

                time.sleep(0.01)

            time.sleep(0.5)

 

    # 测量颜色频率

    sensor.set_color_channel('R')

    time.sleep(0.05)

    freq_r = measure_frequency(out_pin)

 

    sensor.set_color_channel('G')

    time.sleep(0.05)

    freq_g = measure_frequency(out_pin)

 

    sensor.set_color_channel('B')

    time.sleep(0.05)

    freq_b = measure_frequency(out_pin)

 

    # 转换为RGB

    r, g, b = sensor.frequency_to_rgb(freq_r, freq_g, freq_b)

 

    # 串口输出颜色信息

    print_color_data(freq_r, freq_g, freq_b, r, g, b)

 

    # 更新显示颜色 - 全屏显示

    color_palette[0] = (r << 16) | (g << 8) | b

    pixel.fill((r, g, b))

 

    # 立即刷新屏幕

    display.refresh()

 

    # 蜂鸣器播放八阶音符旋律

    play_melody(r, g, b)

 

    # 短暂延时

    time.sleep(0.1)

 

 

三、连接实物图

image.png

四、实现效果

 image.pngimage.png

image.png

 

 

颜色校准系统

白平衡校准:在白色背景下读取RGB基准值,自动计算校准系数

Gamma校正:应用2.2次方的非线性映射,符合人眼视觉特性

动态范围压缩:通过map函数将传感器数据映射到0-255范围

实时性优化

10ms快速采样周期,确保颜色变化即时响应

硬件中断驱动:利用FreqCount库实现精确频率测量

双缓冲技术:避免显示闪烁,确保平滑过渡



共1条 1/1 1 跳转至

回复

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