【CanMV K210】基础实验 RGB LED 三色混光与状态灯封装

在智能硬件项目中,RGB LED 经常承担"状态表达"的角色。单色 LED 只能表达亮和灭,而 RGB LED 可以通过红、绿、蓝三路光的混合,表达更多设备状态。例如白色短亮可以表示设备启动,蓝色呼吸可以表示待机,绿色闪烁可以表示任务完成,红色长闪可以表示错误,橙色闪烁可以表示普通警告。

本实验基于 CanMV K210 使用 PWM 控制 RGB 三色 LED。程序将物理引脚 6、7、8 分别作为红色、绿色、蓝色通道,通过三个 PWM 对象输出不同占空比,让 RGB LED 显示指定颜色。代码支持 RGB 元组设置、十六进制颜色设置、全局亮度缩放、平滑渐变、呼吸灯、警告闪烁、成功提示、错误提示和设备状态演示。这个实验不只是让灯变颜色,而是把颜色当成智能硬件的人机反馈语言。

学习目标 说明
理解 PWM 控制 认识 PWM 占空比如何影响 LED 亮度
掌握 RGB 混色 通过红、绿、蓝三路亮度组合显示不同颜色
学会亮度缩放 使用全局亮度参数控制整体亮度,避免灯光过亮
理解灯效封装 将渐变、呼吸、闪烁和状态提示封装成可复用函数
建立状态灯思维 使用不同颜色和闪烁节奏表达设备运行状态

文章目录

理论基础

RGB LED 可以理解成把红色 LED、绿色 LED 和蓝色 LED 封装在一起的发光器件。程序分别控制 R、G、B 三个通道的亮度,就可以混合出不同颜色。红色通道亮度高时显示偏红,绿色通道亮度高时显示偏绿,蓝色通道亮度高时显示偏蓝;红色和绿色同时亮起可以形成黄色,绿色和蓝色同时亮起可以形成青色,红色和蓝色同时亮起可以形成紫色,三路同时亮起可以形成白色。

普通 GPIO 输出只有高电平和低电平,适合控制 LED 亮灭,但不适合控制亮度变化。PWM 的作用就是通过快速开关输出形成不同占空比,让 LED 看起来具有不同亮度。占空比越高,对应通道越亮;占空比越低,对应通道越暗。本实验中的 rgb_to_duty() 函数,就是把 0~255 的颜色值转换成 0~100 的 PWM 占空比。

RGB LED 常见结构包括共阴极和共阳极。共阴极 RGB LED 通常是数值越大越亮,三路颜色通道输出较高占空比时,对应颜色增强。共阳极 RGB LED 的亮灭逻辑相反,数值越大不一定越亮。代码中通过 COMMON_ANODE 参数适配这两类模块,默认按共阴极方式处理。如果实际现象出现颜色反向、熄灭异常或亮灭逻辑不符合预期,可以修改这个参数。

下面的流程图从电路控制角度展示整个实验链路。程序并不是直接"设置颜色",而是先把颜色值拆成 R、G、B 三路亮度,再转换成 PWM 占空比,最后由三个引脚分别控制 RGB LED 的三个颜色通道。
#mermaid-svg-YkcOAqKJVXpchYCh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YkcOAqKJVXpchYCh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YkcOAqKJVXpchYCh .error-icon{fill:#552222;}#mermaid-svg-YkcOAqKJVXpchYCh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YkcOAqKJVXpchYCh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YkcOAqKJVXpchYCh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YkcOAqKJVXpchYCh .marker.cross{stroke:#333333;}#mermaid-svg-YkcOAqKJVXpchYCh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YkcOAqKJVXpchYCh p{margin:0;}#mermaid-svg-YkcOAqKJVXpchYCh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YkcOAqKJVXpchYCh .cluster-label text{fill:#333;}#mermaid-svg-YkcOAqKJVXpchYCh .cluster-label span{color:#333;}#mermaid-svg-YkcOAqKJVXpchYCh .cluster-label span p{background-color:transparent;}#mermaid-svg-YkcOAqKJVXpchYCh .label text,#mermaid-svg-YkcOAqKJVXpchYCh span{fill:#333;color:#333;}#mermaid-svg-YkcOAqKJVXpchYCh .node rect,#mermaid-svg-YkcOAqKJVXpchYCh .node circle,#mermaid-svg-YkcOAqKJVXpchYCh .node ellipse,#mermaid-svg-YkcOAqKJVXpchYCh .node polygon,#mermaid-svg-YkcOAqKJVXpchYCh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YkcOAqKJVXpchYCh .rough-node .label text,#mermaid-svg-YkcOAqKJVXpchYCh .node .label text,#mermaid-svg-YkcOAqKJVXpchYCh .image-shape .label,#mermaid-svg-YkcOAqKJVXpchYCh .icon-shape .label{text-anchor:middle;}#mermaid-svg-YkcOAqKJVXpchYCh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YkcOAqKJVXpchYCh .rough-node .label,#mermaid-svg-YkcOAqKJVXpchYCh .node .label,#mermaid-svg-YkcOAqKJVXpchYCh .image-shape .label,#mermaid-svg-YkcOAqKJVXpchYCh .icon-shape .label{text-align:center;}#mermaid-svg-YkcOAqKJVXpchYCh .node.clickable{cursor:pointer;}#mermaid-svg-YkcOAqKJVXpchYCh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YkcOAqKJVXpchYCh .arrowheadPath{fill:#333333;}#mermaid-svg-YkcOAqKJVXpchYCh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YkcOAqKJVXpchYCh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YkcOAqKJVXpchYCh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YkcOAqKJVXpchYCh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YkcOAqKJVXpchYCh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YkcOAqKJVXpchYCh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YkcOAqKJVXpchYCh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YkcOAqKJVXpchYCh .cluster text{fill:#333;}#mermaid-svg-YkcOAqKJVXpchYCh .cluster span{color:#333;}#mermaid-svg-YkcOAqKJVXpchYCh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YkcOAqKJVXpchYCh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YkcOAqKJVXpchYCh rect.text{fill:none;stroke-width:0;}#mermaid-svg-YkcOAqKJVXpchYCh .icon-shape,#mermaid-svg-YkcOAqKJVXpchYCh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YkcOAqKJVXpchYCh .icon-shape p,#mermaid-svg-YkcOAqKJVXpchYCh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YkcOAqKJVXpchYCh .icon-shape .label rect,#mermaid-svg-YkcOAqKJVXpchYCh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YkcOAqKJVXpchYCh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YkcOAqKJVXpchYCh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YkcOAqKJVXpchYCh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-YkcOAqKJVXpchYCh .code>*{fill:#E8F3FF!important;stroke:#5B9BFF!important;stroke-width:2px!important;color:#1F3B6D!important;}#mermaid-svg-YkcOAqKJVXpchYCh .code span{fill:#E8F3FF!important;stroke:#5B9BFF!important;stroke-width:2px!important;color:#1F3B6D!important;}#mermaid-svg-YkcOAqKJVXpchYCh .code tspan{fill:#1F3B6D!important;}#mermaid-svg-YkcOAqKJVXpchYCh .pwm>*{fill:#EAFBF1!important;stroke:#42B983!important;stroke-width:2px!important;color:#1F5C3A!important;}#mermaid-svg-YkcOAqKJVXpchYCh .pwm span{fill:#EAFBF1!important;stroke:#42B983!important;stroke-width:2px!important;color:#1F5C3A!important;}#mermaid-svg-YkcOAqKJVXpchYCh .pwm tspan{fill:#1F5C3A!important;}#mermaid-svg-YkcOAqKJVXpchYCh .led>*{fill:#FFF4E8!important;stroke:#F4A261!important;stroke-width:2px!important;color:#7A4A00!important;}#mermaid-svg-YkcOAqKJVXpchYCh .led span{fill:#FFF4E8!important;stroke:#F4A261!important;stroke-width:2px!important;color:#7A4A00!important;}#mermaid-svg-YkcOAqKJVXpchYCh .led tspan{fill:#7A4A00!important;}#mermaid-svg-YkcOAqKJVXpchYCh .config>*{fill:#FCEEF4!important;stroke:#E76F51!important;stroke-width:2px!important;color:#7A2740!important;}#mermaid-svg-YkcOAqKJVXpchYCh .config span{fill:#FCEEF4!important;stroke:#E76F51!important;stroke-width:2px!important;color:#7A2740!important;}#mermaid-svg-YkcOAqKJVXpchYCh .config tspan{fill:#7A2740!important;} 颜色指令

RGB 元组 / HEX 颜色 / 状态灯函数
颜色解析

R / G / B 三路数值
亮度缩放

BRIGHTNESS 全局亮度
PWM 占空比转换

rgb_to_duty()
CanMV K210

物理引脚 6 / 7 / 8
RGB LED

红色 / 绿色 / 蓝色通道
灯光效果

混色 / 渐变 / 呼吸 / 闪烁 / 状态提示
COMMON_ANODE

共阳极适配
Timer + PWM

定时器与 PWM 输出

从这条链路可以看出,RGB LED 实验不只是普通亮灯实验的升级版。它同时涉及 PWM 输出、颜色值换算、亮度比例控制、灯效节奏设计和设备状态映射。后续做联网状态灯、AI 识别结果提示、传感器阈值报警、设备运行反馈时,都可以复用这种思路。

硬件设施

本实验真正使用到的硬件对象是 CanMV K210 开发板和一个 RGB LED。软件侧主要使用 machine.Timermachine.PWMtime。代码没有使用 LCD、按键、蜂鸣器、摄像头或传感器,因此这些模块不作为本节重点。RGB LED 的核心控制方式是 PWM,程序通过不同通道的占空比控制红、绿、蓝三种颜色的亮度,再由三色混合形成不同颜色效果。

接线关系可以先通过下面这张图建立整体印象。CanMV K210 使用物理引脚 6、7、8 分别连接 RGB LED 的红色、绿色、蓝色通道,公共端需要根据 RGB LED 类型连接到对应电源或地线。如果使用的是裸 RGB LED,建议给每个颜色通道串联合适的限流电阻;如果使用的是 RGB LED 模块,通常模块板上已经集成限流电阻。

硬件 / 软件 作用 说明
CanMV K210 开发板 实验运行平台 负责执行 MicroPython 程序,并通过 PWM 输出控制 RGB LED
RGB LED 彩色显示对象 通过红、绿、蓝三路通道混合显示不同颜色
物理引脚 6 红色通道输出 对应 RED_PIN,用于控制 RGB LED 的红色亮度
物理引脚 7 绿色通道输出 对应 GREEN_PIN,用于控制 RGB LED 的绿色亮度
物理引脚 8 蓝色通道输出 对应 BLUE_PIN,用于控制 RGB LED 的蓝色亮度
machine.Timer PWM 定时器资源 为 PWM 输出提供定时器和通道配置
machine.PWM PWM 控制模块 通过频率和占空比控制每个颜色通道的输出强度
time 延时控制模块 通过 time.sleep_ms() 控制颜色保持、闪烁和渐变速度

实验中使用的 RGB LED 模块如下。接线时需要重点确认 R、G、B 三个颜色输入端和公共端,不同模块的引脚排列可能不同,不能只根据线的颜色判断通道。若红色、绿色、蓝色显示顺序和程序不一致,优先检查接线顺序,再考虑修改代码中的 RED_PINGREEN_PINBLUE_PIN

物理引脚 PWM 对象 代码变量 对应硬件 说明
6 pwm_r RED_PIN RGB LED 红色通道 负责控制红色亮度
7 pwm_g GREEN_PIN RGB LED 绿色通道 负责控制绿色亮度
8 pwm_b BLUE_PIN RGB LED 蓝色通道 负责控制蓝色亮度
公共端 COMMON_ANODE 相关 RGB LED 公共引脚 共阴极接 GND,共阳极接 VCC,具体以模块标识为准

完成接线后的整体状态如下。检查时重点关注三个位置:RGB LED 的 R/G/B 通道是否接到代码指定引脚,公共端连接方式是否和模块类型一致,程序中的 COMMON_ANODE 是否匹配实际 RGB LED 类型。接线正确后,程序运行会依次出现颜色轮播、平滑渐变、呼吸灯和状态灯演示效果。

实验现象 正常表现 异常提示
基础颜色轮播 红、绿、蓝、黄、紫、青、白依次显示 颜色顺序错误时检查 R/G/B 接线
平滑颜色渐变 不同颜色之间逐步过渡 渐变突兀时可增加 steps 或减小 delay_ms
RGB 呼吸灯 指定颜色由暗变亮,再由亮变暗 亮度异常时检查 BRIGHTNESSCOMMON_ANODE
设备启动提示 白色短亮 不亮时检查公共端和 PWM 引脚
待机状态提示 蓝色呼吸 颜色不对时检查蓝色通道接线
运行状态提示 蓝色和青色之间平滑变化 绿色或蓝色通道异常会导致颜色偏差
警告与错误提示 橙色或红色闪烁 红色通道异常会影响警告显示

软件代码

本实验代码围绕 RGB LED 的 PWM 控制展开。程序先定义红、绿、蓝三个物理引脚,再创建三个 PWM 输出对象。后续所有颜色显示、渐变、呼吸灯和状态提示,都基于 set_rgb() 统一控制三路颜色通道。代码还增加了亮度缩放和共阳极适配变量,便于在不同 RGB LED 模块之间调整。

软件环境 作用 检查重点
CanMV IDE 编辑、运行和调试 K210 程序 能识别开发板串口,并能正常运行基础程序
CanMV 固件 提供 machine.Timermachine.PWM 固件环境需要支持当前 PWM 写法
USB 串口驱动 让电脑识别开发板串口 串口终端能看到状态打印信息
machine.Timer 创建 PWM 所需定时器资源 三个颜色通道分别绑定到不同通道
machine.PWM 输出 PWM 波形 通过 duty() 修改 RGB LED 亮度
time 控制灯效节奏 控制颜色保持、闪烁间隔和渐变速度
python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
CanMV K210 RGB-LED 实验 Demo

功能:
1. 使用 PWM 控制 RGB 三色 LED
2. 支持 HEX 颜色、RGB 颜色两种设置方式
3. 支持亮度缩放,避免灯光过亮
4. 支持颜色切换、渐变过渡、呼吸灯、警告闪烁、设备状态灯
5. 通过不同颜色表达智能硬件状态
"""

from machine import Timer, PWM
import time


# =========================
# 硬件配置区
# =========================

RED_PIN = 6
GREEN_PIN = 7
BLUE_PIN = 8

PWM_FREQ = 2000          # PWM 频率
BRIGHTNESS = 0.35        # 全局亮度,范围 0.0 ~ 1.0

# 大多数普通 RGB LED 为共阴极:数值越大越亮
# 若实际现象为颜色反向或熄灭异常,可改为 True
COMMON_ANODE = False


# =========================
# PWM 初始化
# =========================

timer_r = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
timer_g = Timer(Timer.TIMER0, Timer.CHANNEL1, mode=Timer.MODE_PWM)
timer_b = Timer(Timer.TIMER0, Timer.CHANNEL2, mode=Timer.MODE_PWM)

pwm_r = PWM(timer_r, freq=PWM_FREQ, duty=0, pin=RED_PIN)
pwm_g = PWM(timer_g, freq=PWM_FREQ, duty=0, pin=GREEN_PIN)
pwm_b = PWM(timer_b, freq=PWM_FREQ, duty=0, pin=BLUE_PIN)


# =========================
# 常用颜色定义
# =========================

BLACK   = (0, 0, 0)
RED     = (255, 0, 0)
GREEN   = (0, 255, 0)
BLUE    = (0, 0, 255)
YELLOW  = (255, 255, 0)
CYAN    = (0, 255, 255)
PURPLE  = (255, 0, 255)
WHITE   = (255, 255, 255)
ORANGE  = (255, 80, 0)

COLOR_LIST = [
    RED,
    GREEN,
    BLUE,
    YELLOW,
    PURPLE,
    CYAN,
    WHITE
]


# =========================
# 工具函数
# =========================

def clamp(value, min_value=0, max_value=255):
    """限制数值范围"""
    if value < min_value:
        return min_value
    if value > max_value:
        return max_value
    return value


def rgb_to_duty(value):
    """
    将 0~255 的颜色值转换为 0~100 的 PWM 占空比
    """
    value = clamp(value)
    duty = int(value / 255 * 100 * BRIGHTNESS)

    if COMMON_ANODE:
        duty = 100 - duty

    return duty


def hex_to_rgb(color):
    """
    将 0xRRGGBB 颜色转换为 RGB 元组
    """
    r = (color & 0xFF0000) >> 16
    g = (color & 0x00FF00) >> 8
    b = color & 0x0000FF
    return r, g, b


# =========================
# 基础控制函数
# =========================

def set_rgb(r, g, b):
    """
    设置 RGB LED 颜色
    """
    pwm_r.duty(rgb_to_duty(r))
    pwm_g.duty(rgb_to_duty(g))
    pwm_b.duty(rgb_to_duty(b))


def set_hex_color(color):
    """
    通过十六进制颜色设置 RGB LED
    示例:set_hex_color(0xFF0000)
    """
    r, g, b = hex_to_rgb(color)
    set_rgb(r, g, b)


def led_off():
    """
    关闭 RGB LED
    """
    set_rgb(0, 0, 0)


def show_color(color, delay_ms=800):
    """
    显示指定颜色一段时间
    """
    r, g, b = color
    set_rgb(r, g, b)
    time.sleep_ms(delay_ms)


# =========================
# 灯效函数
# =========================

def color_cycle(delay_ms=700):
    """
    基础颜色轮播
    """
    for color in COLOR_LIST:
        show_color(color, delay_ms)


def fade_to_color(start_color, end_color, steps=40, delay_ms=20):
    """
    从一种颜色平滑渐变到另一种颜色
    """
    start_r, start_g, start_b = start_color
    end_r, end_g, end_b = end_color

    for i in range(steps + 1):
        r = int(start_r + (end_r - start_r) * i / steps)
        g = int(start_g + (end_g - start_g) * i / steps)
        b = int(start_b + (end_b - start_b) * i / steps)

        set_rgb(r, g, b)
        time.sleep_ms(delay_ms)


def smooth_color_cycle():
    """
    平滑颜色渐变轮播
    """
    colors = [RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, RED]

    for i in range(len(colors) - 1):
        fade_to_color(colors[i], colors[i + 1], steps=45, delay_ms=18)


def breathing_light(color=BLUE, cycles=3):
    """
    单色呼吸灯
    """
    global BRIGHTNESS

    old_brightness = BRIGHTNESS
    r, g, b = color

    for _ in range(cycles):
        for level in range(0, 101, 4):
            BRIGHTNESS = level / 100 * old_brightness
            set_rgb(r, g, b)
            time.sleep_ms(25)

        for level in range(100, -1, -4):
            BRIGHTNESS = level / 100 * old_brightness
            set_rgb(r, g, b)
            time.sleep_ms(25)

    BRIGHTNESS = old_brightness
    led_off()


def blink_color(color, times=3, on_ms=180, off_ms=180):
    """
    指定颜色闪烁
    """
    r, g, b = color

    for _ in range(times):
        set_rgb(r, g, b)
        time.sleep_ms(on_ms)

        led_off()
        time.sleep_ms(off_ms)


def warning_flash():
    """
    警告闪烁:红色快速闪烁
    """
    blink_color(RED, times=6, on_ms=120, off_ms=120)


def success_flash():
    """
    成功提示:绿色闪烁
    """
    blink_color(GREEN, times=2, on_ms=200, off_ms=160)


def error_flash():
    """
    错误提示:红色长闪
    """
    blink_color(RED, times=3, on_ms=450, off_ms=200)


def standby_light():
    """
    待机状态:蓝色呼吸灯
    """
    breathing_light(BLUE, cycles=2)


def running_light():
    """
    运行状态:青色平滑渐变
    """
    fade_to_color(BLUE, CYAN, steps=35, delay_ms=18)
    fade_to_color(CYAN, BLUE, steps=35, delay_ms=18)


def device_status_demo():
    """
    智能硬件状态灯演示
    """
    print("设备启动:白色短亮")
    show_color(WHITE, 500)
    led_off()
    time.sleep_ms(300)

    print("待机状态:蓝色呼吸")
    standby_light()

    print("运行状态:蓝青渐变")
    running_light()

    print("任务完成:绿色提示")
    success_flash()

    print("普通警告:橙色提示")
    blink_color(ORANGE, times=4, on_ms=150, off_ms=150)

    print("错误状态:红色提示")
    error_flash()


# =========================
# 主循环
# =========================

def loop():
    while True:
        print("基础颜色轮播")
        color_cycle()

        print("平滑颜色渐变")
        smooth_color_cycle()

        print("RGB 呼吸灯")
        breathing_light(PURPLE, cycles=2)

        print("智能硬件状态演示")
        device_status_demo()

        print("演示结束,暂停 2 秒")
        led_off()
        time.sleep_ms(2000)


# =========================
# 程序入口
# =========================

if __name__ == "__main__":
    try:
        loop()
    except KeyboardInterrupt:
        led_off()
        print("程序已停止,RGB LED 已关闭")

这段程序可以分成三个层级。底层是 PWM 初始化和占空比转换,负责把颜色值变成真实的 PWM 输出;中间层是 set_rgb()set_hex_color()led_off()show_color(),负责提供统一的颜色控制接口;上层是颜色轮播、渐变、呼吸灯、闪烁提示和设备状态演示,负责把灯光变化变成可理解的设备反馈。

硬件配置区集中管理 RED_PINGREEN_PINBLUE_PINPWM_FREQBRIGHTNESSCOMMON_ANODE。后续更换接线、调节亮度或适配共阳极 RGB LED 时,只需要修改配置区,不需要进入每个灯效函数中逐个查找。set_rgb() 是最核心的接口,后面的颜色轮播、渐变、呼吸和状态灯都围绕它展开。

函数名 功能 对应现象
clamp() 限制颜色数值范围 防止 RGB 数值超出 0~255 导致占空比异常
rgb_to_duty() 将 RGB 颜色值转换为 PWM 占空比 控制单个颜色通道的实际亮度
hex_to_rgb() 将十六进制颜色拆成 RGB 元组 支持 0xRRGGBB 方式设置颜色
set_rgb() 设置 RGB LED 三路颜色值 RGB LED 显示指定混合颜色
set_hex_color() 使用十六进制颜色设置 LED 通过 0xFF0000 这类颜色值控制灯光
led_off() 关闭 RGB LED 三路颜色通道全部熄灭
show_color() 显示指定颜色并保持一段时间 LED 固定显示某种颜色
color_cycle() 基础颜色轮播 红、绿、蓝、黄、紫、青、白依次显示
fade_to_color() 两种颜色之间平滑过渡 LED 从一种颜色逐步渐变到另一种颜色
smooth_color_cycle() 多色平滑渐变轮播 RGB LED 在多种颜色之间连续过渡
breathing_light() 单色呼吸灯 指定颜色由暗变亮,再由亮变暗
blink_color() 指定颜色闪烁 LED 按设置次数和时间间隔闪烁
warning_flash() 警告闪烁 红色快速闪烁,模拟警告提示
success_flash() 成功提示 绿色短闪,模拟任务完成反馈
error_flash() 错误提示 红色长闪,模拟错误状态反馈
standby_light() 待机状态灯 蓝色呼吸,表达设备处于待机状态
running_light() 运行状态灯 蓝色与青色之间平滑渐变
device_status_demo() 智能硬件状态灯演示 用不同颜色和节奏表达启动、待机、运行、完成、警告、错误
loop() 主循环调度 持续播放颜色轮播、渐变、呼吸灯和状态灯演示

device_status_demo() 更接近真实项目中的状态灯逻辑。设备启动时白色短亮,待机时蓝色呼吸,运行时蓝青渐变,任务完成时绿色闪烁,普通警告时橙色闪烁,错误状态时红色长闪。这里的重点不是颜色本身,而是将程序状态映射成灯光语言。后续只要把真实设备状态变量接入这些函数,就可以把 RGB LED 变成简单但有效的人机反馈模块。

扩展应用

RGB LED 实验常见问题主要集中在颜色不对、亮度异常、灯不亮、闪烁不稳定和共阴共阳接反等方面。排查时应围绕引脚接线、PWM 输出、占空比转换和 LED 类型逐步确认,不需要扩展到当前代码没有使用的模块。

问题现象 可能原因 处理思路
RGB LED 完全不亮 开发板供电异常、程序没有运行、引脚接线错误、公共端未连接 检查程序是否启动,确认 RGB LED 公共端和 R/G/B 三路是否正确连接
显示颜色与代码不一致 红、绿、蓝通道接线顺序错误 运行 color_cycle() 观察红绿蓝是否对应,必要时调整 RED_PINGREEN_PINBLUE_PIN 或实际接线
颜色亮灭逻辑反了 RGB LED 模块可能是共阳极结构 COMMON_ANODE = False 改成 COMMON_ANODE = True 后重新运行
灯光太亮刺眼 BRIGHTNESS 参数过高 降低全局亮度,例如从 0.35 调整为 0.2
渐变不够平滑 steps 太少或 delay_ms 太大 增加渐变步数,适当减小每一步延时
呼吸灯亮度没有恢复 程序异常中断在亮度变化过程中 重新运行程序,或在中断后重新设置 BRIGHTNESS
某一种颜色始终不亮 对应颜色通道接线异常、LED 管脚损坏或 PWM 引脚不匹配 单独执行 set_rgb(255, 0, 0)set_rgb(0, 255, 0)set_rgb(0, 0, 255) 定位异常通道
串口打印正常但灯效没有变化 PWM 引脚与实际连接不一致 根据硬件连接重新修改 RED_PINGREEN_PINBLUE_PIN
灯光闪烁异常 接线松动、公共端连接不稳定或模块供电不足 重新检查公共端、供电和三路颜色通道连接

RGB LED 的价值在于用很少的硬件资源表达丰富状态。相比单色 LED,RGB LED 不仅能亮灭,还能用颜色、闪烁频率、渐变节奏和呼吸效果表达不同含义。当前代码已经把颜色设置、渐变、闪烁、呼吸和状态演示封装成函数,后续只需要根据设备状态调用不同函数,就能把 RGB LED 变成智能硬件的状态提示窗口。

应用场景 实现思路 可扩展能力
设备启动提示 启动时调用 show_color(WHITE, 500),用白色短亮表示系统开始运行 可结合开机自检结果显示不同启动状态
待机状态显示 使用 standby_light() 让蓝色灯光持续呼吸 可扩展为低功耗待机、等待联网、等待任务输入等状态
任务运行反馈 使用 running_light() 在蓝色和青色之间渐变 可根据任务进度改变渐变速度或颜色范围
任务完成提示 调用 success_flash() 让绿色短闪 可用于拍照完成、识别完成、上传完成等场景
异常报警提示 使用 error_flash()warning_flash() 表示错误和警告 后续可扩展蜂鸣器,实现声光报警
教学演示实验 通过颜色变化观察 PWM、占空比、RGB 混色和函数封装 可把抽象参数变化转化为可见灯光效果
智能硬件状态灯 使用 device_status_demo() 建立颜色与设备状态的对应关系 可接入传感器、摄像头识别结果或网络状态变量
氛围灯效果 使用 smooth_color_cycle() 进行平滑颜色轮播 可扩展更多颜色表和自定义主题色

从工程角度看,这段代码已经具备较好的复用性。引脚、频率、亮度和共阳极配置集中在硬件配置区,颜色定义集中在常量区,底层 PWM 控制统一封装到 set_rgb(),业务层状态提示则由 device_status_demo() 组织。后续增加更多状态时,不需要重新理解 PWM 初始化,只需要新增颜色函数或在状态演示函数中增加调用逻辑。这样的结构适合继续扩展为按键切换灯效、传感器阈值报警、AI 摄像头识别状态提示或网络连接状态显示。

总结

本实验通过 CanMV K210 使用 PWM 控制 RGB LED,完成了三色通道控制、RGB 颜色混合、HEX 颜色解析、亮度缩放、共阳极适配、颜色渐变、呼吸灯和设备状态灯封装。代码从三个颜色通道出发,把硬件层面的 PWM 占空比转换成可观察的颜色变化,再通过函数封装形成更接近真实项目的状态提示逻辑。

RGB LED 实验很适合作为硬件编程进阶案例。普通 GPIO 只能表达高低电平,而 PWM 可以表达连续变化的亮度;单色 LED 只能表达亮灭,而 RGB LED 可以通过颜色组合表达更丰富的设备状态。后续课程可以继续扩展到按键切换灯效、蜂鸣器报警、LCD 显示状态、传感器数据采集、AI 摄像头识别结果提示等方向。只要把程序中的状态变化映射到合适的颜色和节奏,RGB LED 就能成为智能硬件项目中简单直观的反馈系统。

相关推荐
万俟淋曦1 小时前
【论文速递】2026年第02周(Jan-04-10)(Robotics/Embodied AI/LLM)
人工智能·深度学习·机器人·大模型·论文·robotics·具身智能
Black蜡笔小新1 小时前
企业私有化AI训练推理一体工作站DLTM企业级AI模型工作站助力企业AI落地常态化
人工智能
apcipot_rain1 小时前
计科八股20260530——文本输入模型步骤、CNN权重共享、Resnet、Transformer、RNN
人工智能·深度学习·神经网络·数学建模·自然语言处理
Mikowoo0072 小时前
神经网络 替代 线性模型_进行模型学习
人工智能·神经网络·学习
53AI2 小时前
AI赋能企业合规审查:从信息过载到智能闭环
人工智能·智能审核·合同审核·合规审查
搬砖的小码农_Sky2 小时前
macOS Sequoia OpenClaw + Ollama 本地离线部署(免API、Apple Silicon金属加速)
人工智能·macos·ai·人机交互
程序猿阿伟2 小时前
《OpenClaw边缘轻量化部署的核心技术与实践》
人工智能
Ajie'Blog2 小时前
Claude 大模型深度评测:从参数架构到实战边界
大数据·人工智能·架构
苏奇伦2 小时前
链式提示——把复杂任务拆成多步对话
人工智能