电子网首页 > 开源与设计

[DIY拾色播放器]-任务一:TCS3200拾色传感器

2025-11-23 00:50 | 来源:电子世界报

首先要感谢EEPW给这次学习的机会。

本次学习硬件使用Adafruit ESP32-S3 Reverse TFT Feather开发板,驱动TCS3200颜色传感器取颜色数据,并在TFT显示屏上显示结果。

一、硬件接线

1、开发板原理图

在实验中会使用到ESP32-S3开发板上的按键D0、D1、D2和LED,如下:

image.png

image.png


按键D0 -> BOOT0 按键D1 -> D1 按键D2 -> D2 LED灯 -> D13

image.png 

通过Mu Editor串口指令,可查看板端已配置接口。

2、TCS3200原理图

image.png

S0,S1:设置传感器的频率缩放比例

S2,S3:设置传感器的颜色滤波器

OUT:传感器频率输出口

LED:补光灯控制口

3、接线图

image.png

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

二、库文件

image.png

三、代码实现

1、按键代码

# 初始化板载按键D0/BOOT0,按下接地
button0 = digitalio.DigitalInOut(board.BUTTON)
button0.switch_to_input(pull=digitalio.Pull.UP)
# 初始化板载按键D1,按下接VCC
button1 = digitalio.DigitalInOut(board.D1)
button1.switch_to_input(pull=digitalio.Pull.DOWN)
# 初始化板载按键D2,按下接VCC
button2 = digitalio.DigitalInOut(board.D2)
button2.switch_to_input(pull=digitalio.Pull.DOWN)

2、LED指示灯代码

# 初始化板载LED
led0 = digitalio.DigitalInOut(board.LED)
# led0 = digitalio.DigitalInOut(board.D13)
led0.direction = digitalio.Direction.OUTPUT
led0.value = True

3、TCS3200驱动代码

class TCS3200:
    NUM_CYCLES = 100  # 测试多少个周期

    def __init__(self, s0_pin, s1_pin, s2_pin, s3_pin, out_pin):
        # 初始化控制引脚
        self.s0 = digitalio.DigitalInOut(s0_pin)
        self.s1 = digitalio.DigitalInOut(s1_pin)
        self.s2 = digitalio.DigitalInOut(s2_pin)
        self.s3 = digitalio.DigitalInOut(s3_pin)
        self.out = digitalio.DigitalInOut(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_scaling(100)
        # 白平衡校准系数 (初始值为1,需要实际校准)
        self.r_scal = 1.0
        self.g_scal = 1.0
        self.b_scal = 1.0

        print("TCS3200传感器初始化完成")

    def set_frequency_scaling(self, scaling):
        """
        设置传感器的频率缩放比例
        # s0  s1
        # L   L   关闭
        # L   H   2%
        # H   L   20%
        # H   H   100%
        """
        if scaling == 2:       # 2%
            self.s0.value = False
            self.s1.value = True
            # print("TCS3200传感器设置频率缩放比为:%2 -> s0,s1[0,1]")
        elif scaling == 20:    # 20%
            self.s0.value = True
            self.s1.value = False
            # print("TCS3200传感器设置频率缩放比为:%20 -> s0,s1[1,0]")
        elif scaling == 100:   # 100%
            self.s0.value = True
            self.s1.value = True
            # print("TCS3200传感器设置频率缩放比为:%100 -> s0,s1[1,1]")
        else:                  # 关闭
            self.s0.value = False
            self.s1.value = False
            # print("TCS3200传感器设置频率缩放比为:%0 -> s0,s1[0,0]")

        time.sleep(0.01)       # 短暂延时稳定频率缩放比例

    def set_color_filter(self, filter_type):
        """
        设置传感器的颜色滤波器
        # s2  s3
        # L   L   Red
        # H   H   Green
        # L   H   Blue
        # H   L   Clear(no filter)
        """
        if filter_type == "Red":
            self.s2.value = False
            self.s3.value = False
            # print("TCS3200传感器设置颜色滤波器为:Red -> s2,s3[0,0]")
        elif filter_type == "Green":
            self.s2.value = True
            self.s3.value = True
            # print("TCS3200传感器设置颜色滤波器为:Green -> s2,s3[1,1]")
        elif filter_type == "Blue":
            self.s2.value = False
            self.s3.value = True
            # print("TCS3200传感器设置颜色滤波器为:Blue -> s2,s3[0,1]")
        else:  # "Clear"
            self.s2.value = True
            self.s3.value = False
            # print("TCS3200传感器设置颜色滤波器为:Clear -> s2,s3[1,0]")

        time.sleep(0.01)       # 短暂延时稳定滤波器

    def measure_frequency(self):
        # 测量频率,并转换单位为Hz
        timestamps = []
        last_state = self.out.value

        while len(timestamps) < self.NUM_CYCLES:
            current_state = self.out.value
            if current_state != last_state:  # 发生边缘变化
                timestamps.append(time.monotonic_ns())
                last_state = current_state

        # 计数周期
        periods = []
        for i in range(2, len(timestamps), 2):
            period_ns = timestamps[i] - timestamps[i - 2]  # 一个完整周期(两个边缘)
            periods.append(period_ns)

        avg_period_ns = sum(periods) / len(periods)
        frequency = 1000000000 / avg_period_ns  # 转换为 Hz
        # print(f"原始频率值 -> Frequency:{frequency:.3f}")

        return frequency

    def read_rgb_freq(self):
        # 读取RGB三个通道的频率值
        red_freq = 0
        green_freq = 0
        blue_freq = 0

        # 读取红色分量 (S2=0, S3=0)
        self.set_color_filter("Red")
        red_freq = self.measure_frequency()
        # 读取绿色分量 (S2=1, S3=1)
        self.set_color_filter("Green")
        green_freq = self.measure_frequency()
        # 读取蓝色分量 (S2=0, S3=1)
        self.set_color_filter("Blue")
        blue_freq = self.measure_frequency()

        # 清除绿色分量 (S2=1, S3=0)
        # self.set_color_filter("Clear")

        # print(f"原始频率值 -> R:{red_freq:.3f}, G:{green_freq:.3f}, B:{blue_freq:.3f}")

        return red_freq, green_freq, blue_freq

    def calibrate_white_balance(self):
        # 白平衡校准 - 将传感器对准白色参考物后调用此方法
        print("正在进行白平衡校准...")
        print("请将传感器对准白色参考物")

        # 读取白色参考物的原始频率
        red, green, blue = self.read_rgb_freq()

        # 换算为RGB值 (18000/255 = 70)
        red = red / 70 if red > 0 else 1.0
        green = green / 70 if green > 0 else 1.0
        blue = blue / 70 if blue > 0 else 1.0

        # 计算校准系数 (假设我们希望白色时RGB值接近255)
        self.r_scal = 255.0 / red if red > 0 else 1.0
        self.g_scal = 255.0 / green if green > 0 else 1.0
        self.b_scal = 255.0 / blue if blue > 0 else 1.0

        print(f"校准完成 -> R:{self.r_scal:.3f}, G:{self.g_scal:.3f}, B:{self.b_scal:.3f}")

    def read_rgb(self):
        # 读取RGB三个通道的频率值,应用白平衡,并转换为RGB
        r = 0
        g = 0
        b = 0

        # 读取RGB三个通道的频率值
        red_freq, green_freq, blue_freq = self.read_rgb_freq()

        # 应用白平衡校准 (18000/255 = 70)
        r = int(red_freq / 70 * self.r_scal)
        g = int(green_freq / 70 * self.g_scal)
        b = int(blue_freq / 70 * self.b_scal)

        # 限制在0-255范围
        r = max(0, min(255, r))
        g = max(0, min(255, g))
        b = max(0, min(255, b))

        return r, g, b

4、完整代码

import board
import digitalio
import time
import displayio
import terminalio
from adafruit_display_text import label

# 定义按键变量
Button0_Value = 0
Button1_Value = 0
Button2_Value = 0

class TCS3200:
    NUM_CYCLES = 10  # 测试多少个周期

    def __init__(self, s0_pin, s1_pin, s2_pin, s3_pin, out_pin):
        # 初始化控制引脚
        self.s0 = digitalio.DigitalInOut(s0_pin)
        self.s1 = digitalio.DigitalInOut(s1_pin)
        self.s2 = digitalio.DigitalInOut(s2_pin)
        self.s3 = digitalio.DigitalInOut(s3_pin)
        self.out = digitalio.DigitalInOut(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_scaling(100)
        # 白平衡校准系数 (初始值为1,需要实际校准)
        self.r_scal = 1.0
        self.g_scal = 1.0
        self.b_scal = 1.0

        print("TCS3200传感器初始化完成")

    def set_frequency_scaling(self, scaling):
        """
        设置传感器的频率缩放比例
        # s0  s1
        # L   L   关闭
        # L   H   2%
        # H   L   20%
        # H   H   100%
        """
        if scaling == 2:       # 2%
            self.s0.value = False
            self.s1.value = True
            # print("TCS3200传感器设置频率缩放比为:%2 -> s0,s1[0,1]")
        elif scaling == 20:    # 20%
            self.s0.value = True
            self.s1.value = False
            # print("TCS3200传感器设置频率缩放比为:%20 -> s0,s1[1,0]")
        elif scaling == 100:   # 100%
            self.s0.value = True
            self.s1.value = True
            # print("TCS3200传感器设置频率缩放比为:%100 -> s0,s1[1,1]")
        else:                  # 关闭
            self.s0.value = False
            self.s1.value = False
            # print("TCS3200传感器设置频率缩放比为:%0 -> s0,s1[0,0]")

        time.sleep(0.01)       # 短暂延时稳定频率缩放比例

    def set_color_filter(self, filter_type):
        """
        设置传感器的颜色滤波器
        # s2  s3
        # L   L   Red
        # H   H   Green
        # L   H   Blue
        # H   L   Clear(no filter)
        """
        if filter_type == "Red":
            self.s2.value = False
            self.s3.value = False
            # print("TCS3200传感器设置颜色滤波器为:Red -> s2,s3[0,0]")
        elif filter_type == "Green":
            self.s2.value = True
            self.s3.value = True
            # print("TCS3200传感器设置颜色滤波器为:Green -> s2,s3[1,1]")
        elif filter_type == "Blue":
            self.s2.value = False
            self.s3.value = True
            # print("TCS3200传感器设置颜色滤波器为:Blue -> s2,s3[0,1]")
        else:  # "Clear"
            self.s2.value = True
            self.s3.value = False
            # print("TCS3200传感器设置颜色滤波器为:Clear -> s2,s3[1,0]")

        time.sleep(0.01)       # 短暂延时稳定滤波器

    def measure_frequency(self):
        # 测量频率,并转换单位为Hz
        timestamps = []
        last_state = self.out.value

        while len(timestamps) < self.NUM_CYCLES:
            current_state = self.out.value
            if current_state != last_state:  # 发生边缘变化
                timestamps.append(time.monotonic_ns())
                last_state = current_state

        # 计数周期
        periods = []
        for i in range(2, len(timestamps), 2):
            period_ns = timestamps[i] - timestamps[i - 2]  # 一个完整周期(两个边缘)
            periods.append(period_ns)

        avg_period_ns = sum(periods) / len(periods)
        frequency = 1000000000 / avg_period_ns  # 转换为 Hz
        # print(f"原始频率值 -> Frequency:{frequency:.3f}")

        return frequency

    def read_rgb_freq(self):
        # 读取RGB三个通道的频率值
        red_freq = 0
        green_freq = 0
        blue_freq = 0

        # 读取红色分量 (S2=0, S3=0)
        self.set_color_filter("Red")
        red_freq = self.measure_frequency()
        # 读取绿色分量 (S2=1, S3=1)
        self.set_color_filter("Green")
        green_freq = self.measure_frequency()
        # 读取蓝色分量 (S2=0, S3=1)
        self.set_color_filter("Blue")
        blue_freq = self.measure_frequency()

        # 清除绿色分量 (S2=1, S3=0)
        # self.set_color_filter("Clear")

        # print(f"原始频率值 -> R:{red_freq:.3f}, G:{green_freq:.3f}, B:{blue_freq:.3f}")

        return red_freq, green_freq, blue_freq

    def calibrate_white_balance(self):
        # 白平衡校准 - 将传感器对准白色参考物后调用此方法
        print("正在进行白平衡校准...")
        print("请将传感器对准白色参考物")

        # 读取白色参考物的原始频率
        red, green, blue = self.read_rgb_freq()

        # 换算为RGB值 (18000/255 = 70)
        red = red / 70 if red > 0 else 1.0
        green = green / 70 if green > 0 else 1.0
        blue = blue / 70 if blue > 0 else 1.0

        # 计算校准系数 (假设我们希望白色时RGB值接近255)
        self.r_scal = 255.0 / red if red > 0 else 1.0
        self.g_scal = 255.0 / green if green > 0 else 1.0
        self.b_scal = 255.0 / blue if blue > 0 else 1.0

        print(f"校准完成 -> R:{self.r_scal:.3f}, G:{self.g_scal:.3f}, B:{self.b_scal:.3f}")

    def read_rgb(self):
        # 读取RGB三个通道的频率值,应用白平衡,并转换为RGB
        r = 0
        g = 0
        b = 0

        # 读取RGB三个通道的频率值
        red_freq, green_freq, blue_freq = self.read_rgb_freq()

        # 应用白平衡校准 (18000/255 = 70)
        r = int(red_freq / 70 * self.r_scal)
        g = int(green_freq / 70 * self.g_scal)
        b = int(blue_freq / 70 * self.b_scal)

        # 限制在0-255范围
        r = max(0, min(255, r))
        g = max(0, min(255, g))
        b = max(0, min(255, b))

        return r, g, b


# 初始化板载按键D0/BOOT0,按下接地
button0 = digitalio.DigitalInOut(board.BUTTON)
button0.switch_to_input(pull=digitalio.Pull.UP)
# 初始化板载按键D1,按下接VCC
button1 = digitalio.DigitalInOut(board.D1)
button1.switch_to_input(pull=digitalio.Pull.DOWN)
# 初始化板载按键D2,按下接VCC
button2 = digitalio.DigitalInOut(board.D2)
button2.switch_to_input(pull=digitalio.Pull.DOWN)

# 初始化板载LED
led0 = digitalio.DigitalInOut(board.LED)
# led0 = digitalio.DigitalInOut(board.D13)
led0.direction = digitalio.Direction.OUTPUT
led0.value = True

# 初始化颜色传感器LED补光灯
led1 = digitalio.DigitalInOut(board.D5)
led1.direction = digitalio.Direction.OUTPUT
led1.value = True

# 初始化显示屏
display = board.DISPLAY
# 创建显示组
splash = displayio.Group()
display.root_group = splash

# 创建DIY活动文本标签
textdo = "Let's do - EEPW DIY"
text_area_do = label.Label(terminalio.FONT, text=textdo, color=0xFFFF00, x=60, y=20)

# 创建文本标签用于显示RGB值
text_area_r = label.Label(terminalio.FONT, text="R: ---", color=0xFF0000, x=10, y=50)
text_area_g = label.Label(terminalio.FONT, text="G: ---", color=0x00FF00, x=10, y=70)
text_area_b = label.Label(terminalio.FONT, text="B: ---", color=0x0000FF, x=10, y=90)
text_area_h = label.Label(terminalio.FONT, text="#------", color=0xFFFFFF, x=10, y=120)

# 显示输出
for text_area in (text_area_do, text_area_r, text_area_g, text_area_b, text_area_h):
    splash.append(text_area)

# 创建TCS3200颜色传感器实体
try:
    # 创建TCS3200对象
    color_sensor = TCS3200(
        s0_pin=board.D12,
        s1_pin=board.D11,
        s2_pin=board.D10,
        s3_pin=board.D9,
        out_pin=board.D6
    )
    print("TCS3200实例创建成功")
except Exception as e:
    print(f"初始化TCS3200失败: {e}")
    # 创建虚拟传感器用于测试
    color_sensor = None

# 主循环
while True:
    led0.value = True
    time.sleep(0.05)

    # 读取按键0
    if not button0.value:
        print("button0按下")
        Button0_Value = 1
        Button1_Value = 0
        Button2_Value = 0
    # 读取按键1
    if button1.value:
        print("button1按下")
        Button0_Value = 0
        Button1_Value = 1
        Button2_Value = 0
    # 读取按键2
    if button2.value:
        print("button2按下")
        Button0_Value = 0
        Button1_Value = 0
        Button2_Value = 1

    if Button0_Value:
        Button0_Value = 0
        # 调用白平衡校准
        color_sensor.calibrate_white_balance()
        # 更新显示
        text_area_r.text = "R: {:.3f}".format(color_sensor.r_scal)
        text_area_g.text = "G: {:.3f}".format(color_sensor.g_scal)
        text_area_b.text = "B: {:.3f}".format(color_sensor.b_scal)
        text_area_h.text = "#------"

    if Button1_Value:
        # 读取并显示TCS3200颜色传感器的频率值
        if color_sensor is not None:
            try:
                # 调用read_rgb_freq方法读取频率值
                R_Val, G_Val, B_Val = color_sensor.read_rgb_freq()

                # 更新显示
                text_area_r.text = "R: {:.3f}".format(R_Val)
                text_area_g.text = "G: {:.3f}".format(G_Val)
                text_area_b.text = "B: {:.3f}".format(B_Val)
                text_area_h.text = "#: {:.3f},{:.3f},{:.3f}".format(R_Val, G_Val, B_Val)

                print("RGB: {:.3f},{:.3f},{:.3f}".format(R_Val, G_Val, B_Val))

            except Exception as e:
                print(f"读取颜色传感器错误: {e}")
                R_Val = 128
                G_Val = 128
                B_Val = 128

        else:
            # 更新显示屏
            text_area_r.text = "R: {:.3f}".format(R_Val)
            text_area_g.text = "G: {:.3f}".format(G_Val)
            text_area_b.text = "B: {:.3f}".format(B_Val)
            text_area_h.text = "#: {:.3f},{:.3f},{:.3f}".format(R_Val, G_Val, B_Val)

    if Button2_Value:
        # 读取并显示TCS3200颜色传感器的RGB值
        if color_sensor is not None:
            try:
                # 调用read_rgb方法读取颜色值
                R_Val, G_Val, B_Val = color_sensor.read_rgb()

                # 更新显示
                text_area_r.text = "R: {:3d}".format(R_Val)
                text_area_g.text = "G: {:3d}".format(G_Val)
                text_area_b.text = "B: {:3d}".format(B_Val)
                text_area_h.text = "#: {:02X}{:02X}{:02X}".format(R_Val, G_Val, B_Val)

                print("RGB: #{:02X}{:02X}{:02X}".format(R_Val, G_Val, B_Val))

            except Exception as e:
                print(f"读取颜色传感器错误: {e}")
                R_Val = 128
                G_Val = 128
                B_Val = 128

        else:
            # 更新显示屏
            text_area_r.text = "R: {:3d}".format(R_Val)
            text_area_g.text = "G: {:3d}".format(G_Val)
            text_area_b.text = "B: {:3d}".format(B_Val)
            text_area_h.text = "#: {:02X}{:02X}{:02X}".format(R_Val, G_Val, B_Val)

    led0.value = False
    time.sleep(0.05)

四、实例测试

1、开机界面

image.png

2、按键D0校准

image.png

3、频率值显示

image.png

4、RGB值显示

image.png

5、颜色数值显示

image.png

image.png

image.png

6、颜色RGB显示

image.png

image.png

image.png


推荐技术

返回顶部