【CanMV K210】传感器实验 U 型光电传感器遮挡检测与 LED 提示

在智能硬件项目中,光电传感器常用于判断"物体是否经过某个位置"。例如计数器、限位检测、物料经过检测、小车测速、闸机识别和自动分拣设备,背后的基础逻辑都离不开传感器状态读取。对于 Python 硬件编程而言,这类实验非常适合作为输入检测入门案例,因为程序不只是控制 LED 发光,还会根据外部环境变化做出判断。

本实验使用 CanMV K210 开发板读取 U 型光电传感器的信号状态。当传感器光路无遮挡时,绿色 LED 点亮;当光路被物体遮挡时,红色 LED 点亮,并统计遮挡发生次数。程序还加入了稳定采样和状态变化判断,只在遮挡状态发生变化时打印信息,避免控制台不断刷屏。

学习目标 说明
理解光电检测 认识 U 型光电传感器如何通过光路遮挡判断物体经过
掌握 GPIO 输入 使用 GPIOHS 输入读取传感器输出电平
掌握 GPIO 输出 使用普通 GPIO 控制红色 LED 和绿色 LED 显示状态
理解状态变化判断 只在遮挡和恢复之间发生变化时更新输出,避免重复打印
建立检测类项目思路 为计数器、限位检测、小车测速和自动分拣实验打基础

U 型光电传感器的特点是结构直观,一端发射光,一端接收光。当中间光路被物体挡住,输出电平会发生变化;开发板通过 GPIO 输入读取这个电平,再用代码控制不同颜色的 LED 显示状态。这个过程完整体现了"传感器采集状态,程序判断逻辑,硬件输出反馈"的基本控制链路。

文章目录

理论基础

U 型光电传感器可以理解成一个"光路开关"。无遮挡时,发射端的光能够被接收端检测到,传感器输出一种电平状态;有物体插入 U 型槽中时,光路被挡住,传感器输出另一种电平状态。开发板不需要知道物体的颜色、形状或材质,只需要读取传感器信号端的高低电平,就能判断是否发生遮挡。

本实验中,U 型光电传感器的信号端接入 IO6,红色 LED 接入 IO7,绿色 LED 接入 IO8。代码中约定 BLOCKED_LEVEL = 0 表示光路被遮挡,CLEAR_LEVEL = 1 表示光路无遮挡。红色 LED 和绿色 LED 采用低电平点亮方式,因此 LED_ON = 0LED_OFF = 1。如果实际模块的电平逻辑与代码不同,只需要调整这些常量,主循环和函数结构不需要重写。

传感器输入实验和普通 LED 输出实验的区别在于,程序需要先读取外部环境,再根据读取结果决定输出状态。LED 实验通常是程序主动控制硬件;传感器实验则是外部环境先变化,程序再响应。这个思路更接近真实自动化项目,例如物体经过检测、设备到位判断、通道计数、机械限位和异常停留识别。
#mermaid-svg-IFr1GPU2Ve8wizz6{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-IFr1GPU2Ve8wizz6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IFr1GPU2Ve8wizz6 .error-icon{fill:#552222;}#mermaid-svg-IFr1GPU2Ve8wizz6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IFr1GPU2Ve8wizz6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .marker.cross{stroke:#333333;}#mermaid-svg-IFr1GPU2Ve8wizz6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IFr1GPU2Ve8wizz6 p{margin:0;}#mermaid-svg-IFr1GPU2Ve8wizz6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .cluster-label text{fill:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .cluster-label span{color:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .cluster-label span p{background-color:transparent;}#mermaid-svg-IFr1GPU2Ve8wizz6 .label text,#mermaid-svg-IFr1GPU2Ve8wizz6 span{fill:#333;color:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .node rect,#mermaid-svg-IFr1GPU2Ve8wizz6 .node circle,#mermaid-svg-IFr1GPU2Ve8wizz6 .node ellipse,#mermaid-svg-IFr1GPU2Ve8wizz6 .node polygon,#mermaid-svg-IFr1GPU2Ve8wizz6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .rough-node .label text,#mermaid-svg-IFr1GPU2Ve8wizz6 .node .label text,#mermaid-svg-IFr1GPU2Ve8wizz6 .image-shape .label,#mermaid-svg-IFr1GPU2Ve8wizz6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-IFr1GPU2Ve8wizz6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .rough-node .label,#mermaid-svg-IFr1GPU2Ve8wizz6 .node .label,#mermaid-svg-IFr1GPU2Ve8wizz6 .image-shape .label,#mermaid-svg-IFr1GPU2Ve8wizz6 .icon-shape .label{text-align:center;}#mermaid-svg-IFr1GPU2Ve8wizz6 .node.clickable{cursor:pointer;}#mermaid-svg-IFr1GPU2Ve8wizz6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .arrowheadPath{fill:#333333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IFr1GPU2Ve8wizz6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IFr1GPU2Ve8wizz6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IFr1GPU2Ve8wizz6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IFr1GPU2Ve8wizz6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .cluster text{fill:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 .cluster span{color:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 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-IFr1GPU2Ve8wizz6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IFr1GPU2Ve8wizz6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-IFr1GPU2Ve8wizz6 .icon-shape,#mermaid-svg-IFr1GPU2Ve8wizz6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IFr1GPU2Ve8wizz6 .icon-shape p,#mermaid-svg-IFr1GPU2Ve8wizz6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IFr1GPU2Ve8wizz6 .icon-shape .label rect,#mermaid-svg-IFr1GPU2Ve8wizz6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IFr1GPU2Ve8wizz6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IFr1GPU2Ve8wizz6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IFr1GPU2Ve8wizz6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-IFr1GPU2Ve8wizz6 .sensor>*{fill:#E8F3FF!important;stroke:#5B9BFF!important;stroke-width:2px!important;color:#1F3B6D!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .sensor span{fill:#E8F3FF!important;stroke:#5B9BFF!important;stroke-width:2px!important;color:#1F3B6D!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .sensor tspan{fill:#1F3B6D!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .input>*{fill:#EAFBF1!important;stroke:#42B983!important;stroke-width:2px!important;color:#1F5C3A!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .input span{fill:#EAFBF1!important;stroke:#42B983!important;stroke-width:2px!important;color:#1F5C3A!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .input tspan{fill:#1F5C3A!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .logic>*{fill:#FFF4E8!important;stroke:#F4A261!important;stroke-width:2px!important;color:#7A4A00!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .logic span{fill:#FFF4E8!important;stroke:#F4A261!important;stroke-width:2px!important;color:#7A4A00!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .logic tspan{fill:#7A4A00!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .output>*{fill:#F4EEFF!important;stroke:#8E6AD8!important;stroke-width:2px!important;color:#3D2B68!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .output span{fill:#F4EEFF!important;stroke:#8E6AD8!important;stroke-width:2px!important;color:#3D2B68!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .output tspan{fill:#3D2B68!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .power>*{fill:#FCEEF4!important;stroke:#E76F51!important;stroke-width:2px!important;color:#7A2740!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .power span{fill:#FCEEF4!important;stroke:#E76F51!important;stroke-width:2px!important;color:#7A2740!important;}#mermaid-svg-IFr1GPU2Ve8wizz6 .power tspan{fill:#7A2740!important;} U 型光电传感器

发射端与接收端
光路状态

无遮挡 / 被遮挡
信号端 IO6

输出高低电平
GPIOHS0 输入

photo_sensor.value()
稳定采样

多次读取减少抖动
状态判断

BLOCKED / CLEAR
红色 LED IO7

遮挡时点亮
绿色 LED IO8

无遮挡时点亮
计数统计

遮挡次数累加
模块供电

VCC
公共地线

GND

这条链路可以从电路和程序两个角度理解。电路侧,U 型光电传感器把光路变化转换成电平变化;程序侧,CanMV K210 读取 IO6 的电平,根据当前状态控制 IO7 和 IO8 的 LED 输出,并在遮挡发生时更新计数。整个实验不是单纯读取一个 GPIO,而是完成了"输入采集、状态判断、输出反馈、事件统计"的完整过程。

稳定采样是本实验中的一个重要设计。物体经过光路边缘时,传感器输出可能会在很短时间内抖动。如果程序每次读取到变化都立即响应,就可能出现一次遮挡被统计多次的问题。代码中的 read_photo_sensor_stable() 会连续读取多次,并用多数结果作为最终状态,从而降低瞬时抖动造成的误判。

硬件设施

本实验围绕 U 型光电传感器、红色 LED、绿色 LED 和 CanMV K210 的 GPIO 输入输出能力展开。代码没有使用 LCD、摄像头、蜂鸣器、电机或其他传感器,因此硬件重点集中在 IO6、IO7、IO8 三个引脚,以及传感器供电和公共地线。

接线关系可以先通过下面这张图建立整体印象。IO6 用于读取 U 型光电传感器信号,IO7 用于控制红色 LED,IO8 用于控制绿色 LED。传感器模块需要正常供电,并与 CanMV K210 保持公共地线。

硬件 / 软件 作用 说明
CanMV K210 开发板 实验运行平台 负责执行 MicroPython 程序,并读取传感器状态、控制 LED 输出
U 型光电传感器 遮挡检测模块 信号端接入 IO6,光路被遮挡时输出低电平,无遮挡时输出高电平
红色 LED 遮挡状态提示 接入 IO7,传感器检测到遮挡时点亮
绿色 LED 无遮挡状态提示 接入 IO8,传感器无遮挡时点亮
限流电阻 LED 保护 如果使用独立 LED,需要串联限流电阻,避免 LED 或 GPIO 过流
maix.GPIO GPIO 控制模块 用于创建输入和输出对象,完成 LED 控制与传感器读取
fpioa_manager.fm 引脚映射模块 用于把物理引脚绑定到指定 GPIO 或 GPIOHS 功能
time 延时模块 用于传感器稳定采样和主循环节奏控制

实验中用到的主要零件如下。U 型光电传感器负责检测光路是否被遮挡,红色 LED 和绿色 LED 负责显示当前状态,CanMV K210 负责读取输入并输出控制信号。实物接线时重点检查信号线和 LED 极性,不要只看模块是否插上。

接线关系可以直接从代码中的引脚常量和 fm.register() 推导出来。红灯连接到 IO7,绿灯连接到 IO8,U 型光电传感器信号端连接到 IO6。红灯和绿灯使用普通 GPIO 输出,光电传感器使用 GPIOHS0 输入,并配置为上拉输入模式。

物理引脚 GPIO 功能 代码变量 对应硬件 说明
IO7 GPIO0 red_led 红色 LED 低电平点亮,用于表示光路被遮挡
IO8 GPIO1 green_led 绿色 LED 低电平点亮,用于表示光路无遮挡
IO6 GPIOHS0 photo_sensor U 型光电传感器信号端 使用上拉输入读取传感器输出电平
VCC 模块供电 U 型光电传感器 VCC 根据模块标识连接对应供电端
GND 公共地线 U 型光电传感器 GND 与 CanMV K210 共地,保证输入电平稳定

完成接线后的整体效果如下。检查时重点关注 IO6、IO7、IO8 三个位置:IO6 是否接到传感器信号端,IO7 是否接到红色 LED,IO8 是否接到绿色 LED。程序运行后,无遮挡时绿色 LED 应该点亮;用物体遮挡 U 型槽后,绿色 LED 熄灭,红色 LED 点亮。

实验现象 正常表现 异常提示
程序启动 默认进入无遮挡状态,绿色 LED 点亮 两个 LED 都不亮时,检查 LED 极性、限流电阻和 GPIO 映射
光路无遮挡 传感器输出高电平,绿灯亮,红灯灭 若红灯亮,可能是传感器电平逻辑与代码设定相反
光路被遮挡 传感器输出低电平,红灯亮,绿灯灭 遮挡无反应时,检查 IO6 是否接到传感器信号端
物体快速经过 控制台只在状态变化时打印 如果计数偏多,需要增加采样次数或延时
光路恢复 程序打印恢复信息,绿色 LED 重新点亮 状态不恢复时,检查传感器是否被持续遮挡或安装偏移
多次遮挡 每次从无遮挡进入遮挡时累计次数增加 计数异常时,检查传感器抖动和消抖参数

软件代码

本实验代码围绕一个传感器输入和两个 LED 输出展开。程序先完成引脚注册和 GPIO 对象创建,再封装红绿灯控制函数,接着通过稳定采样读取传感器状态。主循环只在状态发生变化时更新 LED 和打印信息,这样既能及时响应遮挡变化,也能避免控制台被重复信息占满。

软件环境 作用 检查重点
CanMV IDE 编辑、运行和调试 K210 程序 能识别开发板串口,并能运行基础 print() 测试
CanMV 固件 提供 maix.GPIOfpioa_manager 等模块 固件环境需要支持当前 GPIO 与 FPIOA 写法
USB 串口驱动 让电脑识别开发板串口 串口工具中能看到对应端口
串口终端 查看遮挡事件和累计次数 遮挡或恢复时能看到状态打印
maix.GPIO 创建 GPIO 输入输出对象 能控制 LED,并读取传感器信号端电平
fpioa_manager.fm 完成 IO 与 GPIO 功能映射 IO6、IO7、IO8 能映射到对应 GPIO 功能
python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
CanMV K210 U 型光电传感器实验 Demo

实验目标:
1. 读取 U 型光电传感器的遮挡状态
2. 遮挡时点亮红灯,无遮挡时点亮绿灯
3. 统计被遮挡次数
4. 只在状态变化时打印信息,避免控制台刷屏
"""

from maix import GPIO
from fpioa_manager import fm
import time


# =========================
# 硬件引脚配置区
# =========================

RED_LED_PIN = 7                 # 红色 LED 接 IO7
GREEN_LED_PIN = 8               # 绿色 LED 接 IO8
PHOTO_PIN = 6                   # U 型光电传感器信号端接 IO6

RED_LED_GPIO = fm.fpioa.GPIO0
GREEN_LED_GPIO = fm.fpioa.GPIO1
PHOTO_GPIO = fm.fpioa.GPIOHS0


# =========================
# 电平配置区
# =========================

LED_ON = 0                      # LED 低电平点亮
LED_OFF = 1                     # LED 高电平熄灭

BLOCKED_LEVEL = 0               # 光路被遮挡时,传感器输出低电平
CLEAR_LEVEL = 1                 # 光路无遮挡时,传感器输出高电平


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

def setup():
    """初始化 LED 和 U 型光电传感器"""
    global red_led
    global green_led
    global photo_sensor

    fm.register(RED_LED_PIN, RED_LED_GPIO, force=True)
    fm.register(GREEN_LED_PIN, GREEN_LED_GPIO, force=True)
    fm.register(PHOTO_PIN, PHOTO_GPIO, force=True)

    red_led = GPIO(GPIO.GPIO0, GPIO.OUT)
    green_led = GPIO(GPIO.GPIO1, GPIO.OUT)
    photo_sensor = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)

    set_clear_state()
    print("U 型光电传感器初始化完成")
    print("无遮挡:绿灯亮")
    print("被遮挡:红灯亮")


# =========================
# LED 状态控制
# =========================

def red_on():
    red_led.value(LED_ON)


def red_off():
    red_led.value(LED_OFF)


def green_on():
    green_led.value(LED_ON)


def green_off():
    green_led.value(LED_OFF)


def set_blocked_state():
    """遮挡状态:红灯亮,绿灯灭"""
    red_on()
    green_off()


def set_clear_state():
    """无遮挡状态:绿灯亮,红灯灭"""
    red_off()
    green_on()


# =========================
# 传感器读取
# =========================

def read_photo_sensor():
    """
    读取 U 型光电传感器状态

    返回值:
    0 表示光路被遮挡
    1 表示光路无遮挡
    """
    return photo_sensor.value()


def read_photo_sensor_stable(samples=5, delay_ms=2):
    """
    多次采样,减少抖动误判

    samples  : 采样次数
    delay_ms : 每次采样间隔
    """
    high_count = 0

    for _ in range(samples):
        if read_photo_sensor() == 1:
            high_count += 1
        time.sleep_ms(delay_ms)

    if high_count > samples // 2:
        return CLEAR_LEVEL
    else:
        return BLOCKED_LEVEL


# =========================
# 状态处理
# =========================

def handle_status_change(status, block_count):
    """根据传感器状态切换 LED,并打印事件信息"""
    if status == BLOCKED_LEVEL:
        block_count += 1
        set_blocked_state()
        print("检测到物体遮挡,累计次数:{}".format(block_count))
    else:
        set_clear_state()
        print("光路恢复无遮挡")

    return block_count


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

def loop():
    """循环检测 U 型光电传感器状态"""
    last_status = None
    block_count = 0

    while True:
        current_status = read_photo_sensor_stable()

        if current_status != last_status:
            block_count = handle_status_change(current_status, block_count)
            last_status = current_status

        time.sleep_ms(30)


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

if __name__ == '__main__':
    setup()

    try:
        loop()
    except KeyboardInterrupt:
        red_off()
        green_off()
        print("程序已停止,LED 已关闭")

这段程序可以分成输入、判断和输出三个层级。输入层由 photo_sensorread_photo_sensor_stable() 完成,负责读取 U 型光电传感器的稳定状态;判断层由 BLOCKED_LEVELCLEAR_LEVELlast_statushandle_status_change() 完成,负责判断遮挡是否发生变化;输出层由红色 LED、绿色 LED 和串口打印完成,负责把检测结果反馈出来。

引脚配置区把红灯、绿灯和光电传感器的物理连接写成常量,后续修改接线时只需要调整顶部配置。电平配置区把 LED 点亮逻辑和传感器输出逻辑独立出来,如果实际硬件电平相反,优先调整 LED_ONLED_OFFBLOCKED_LEVELCLEAR_LEVEL,不要直接改主循环。

函数名 功能 对应现象
setup() 初始化 LED、光电传感器和引脚映射 程序启动后绿灯亮起,并打印初始化提示
red_on() 点亮红色 LED 遮挡状态下红灯亮
red_off() 熄灭红色 LED 无遮挡状态下红灯灭
green_on() 点亮绿色 LED 无遮挡状态下绿灯亮
green_off() 熄灭绿色 LED 遮挡状态下绿灯灭
set_blocked_state() 设置遮挡显示状态 红灯亮,绿灯灭
set_clear_state() 设置无遮挡显示状态 绿灯亮,红灯灭
read_photo_sensor() 直接读取传感器电平 获取当前光路是否被遮挡
read_photo_sensor_stable() 多次采样并判断稳定状态 减少传感器抖动带来的误判
handle_status_change() 根据状态切换 LED 并更新计数 遮挡时累计次数,恢复时切换绿灯
loop() 持续检测传感器状态 程序持续响应遮挡和恢复事件

主循环中的 last_status 是避免刷屏和重复计数的关键。程序每次读取当前状态后,会和上一次状态比较。只有遮挡状态发生变化时,才调用 handle_status_change() 切换 LED 并打印信息。遮挡发生时,block_count 自增一次;光路恢复时,程序切换回绿灯状态并输出恢复提示。这种写法更接近真实项目中的事件触发逻辑,而不是简单地反复打印传感器当前值。

扩展应用

U 型光电传感器实验的调试重点在于电平逻辑、接线关系和状态变化判断。遇到问题时,不适合直接大范围修改代码,应围绕传感器输出、LED 电平和引脚映射逐步确认。

问题现象 可能原因 处理思路
程序运行后 LED 都不亮 LED 接线错误、供电异常、低电平点亮逻辑与实际硬件不一致 检查 IO7、IO8 连接关系,尝试切换 LED_ONLED_OFF 的取值
遮挡时绿灯亮、无遮挡时红灯亮 传感器输出电平与代码设定相反 对调 BLOCKED_LEVELCLEAR_LEVEL,或单独打印传感器电平确认
控制台没有遮挡信息 传感器信号线未接到 IO6,或 GPIOHS0 映射不正确 核对 PHOTO_PIN = 6 和实际信号端接线,单独打印 photo_sensor.value() 测试
控制台信息频繁变化 遮挡边缘抖动、采样次数太少、传感器安装不稳定 增大 samplesdelay_ms,固定传感器位置,避免物体停在光路边缘
遮挡次数统计偏多 同一次遮挡过程中状态反复跳变 提高稳定采样次数,或在状态切换后增加更长的消抖等待
按 Ctrl+C 后 LED 仍亮 程序异常退出前没有执行关闭逻辑,或中断没有被捕获 保留 try...except KeyboardInterrupt,停止时调用 red_off()green_off()
传感器一直显示遮挡 U 型槽内有异物、传感器安装偏移、输出逻辑与代码相反 清理光路,重新固定传感器,并检查 BLOCKED_LEVEL 设置
传感器一直显示无遮挡 信号线接错、传感器未供电、遮挡物没有进入有效光路 检查 VCC、GND、信号线和遮挡位置

U 型光电传感器实验的核心价值在于把"是否有物体经过"转换成程序可以处理的数字信号。当前代码已经具备输入读取、稳定采样、状态变化判断、LED 状态反馈和次数统计能力,因此可以自然扩展到很多检测类项目中。只要将遮挡事件看作一次输入触发,就可以继续连接计数、报警、限位、测速或自动化控制逻辑。

应用场景 实现思路 可扩展能力
物体通过计数 每次检测到遮挡状态时累加计数 可扩展为生产线计数器、通道计数器或课堂演示计数器
小车测速实验 在固定距离放置两个 U 型光电传感器,记录通过时间差 后续可扩展双传感器测速和速度计算
限位检测 将遮挡状态作为设备到位信号 可扩展到滑轨、小车、机械结构的边界检测
闸机通行检测 遮挡光路表示有物体或卡片经过 可扩展蜂鸣器提示、LCD 显示和通行次数记录
自动分拣触发 物体经过传感器时触发后续动作 后续可扩展电机、舵机或继电器控制
教学演示实验 通过红绿灯直观看到输入状态变化 可用于讲解 GPIO 输入、上拉模式、状态机和事件触发
异常状态提示 长时间遮挡时判断为异常停留 可扩展超时判断和声光报警逻辑

从工程结构看,当前程序已经把读取、判断、显示和计数拆成独立函数。新增功能时,可以继续保留 read_photo_sensor_stable() 作为输入入口,把 handle_status_change() 扩展成更完整的事件处理函数。后续接入蜂鸣器、LCD、串口上传或网络通信时,也可以在状态变化发生时触发,而不是在主循环中无意义地重复执行。

总结

本实验通过 CanMV K210 开发板完成了 U 型光电传感器遮挡检测,核心能力包括 FPIOA 引脚映射、GPIO 输出控制、GPIOHS 输入读取、上拉输入配置、传感器稳定采样、状态变化判断、LED 状态提示和遮挡次数统计。代码把外部光路变化转换成程序中的高低电平,再通过红绿灯和控制台信息展示检测结果,完整体现了传感器输入与硬件输出联动的基本思路。

这类实验是智能硬件课程中非常重要的输入检测案例。屏幕中的 if 判断不再只是比较数字,而是对应真实世界中"有物体经过"或"光路恢复"的状态变化。后续课程可以在这个基础上继续扩展按键输入、蜂鸣器反馈、LCD 显示、双传感器测速、数据上传、自动分拣和 AI 摄像头识别等内容。只要理解传感器信号、GPIO 输入和状态处理之间的关系,更多自动化检测项目都可以沿着同一套思路搭建。

相关推荐
向量引擎1 小时前
当搜索开始替人整理答案:我重新理解了向量检索和 API 中间层
人工智能·gpt·aigc·ai编程·ai写作·key·agi
春日见1 小时前
五分钟入门 强化学习---DQN(Deep Q Net)算法与实现
人工智能·python·深度学习·算法·microsoft·机器学习
赤龙ERP1 小时前
赤龙一周观察 · 2026年5月第五周
人工智能
hnult1 小时前
从AI命题到九重监考体系:考试云一站式竞赛答题平台解决方案
人工智能
完成大叔2 小时前
模块二,Agent规划模式的四个工具思考
人工智能
Elastic 中国社区官方博客2 小时前
我们如何在 Elasticsearch Serverless 上将向量搜索吞吐量提升一倍
大数据·数据库·人工智能·elasticsearch·搜索引擎·云原生·serverless
xzzd_jokelin2 小时前
公司AI开发痛点解析:多人+AI辅助 协同开发?
人工智能·机器学习·ai·ai编程·cloud·codex
阿洛学长2 小时前
MoneyPrinterTurbo 深度解析与部署实战:AI 一键短视频生成,从源码到上线全攻略
人工智能·音视频
weelinking2 小时前
【产品】11_实现后端接口——数据在背后如何流动
java·人工智能·python·sql·oracle·json·ai编程