znlgis 博客

GIS开发与技术分享

第12章:环境光与紫外线传感器

本章介绍光敏传感器、紫外线传感器的工作原理、数据采集与应用场景。


12.1 光敏传感器

12.1.1 工作原理

光敏电阻(LDR)是一种光控电阻:

光线 → 光敏材料 → 电阻变化
强光 → 电阻小 → 分压电压低 → ADC 值小
弱光 → 电阻大 → 分压电压高 → ADC 值大

12.1.2 电路结构

    VCC
     │
   [R1 10K]  上拉电阻
     │
     ├───────── S (ADC 输入)
     │
   [LDR]  光敏电阻
     │
    GND

输出电压 = VCC × R_LDR / (R1 + R_LDR)

12.1.3 数据编码

光线强度 ADC 值 说明
强光 低(0-20000) LDR 阻值小
室内 中(20000-45000)  
暗处 高(45000-65535) LDR 阻值大

注意:不同厂家的模块可能有不同的电路设计,需要根据实际测试确定数值范围。

12.1.4 读取代码

'''
实验:光敏传感器读取
接线:S 端连接 GP26 (ADC0)
'''
from machine import ADC
import time

light_sensor = ADC(26)

def get_light_level():
    """读取光线强度"""
    raw = light_sensor.read_u16()
    # 反转:值越大表示越亮
    inverted = 65535 - raw
    percent = inverted / 65535 * 100
    return raw, percent

while True:
    raw, percent = get_light_level()
    print(f"ADC: {raw:5d}  亮度: {percent:5.1f}%")
    time.sleep(0.5)

12.1.5 智能照明控制

'''
实验:自动照明系统
环境变暗时自动开灯
'''
from machine import ADC, Pin, PWM
import time

light_sensor = ADC(26)
led = PWM(Pin(0))
led.freq(1000)

# 阈值设定
DARK_THRESHOLD = 45000     # 暗环境阈值
BRIGHT_THRESHOLD = 30000   # 亮环境阈值

def auto_brightness():
    """根据环境光自动调节 LED 亮度"""
    ambient = light_sensor.read_u16()
    
    if ambient > DARK_THRESHOLD:
        # 环境暗,LED 全亮
        duty = 65535
    elif ambient < BRIGHT_THRESHOLD:
        # 环境亮,LED 关闭
        duty = 0
    else:
        # 中间区域,线性调节
        duty = int((ambient - BRIGHT_THRESHOLD) / 
                   (DARK_THRESHOLD - BRIGHT_THRESHOLD) * 65535)
    
    led.duty_u16(duty)
    return ambient, duty

while True:
    ambient, duty = auto_brightness()
    print(f"环境光: {ambient}  LED: {duty/65535*100:.0f}%")
    time.sleep(0.5)

12.2 紫外线传感器

12.2.1 传感器介绍

套件中的紫外线传感器主要针对太阳光中的 UVA 波段(320-400nm):

  • 适用于 UV 指数监测
  • 可用于紫外线消毒检测
  • 火焰探测

12.2.2 UV 指数对照

UV 指数 辐射强度 防护建议
0-2 无需防护
3-5 中等 戴帽子、太阳镜
6-7 涂防晒霜
8-10 很高 减少户外活动
11+ 极高 避免外出

12.2.3 数据转换

UV 传感器输出电压与 UV 指数的关系(典型值):

def voltage_to_uv_index(voltage):
    """
    电压转 UV 指数
    基于 ML8511 传感器特性(仅供参考)
    """
    if voltage < 0.99:
        return 0
    elif voltage >= 2.8:
        return 11
    else:
        # 线性近似
        uv_index = (voltage - 0.99) / (2.8 - 0.99) * 11
        return uv_index

12.2.4 UV 检测代码

'''
实验:紫外线强度检测
接线:S 端连接 GP26 (ADC0)
'''
from machine import ADC
import time

uv_sensor = ADC(26)

def read_uv_index():
    """读取 UV 指数"""
    raw = uv_sensor.read_u16()
    voltage = raw * 3.3 / 65535
    
    # UV 指数估算(需要根据实际传感器校准)
    if voltage < 0.5:
        uv = 0
    else:
        uv = (voltage - 0.5) / 0.2
    
    return voltage, max(0, min(11, uv))

def get_uv_warning(uv_index):
    """获取防护建议"""
    if uv_index < 3:
        return "低风险"
    elif uv_index < 6:
        return "中等,建议防护"
    elif uv_index < 8:
        return "高风险,需要防护"
    elif uv_index < 11:
        return "很高风险,避免暴露"
    else:
        return "极端风险,禁止外出"

while True:
    voltage, uv = read_uv_index()
    warning = get_uv_warning(uv)
    print(f"电压: {voltage:.2f}V  UV指数: {uv:.1f}  {warning}")
    time.sleep(1)

12.2.5 UV 日志记录

'''
实验:UV 数据记录
定时记录 UV 强度,保存到文件
'''
from machine import ADC, RTC
import time

uv_sensor = ADC(26)
rtc = RTC()

LOG_INTERVAL = 60  # 每分钟记录一次

def log_uv_data():
    """记录 UV 数据到文件"""
    raw = uv_sensor.read_u16()
    timestamp = rtc.datetime()
    
    # 格式化时间
    time_str = f"{timestamp[0]}-{timestamp[1]:02d}-{timestamp[2]:02d} " \
               f"{timestamp[4]:02d}:{timestamp[5]:02d}"
    
    # 追加到日志文件
    with open('uv_log.csv', 'a') as f:
        f.write(f"{time_str},{raw}\n")
    
    print(f"[{time_str}] UV ADC: {raw}")

# 创建日志文件头
with open('uv_log.csv', 'w') as f:
    f.write("时间,ADC值\n")

while True:
    log_uv_data()
    time.sleep(LOG_INTERVAL)

12.3 火焰传感器

12.3.1 工作原理

火焰传感器检测火焰发出的特定波长红外光:

  • 检测波长:760-1100nm
  • 探测角度:约 60°
  • 探测距离:0.5-1m(取决于火焰大小)

12.3.2 双输出模式

火焰传感器通常有两种输出:

  • 数字输出 (D):超过阈值输出低电平
  • 模拟输出 (A):与火焰强度成反比

12.3.3 检测代码

'''
实验:火焰传感器
接线:A 端→GP26, D 端→GP22
'''
from machine import ADC, Pin
import time

flame_analog = ADC(26)
flame_digital = Pin(22, Pin.IN)

def check_flame():
    """检测火焰"""
    digital = flame_digital.value()
    analog = flame_analog.read_u16()
    
    # 数字:0=检测到火焰
    # 模拟:值越小火焰越强
    is_flame = digital == 0 or analog < 30000
    
    return is_flame, analog

while True:
    is_flame, intensity = check_flame()
    
    if is_flame:
        print(f"⚠️ 检测到火焰! 强度ADC: {intensity}")
    else:
        print(f"正常 ADC: {intensity}")
    
    time.sleep(0.5)

12.3.4 火灾报警系统

'''
实验:火灾报警系统
'''
from machine import ADC, Pin
import time

flame_sensor = ADC(26)
buzzer = Pin(20, Pin.OUT)
led = Pin(0, Pin.OUT)

FLAME_THRESHOLD = 30000

def alarm_on():
    """触发报警"""
    for _ in range(5):
        buzzer.value(1)
        led.value(1)
        time.sleep(0.1)
        buzzer.value(0)
        led.value(0)
        time.sleep(0.1)

while True:
    flame = flame_sensor.read_u16()
    
    if flame < FLAME_THRESHOLD:
        print(f"🔥 火灾警报! ADC: {flame}")
        alarm_on()
    else:
        buzzer.value(0)
        led.value(0)
    
    time.sleep(0.2)

12.4 声音传感器

12.4.1 工作原理

声音传感器使用驻极体麦克风(ECM)检测声音:

声波 → 麦克风 → 微弱电信号 → 放大电路 → 输出

12.4.2 输出特性

  • 模拟输出:电压随声音强度变化
  • 无声时:约 VCC/2(中点电压)
  • 有声时:在中点上下波动

12.4.3 声音检测代码

'''
实验:声音传感器
接线:S 端连接 GP26
'''
from machine import ADC
import time

sound = ADC(26)

# 计算基准值(静音时的中点)
baseline = sum(sound.read_u16() for _ in range(100)) // 100

def detect_sound(threshold=5000):
    """检测声音"""
    raw = sound.read_u16()
    deviation = abs(raw - baseline)
    return deviation > threshold, deviation

while True:
    detected, level = detect_sound()
    
    if detected:
        print(f"检测到声音! 偏差: {level}")
    
    time.sleep(0.05)

12.4.4 声控开关

'''
实验:拍手开灯
'''
from machine import ADC, Pin
import time

sound = ADC(26)
led = Pin(0, Pin.OUT)

THRESHOLD = 8000
CLAP_GAP = 300  # 两次拍手间隔 (ms)

baseline = sum(sound.read_u16() for _ in range(100)) // 100
last_clap = 0
clap_count = 0
led_state = False

while True:
    raw = sound.read_u16()
    deviation = abs(raw - baseline)
    
    if deviation > THRESHOLD:
        now = time.ticks_ms()
        
        if time.ticks_diff(now, last_clap) > CLAP_GAP:
            clap_count += 1
            print(f"拍手 {clap_count}")
            
            if clap_count >= 2:
                led_state = not led_state
                led.value(led_state)
                print(f"LED {'开' if led_state else '关'}")
                clap_count = 0
            
            last_clap = now
        
        # 等待声音结束
        while abs(sound.read_u16() - baseline) > THRESHOLD / 2:
            time.sleep_ms(10)
    
    # 超时重置
    if time.ticks_diff(time.ticks_ms(), last_clap) > 1000:
        clap_count = 0
    
    time.sleep_ms(10)

12.5 水滴传感器

12.5.1 工作原理

水滴传感器通过检测电导率变化检测液体:

  • 干燥时:阻抗高,输出高电平
  • 有水时:阻抗低,输出低电平(模拟值降低)

12.5.2 雨水检测

'''
实验:雨水检测
'''
from machine import ADC, Pin
import time

rain_sensor = ADC(26)
led = Pin(0, Pin.OUT)

DRY_THRESHOLD = 50000
WET_THRESHOLD = 30000

def check_rain():
    """检测降雨状态"""
    raw = rain_sensor.read_u16()
    
    if raw > DRY_THRESHOLD:
        return "干燥", raw
    elif raw > WET_THRESHOLD:
        return "小雨", raw
    else:
        return "大雨", raw

while True:
    status, raw = check_rain()
    print(f"状态: {status}  ADC: {raw}")
    
    led.value(status != "干燥")
    time.sleep(0.5)

12.6 本章小结

本章介绍了多种光电和环境传感器:

  1. 光敏传感器
    • 基于光敏电阻,阻值随光强变化
    • 适用于自动照明控制
  2. 紫外线传感器
    • 检测 UVA 波段
    • 输出电压与 UV 强度成正比
  3. 火焰传感器
    • 检测特定波长红外光
    • 数字+模拟双输出
  4. 声音传感器
    • 驻极体麦克风检测声音
    • 适用于声控开关
  5. 水滴传感器
    • 电导率检测
    • 雨水/液体检测

下一章将学习温度与湿度传感器。