激光传感器主要分为接收激光和发射激光两部分组成。通过接接收模块来检测激光束后引脚输出信号,在用单片机进行监测输出引脚的低电平状态,从而实现编程逻辑。相较于红外传感器,激光会更具有抗干扰强、检测距离会更远(可达100米)等特点。 那么激光发射模块只需要接通电源就能射出激光束,将激光束对准接收模块探头就能形成一个闭环。


| 以树莓派Pico开发板为例,提醒: 请按下图的引脚标识接线,务必不能接错。如果接错线通电后会导致设备烧毁! |

接好线后实图如下:

| laser | 下载这个laser源代码上传至树莓派pico文件内,直接运行查看数据(如下图),当激光照射接收头时显示:低电平检测到激光。无照射显示高电平。 |

上述代码的核心是实时监测 GPIO19 引脚的电平变化,并在电平改变时输出激光检测状态,整体可以分为 6 个关键步骤:
1. 模块导入与常量定义
from machine import Pin
import time
import utime
MONITOR_PIN_NUM = 19
导入Pin类用于控制 GPIO 引脚,time/utime用于延时和时间统计;
用常量MONITOR_PIN_NUM管理引脚号,后续想换引脚只需改这一行,提升代码可维护性。
2. 引脚初始化(核心)
monitor_pin = Pin(MONITOR_PIN_NUM, Pin.IN, Pin.PULL_UP)
Pin.IN:把 GPIO19 设置为输入模式(只能读取电平,不能输出信号),符合激光接收模块 “输出信号给 Pico” 的逻辑;
Pin.PULL_UP:启用引脚内部的上拉电阻。
3. 变量初始化
last_state = monitor_pin.value() # 读取引脚初始电平,作为“上一次状态”
start_time = utime.time() # 记录程序启动的时间戳,用于计算相对运行时间
初始化last_state为引脚当前值,避免第一次判断时和None比较导致逻辑错误;
start_time用于后续输出 “XX 秒时检测到电平变化”,比直接输出绝对时间戳更易读。
4. 提示信息输出
print(f"开始监测GP{MONITOR_PIN_NUM}引脚的电平信号...")
print("按下Ctrl+C停止程序")
给用户明确的反馈,告知程序已启动、监测的引脚,以及停止方式。
5. 主循环(核心监测逻辑)
while True:
current_state = monitor_pin.value() # 实时读取当前引脚电平(0=低电平,1=高电平)
# 只有电平发生变化时才输出信息(避免无意义的重复打印)
if current_state != last_state:
elapsed_time = utime.time() - start_time # 计算程序运行了多久
# 适配激光接收模块的逻辑:0=检测到激光,1=未检测到
state_str = "低电平(检测到激光)" if current_state == 0 else "高电平(未接收到激光)"
print(f"[{elapsed_time:.2f}秒] GP{MONITOR_PIN_NUM}状态: {state_str} (数值: {current_state})")
last_state = current_state # 更新“上一次状态”,为下一次判断做准备
time.sleep(0.05) # 50ms延时:防抖+降低CPU占用
while True:无限循环,持续监测引脚状态;
current_state = monitor_pin.value():每次循环都读取当前电平(0 或 1);
电平变化判断:只有当前电平≠上一次电平时才输出信息,避免 “一直检测到激光” 就每秒打印几十次的冗余;
time.sleep(0.05):关键的 “防抖” 操作 —— 激光接收模块可能因环境光波动导致电平瞬间跳变,50ms 延时能过滤这些误触发,同时降低 Pico 的 CPU 占用。
6. 异常处理与收尾
except KeyboardInterrupt:
print(f"\n程序已停止 - 共运行 {utime.time() - start_time:.2f} 秒")
except Exception as e:
print(f"\n程序异常终止: {type(e).__name__} - {e}")
finally:
print("监测程序已退出")
KeyboardInterrupt:捕获用户按Ctrl+C的操作,优雅停止程序并输出运行时长;
Exception:捕获其他意外错误(如引脚故障),避免程序崩溃无提示;
finally:无论程序正常停止还是异常终止,都输出收尾提示,提升用户体验。
这绝大部分新手最容易困惑的点,核心原因是解决激光接收模块 “无信号时引脚电平不确定” 的问题,我分 3 层解释:
1. 先理解:激光接收模块的输出逻辑
我们用的激光接收模块是 “低电平有效” 也就是只能检测到低电平。
有激光照射时:模块内部电路导通,OUT引脚输出低电平(0V);
无激光照射时:模块内部电路断开,OUT引脚处于悬空状态(既不是 0V 也不是 3.3V)。
2. 问题:悬空引脚的电平是 “不稳定的”
如果 Pico 的 GPIO 引脚不启用上拉 / 下拉电阻,当激光接收模块输出悬空时,GPIO 的电平会受环境干扰(如周围电线、静电)随机跳变(一会儿 0,一会儿 1),导致代码误判 “激光时有时无”,监测结果完全不可靠。
3. 解决:启用内部上拉电阻(Pin.PULL_UP)
因为树莓派Pico 的 GPIO 内部集成了上拉电阻(约几十 kΩ),只需要代码启用,如果你的单片机型号自身没有内部上拉功能,可单独给引脚外接一个电阻。
原理:上拉电阻会把 GPIO 引脚 “拉向” 3.3V(高电平),相当于给引脚一个 “默认状态”;
效果:
无激光时:模块OUT悬空,上拉电阻把 GPIO 电平拉成高电平(1),对应代码里的 “未接收到激光”;
有激光时:模块OUT输出低电平(0V),强于上拉电阻的拉力,GPIO 电平被拉成低电平(0),对应代码里的 “检测到激光”;
总结:上拉电阻让引脚在 “无信号” 时拥有明确的高电平,只有 “有激光” 时才变成低电平,彻底解决了悬空电平的不稳定问题。
补充:为什么不用下拉电阻(Pin.PULL_DOWN)?
下拉电阻会把引脚默认拉成低电平,若用下拉:
无激光时:引脚是低电平(0),对应 “检测到激光”(逻辑颠倒);
有激光时:引脚是高电平(1),对应 “未检测到激光”;
不是不能用,只是不符合 “低电平有效” 模块的常规使用习惯,代码里的状态描述也要反过来,不如上拉电阻直观。
代码整体逻辑:初始化输入引脚(启用上拉)→ 记录初始状态和启动时间 → 无限循环读取引脚电平 → 仅在电平变化时输出激光检测状态 → 捕获异常并优雅收尾;
上拉电阻的核心作用:给激光接收模块 “无信号时的悬空引脚” 一个明确的高电平默认状态,避免电平随机跳变导致误判,让 “高电平 = 无激光、低电平 = 有激光” 的逻辑稳定可靠;
time.sleep(0.05)的作用:过滤环境光导致的电平瞬间抖动,减少误触发,同时降低 CPU 占用。
简单来说,上拉电阻是让引脚 “有默认值”,避免 “没信号时乱跳”,而代码的核心就是监测这个稳定的电平变化,从而判断是否有激光。
联系人:张工
电话:0755-32914578
QQ:2251000002
微信:扫下方二维码添加,请备注来意
提供:人工智能,IOT物联网,工控数显,嵌入式软硬件开发,科创教育,产品定制,生产,方案解决...