对射槽型光耦(光电开关)

原理简介

槽型光耦(如 ITR9608)像一个"光电门":一边发红外光,一边接收,中间留一道槽。

  • 工作原理:
    • 无遮挡:红外光直达接收管,接收管导通 → 输出一个电平
    • 有遮挡:光被挡住,接收管截止 → 输出跳变(电平翻转)
  • 所以它本质是个数字开关:遮挡 / 不遮挡,常用来测速、计数、限位
  • 模块说明:带比较器的模块是三线(VCC/GND/OUT,OUT 已处理好上拉);裸 ITR9608 是四脚,要自己配电阻(见注意事项)
  • 接口:OUT 接普通 GPIO(数字输入,建议内部上拉)

典型应用

  • 物体经过计数(流水线、人数统计)
  • 旋转编码器 / 测转速(码盘每格遮挡一次)
  • 传送带走偏、到位限位检测
  • 门窗开合检测
  • 滴落/通过式传感器

接线图

[接线图占位,后续添加]

文字说明(具体接法见下方代码注释):

  • 三线模块版:模块 VCC → Pico 3V3;模块 GND → Pico GND;模块 OUT → Pico GP14(数字输入,用内部上拉)
  • 裸 ITR9608(四脚)版:
    • 发射管:长脚(阳极)串 220Ω → 3V3,短脚(阴极)→ GND
    • 接收管:一端接 3V3,另一端接 GP14 并配 10kΩ 下拉到 GND(遮挡时 GP14 读到 1)
    • 没把握就用带比较器的模块版,省去配电阻的麻烦

示例代码

基础示例:检测遮挡状态

# ============ 接线 ============
# 三线模块版:
#   光耦模块 VCC → Pico 3V3
#   光耦模块 GND → Pico GND
#   光耦模块 OUT → Pico GP14(数字输入,内部上拉)
# 本示例打印"有遮挡 / 无遮挡"
# =============================
from machine import Pin
import time

out = Pin(14, Pin.IN, Pin.PULL_UP)   # 内部上拉;本接法下:有遮挡读到 0,无遮挡读到 1

print('检测遮挡...')

while True:
    if out.value() == 0:
        print('有遮挡')
    else:
        print('无遮挡')
    time.sleep_ms(100)

进阶示例:遮挡计数(带消抖)

# ============ 接线 ============
# 光耦模块 VCC → Pico 3V3,GND → GND
# 光耦模块 OUT → Pico GP14(内部上拉;遮挡读到 0)
# =============================
from machine import Pin
import time

out = Pin(14, Pin.IN, Pin.PULL_UP)
count = 0
last = 1          # 上一次的状态,1=无遮挡

print('每遮挡一次计数 +1')

while True:
    cur = out.value()
    # 边沿检测:从无遮挡(1)变成有遮挡(0)算一次
    if last == 1 and cur == 0:
        count += 1
        print('计数:', count)
        time.sleep_ms(50)        # 简单消抖,避免一次遮挡被数成多次
    last = cur
    time.sleep_ms(5)

应用示例:测转速(算每秒遮挡次数)

# ============ 接线 ============
# 光耦模块 VCC → Pico 3V3,GND → GND
# 光耦模块 OUT → Pico GP14(内部上拉;遮挡读到 0)
# 把码盘/叶片装在转轴上,每转一圈遮挡 N 次
# =============================
from machine import Pin
import time

out = Pin(14, Pin.IN, Pin.PULL_UP)

last = 1
last_ms = time.ticks_ms()      # 上一次遮挡的时刻
SLOTS = 20                     # 每转的遮挡格数,按你的码盘改这个数字

print('测转速...')

while True:
    cur = out.value()
    if last == 1 and cur == 0:                  # 又遮挡了一次
        now = time.ticks_ms()
        dt = time.ticks_diff(now, last_ms)      # 两次遮挡间隔(毫秒)
        last_ms = now
        if dt > 0:
            freq = 1000 / dt                    # 频率 = 每秒遮挡次数(Hz)
            # 转速公式:rpm = 频率 × 60 ÷ 每转遮挡格数
            rpm = freq * 60 / SLOTS
            print('频率: %.2f Hz  转速: %.1f rpm' % (freq, rpm))
    last = cur
    time.sleep_ms(2)

注意事项

  • 上拉电阻:这类光耦多为开集/开漏输出,必须接上拉(内部 PULL_UP 或外接 10kΩ 到 3V3),否则读不到高电平
  • 裸 ITR9608 要配电阻:发射管串 220Ω 限流,接收端配 10kΩ 下拉(或上拉,看极性),没把握就用带比较器的模块版
  • 遮挡物宽度:要够宽能完全挡住槽,太细的线可能检测不到
  • 怕强环境光:红外对管受阳光/强灯光干扰,尽量避光、加遮光罩
  • 响应快适合测速:光耦切换很快,做旋转测速很合适,但软件消抖时间别设太长,否则漏计
  • 电平:模块是 3.3V 器件,接 Pico 3V3;若买到 5V 模块,OUT 高电平可能到 5V,要加分压或电平转换,别直接怼 GPIO

常见问题

Q: 一直读到同一个值,不随遮挡变化? A: 先确认接的是 OUT→GP14 且用了 Pin.PULL_UP;再用 print(out.value()) 单独看,遮挡/不遮挡时是否翻转。若不动,检查 VCC/GND 和模块是否损坏。

Q: 计数比实际多(一次遮挡数成好几下)? A: 遮挡边缘抖动导致多次触发,把进阶示例里的消抖 sleep_ms(50) 调大,或改边沿检测(本示例已用边沿,仍多就加大延时)。

Q: 测速数字跳得厉害? A: 转速本身不均会跳;可多取几次频率求平均。另外确认 SLOTS(每转遮挡格数)填的是你码盘的真实格数。