|
传感器 DIY 实战:BH1750 自动调光 + HX711 高精度电子秤制作

传感器 DIY 实战:BH1750 自动调光 + HX711 高精度电子秤制作

传感器是嵌入式开发中最常用也最有趣的入门元件——把物理世界的温度、光照、压力变成可被 MCU 处理的电信号。本文把两个经典传感器项目合并到一起讲:BH1750 光照传感器自动调光系统HX711 高精度电子秤 DIY。两个项目加起来硬件成本不到 100 元,却涵盖了 I2C 通信、24 位 ADC、信号放大、滤波与校准等核心技能。


项目一:BH1750 光照传感器自动调光系统

为什么需要自动调光?

固定亮度的照明设备很不人性化。环境光变化时,大多数人懒得手动调节——结果就是:要么太亮费电又刺眼,要么太暗伤眼睛。BH1750 自动调光系统能实时检测周围光线强度,自动调节 LED 或屏幕亮度,适合智能台灯、显示器背光、植物生长灯、汽车仪表照明等场景。

BH1750 传感器简介

BH1750 是罗姆半导体(ROHM)出品的数字型光照传感器,相比模拟光敏电阻优势明显:

特性BH1750光敏电阻
输出类型数字 I2C模拟电压
测量范围1–65535 Lux依赖电路设计
精度±20%较差
波长响应接近人眼不一致
校准出厂校准需要手动校准
价格约 3–5 元约 0.5–1 元

关键参数: 工作电压 3.0–3.6V(部分模块带稳压可接 5V),I2C 接口默认地址 0x23(可切 0x5C),16 位分辨率,最快 120ms 响应。

硬件清单

组件型号数量单价总价
光照传感器BH1750FVI 模块1¥4.5¥4.5
主控板Arduino Nano1¥12¥12
LED 灯珠5mm 白光 LED3¥0.3¥0.9
限流电阻220Ω3¥0.1¥0.3
面包板400 孔1¥5¥5
杜邦线公对公 20cm10¥0.2¥2
合计¥24.7

购买建议:淘宝搜索”BH1750 模块”,选择带稳压和上拉电阻的版本,接线更简单。

电路连接

BH1750 使用 I2C 接口,只需要 4 根线:

BH1750Arduino Nano
VCC5V(模块带稳压)
GNDGND
SCLA5(I2C 时钟)
SDAA4(I2C 数据)

LED 连接(3 颗 LED 并联到 D9 PWM 引脚):LED 正极 → 220Ω 电阻 → D9,LED 负极 → GND。

BH1750          Arduino Nano
┌────────┐      ┌────────────┐
│   VCC  │──────│   5V       │
│   GND  │──────│   GND      │
│   SCL  │──────│   A5       │
│   SDA  │──────│   A4       │
└────────┘      └────────────┘

LED (通过 220Ω电阻)
┌────────┐      ┌────────────┐
│   +    │──────│   D9 (PWM) │
│   -    │──────│   GND      │
└────────┘      └────────────┘

代码实现

在 Arduino IDE 中搜索安装 Adafruit_BH1750 库,或手动从 GitHub claws/BH1750 下载。

#include <Wire.h>
#include <BH1750.h>

#define LED_PIN 9

BH1750 lightSensor;

const int MIN_LUX = 50;
const int MAX_LUX = 1000;
const int PWM_MIN = 30;
const int PWM_MAX = 255;

float smoothedLux = 0;
const float ALPHA = 0.3;  // 滤波系数,越小越平滑

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);

  if (lightSensor.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23)) {
    Serial.println(F("BH1750 初始化成功"));
  } else {
    Serial.println(F("BH1750 初始化失败,检查接线!"));
    while (1);
  }
  lightSensor.setMeasurementTime(BH1750::MT_69MS);
}

void loop() {
  if (lightSensor.hasValue()) {
    float lux = lightSensor.readLightLevel();
    smoothedLux = ALPHA * lux + (1 - ALPHA) * smoothedLux;
    int pwmValue = calculatePWM(smoothedLux);
    analogWrite(LED_PIN, pwmValue);

    Serial.print("光照:");
    Serial.print(smoothedLux);
    Serial.print(" Lux | PWM: ");
    Serial.println(pwmValue);
  }
  delay(200);
}

int calculatePWM(float lux) {
  lux = constrain(lux, MIN_LUX, MAX_LUX);
  int pwm = map(lux, MIN_LUX, MAX_LUX, PWM_MIN, PWM_MAX);
  return constrain(pwm, PWM_MIN, PWM_MAX);
}

代码要点:

  1. I2C 初始化lightSensor.begin() 传入测量模式与地址,CONTINUOUS_HIGH_RES_MODE 提供 1 Lux 分辨率。
  2. 指数移动平均滤波ALPHA 系数平衡响应速度与稳定性,避免 LED 闪烁。
  3. PWM 映射:用 map() 把 Lux 线性映射到 PWM 范围,注意人眼对亮度感知是对数的,进阶可做 gamma 校正。

常见问题:传感器返回 0 或固定值

可能原因:SCL/SDA 接反、I2C 地址不对、上拉电阻缺失。用下面这段 I2C 扫描代码确认地址:

#include <Wire.h>
void setup() {
  Serial.begin(9600);
  Wire.begin();
  Serial.println("I2C 扫描中...");
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("找到设备: 0x");
      Serial.println(addr, HEX);
    }
  }
}
void loop() {}

节能效果

相比固定亮度照明,自动调光可节能 30–60%。以 10W LED 灯每天亮 8 小时计算:固定亮度日耗 80Wh,自动调光平均 5W 日耗 40Wh,年节省约 14.6 kWh(约 8.8 元)。办公室 100 盏灯一年可省近 900 元。

实际应用场景

  • 智能台灯: 白天自动调亮,晚上自动调暗,深夜保持最低亮度 30% 避免完全熄灭。
  • 显示器背光: 配合电脑使用,根据房间亮度调整,减少眼睛疲劳,节能 30–50%。
  • 植物生长灯: 根据自然光补充光照,保持植物接收恒定光照强度。
  • 汽车仪表照明: 隧道进出自动调整,避免突然变亮/变暗影响驾驶。

接入智能家居(MQTT)

如果你用 ESP8266/ESP32 替代 Arduino Nano,可以轻松把光照数据推送到 MQTT 服务器,接入 Home Assistant 等智能家居平台:

void publishLux(float lux) {
  char payload[10];
  dtostrf(lux, 4, 1, payload);
  mqttClient.publish("home/sensor/lux", payload);
}

这样就能在手机上实时查看房间光照、设置自动化规则(比如低于 200 Lux 自动开灯)。


项目二:HX711 高精度电子秤制作

为什么选择 HX711?

市面几十块的电子秤精度只能到 1g,而 HX711 + 称重传感器可以轻松做到 0.1g 甚至 0.01g。关键是成本极低:HX711 模块 8 元、50kg 称重传感器 25 元、Arduino Nano 15 元,总成本不到 50 元。

适合 DIY 咖啡称、珠宝秤、配料秤、智能仓储称重系统,也是学习 ADC 原理的绝佳素材。

HX711 工作原理

HX711 是专为高精度称重设计的 24 位 ADC 芯片,内部集成了低噪声可编程增益放大器(PGA,增益 32/64/128 倍可选)和 24 位 Δ-Σ ADC(最高 80SPS)。

为什么需要 24 位? 称重传感器输出的是毫伏级微弱信号(满载约 2mV/V)。5V 供电时满载输出仅 10mV,用 Arduino 10 位 ADC 只能分到 2 个刻度,根本没法用。HX711 把 0–5V 分成 1677 万份,10mV 对应约 3.3 万个刻度,精度提升上万倍。

硬件清单

组件型号价格备注
HX711 模块24 位 ADC¥8带稳压版本
称重传感器50kg 悬臂梁¥25按量程选 1kg–50kg
主控板Arduino Nano¥15或 ESP32
OLED 显示屏0.96 寸 I2C¥12显示重量
杜邦线公对母¥5
面包板400 孔¥8
合计-¥73批量更低

电路连接

HX711 模块引脚:VCC(5V/3.3V)、GND、DT(数据)、SCK(时钟)。称重传感器通常 4 根线:

  • 红线:E+(激励正)
  • 黑线:E-(激励负)
  • 白线:A+(信号正)
  • 绿线:A-(信号负)

接线步骤:

  1. 称重传感器四根线分别接到 HX711 模块的 E+、E-、A+、A- 端子。
  2. HX711 的 VCC 接 Arduino 5V,GND 接 GND。
  3. HX711 的 DT 引脚接 Arduino D2(数据)。
  4. HX711 的 SCK 引脚接 Arduino D3(时钟)。
  5. OLED 显示屏 SDA 接 A4,SCL 接 A5(与 BH1750 共用 I2C 总线)。

如果传感器线色不同,用万用表测电阻识别:E+/E- 之间约 400Ω,A+/A- 之间约 400Ω,其他组合约 300Ω。

称重传感器              HX711              Arduino Nano
┌──────────┐      ┌──────────────┐      ┌────────────┐
│ E+(红)   │──────│ E+           │      │            │
│ E-(黑)   │──────│ E-           │      │            │
│ A+(白)   │──────│ A+           │      │            │
│ A-(绿)   │──────│ A-           │      │            │
└──────────┘      │ VCC  │  GND  │──────│ 5V   GND   │
                  │ DT   │  SCK  │──────│ D2   D3    │
                  └──────────────┘      └────────────┘

基础称重代码

#include "HX711.h"

#define DT_PIN 2
#define SCK_PIN 3

HX711 scale;
float calibration_factor = 420.0;

void setup() {
  Serial.begin(9600);
  Serial.println("HX711 电子秤初始化...");
  scale.begin(DT_PIN, SCK_PIN);
  scale.set_scale(calibration_factor);
  scale.tare();
  Serial.println("初始化完成,开始称重...");
}

void loop() {
  if (scale.is_ready()) {
    float weight = scale.get_units(10);  // 读取 10 次平均
    Serial.print("重量:");
    Serial.print(weight, 2);
    Serial.println(" g");
  }
  delay(500);
}

带 OLED 显示的完整代码

如果你想要一个独立的称重显示设备而不依赖电脑串口,可以加一块 0.96 寸 OLED:

#include "HX711.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define DT_PIN 2
#define SCK_PIN 3
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

HX711 scale;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

float calibration_factor = 420.0;
float current_weight = 0;

void setup() {
  Serial.begin(9600);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED 初始化失败");
    for (;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("电子秤启动中...");
  display.display();

  scale.begin(DT_PIN, SCK_PIN);
  scale.set_scale(calibration_factor);
  scale.tare();
  delay(1000);
  display.clearDisplay();
  display.display();
}

void loop() {
  if (scale.is_ready()) {
    current_weight = scale.get_units(10);
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("当前重量:");
    display.setTextSize(2);
    display.setCursor(20, 25);
    display.print(current_weight, 1);
    display.print(" g");
    display.display();
  }
  delay(300);
}

校准步骤

校准是电子秤精度的关键,你需要一个已知重量的砝码(或已知重量的物品)。

  1. 移除秤盘上所有物品,上电等待 5 秒预热。
  2. 串口输出提示”移除所有重物,准备归零”,等待 3 秒稳定。
  3. 调用 scale.tare() 完成归零。
  4. 放上已知重量的砝码(如 100g)。
  5. 串口输入实际重量(克)。
  6. 代码读取原始值并计算校准系数 calibration_factor = raw_value / known_weight
void calibrate() {
  Serial.println("移除所有重物,准备归零...");
  delay(3000);
  scale.tare();

  Serial.println("放上已知重量的砝码,输入实际重量(克):");
  while (Serial.available() == 0) {}
  float known_weight = Serial.parseFloat();

  long raw_value = scale.read_average(20);
  calibration_factor = raw_value / known_weight;

  Serial.print("校准系数:");
  Serial.println(calibration_factor);
}

校准技巧: 用多个不同重量校准取平均值更准确;校准后不要移动传感器;温度变化会影响精度,重要应用需温度补偿。

常见问题排查

读数一直为 0: 检查 VCC 是否有 5V、DT/SCK 引脚是否正确、传感器线序是否错误。

读数跳动很大: 给 HX711 单独供电避免与电机共用;增加平均次数 scale.get_units(20);使用软件指数滤波:

float filtered = 0;
float alpha = 0.3;
void loop() {
  float raw = scale.get_units(5);
  filtered = alpha * raw + (1 - alpha) * filtered;
  Serial.println(filtered, 2);
}

精度不够: 使用更高品质传感器(不锈钢优于铝合金);确保供电稳定且纹波小;增加采样平均次数;远离振动源并做好机械固定。

漂移严重: 上电预热 5 分钟再使用;定期自动归零(每 10 秒);选择质量更好的传感器。

进阶:去皮与多量程

#define TARE_BUTTON 4
void loop() {
  if (digitalRead(TARE_BUTTON) == LOW) {
    scale.tare();
    delay(500);  // 防抖
  }
  float weight = scale.get_units(10);
  if (weight < 10)       Serial.print(weight, 3);   // <10g 显示 3 位
  else if (weight < 100) Serial.print(weight, 2);   // <100g 显示 2 位
  else                   Serial.print(weight, 1);   // 其余 1 位
  Serial.println(" g");
}

数据记录到 SD 卡

如果想把称重数据长期记录到 SD 卡以便后续分析,可以这样做:

#include <SD.h>

File dataFile;

void setup() {
  SD.begin(4);
  dataFile = SD.open("weight_log.csv", FILE_WRITE);
  dataFile.println("timestamp,weight");
}

void loop() {
  float weight = scale.get_units(10);
  dataFile.print(millis());
  dataFile.print(",");
  dataFile.println(weight);
  dataFile.close();
  delay(1000);
}

这个功能特别适合做咖啡萃取曲线记录、宠物进食监控、物流包裹称重归档等需要长期追踪重量的场景。

批量成本优化

  1. HX711 芯片散装单价降至 ¥6/片。
  2. 传感器批量 10 片以上可谈到 ¥20/片。
  3. 主控换成 ESP8266(¥12/片),自带 WiFi 方便物联网扩展。
  4. 显示屏换成段码屏(¥3/片)替代 OLED,功耗更低。

批量 10 套单套成本约 ¥46。


两个项目的共同要点

对比项BH1750 自动调光HX711 电子秤
传感器类型数字光照24 位 ADC 称重
接口I2C自定义串口协议
信号处理指数移动平均滤波多次采样平均 + 滤波
核心难点PWM 映射曲线校准系数计算
典型成本¥25¥50
精度±20% Lux0.1g

共性技巧: 两个项目都用到了软件滤波(指数移动平均)、都依赖正确接线与 I2C 地址排查、都可通过串口调试观察数据。把这两套系统跑通,你就掌握了嵌入式传感器开发中最核心的信号采集、滤波、标定三板斧。

给初学者的建议: 如果你完全没接触过 Arduino,建议先从 BH1750 项目入手——接线简单(4 根线)、代码短、现象直观(LED 亮度随环境变化),很容易获得成就感。跑通之后再挑战 HX711 电子秤,因为 HX711 涉及校准、去皮、滤波等更复杂的概念,有了 BH1750 的基础会顺畅很多。

进阶方向: 两个项目都可以用 ESP32 替换 Arduino Nano,从而获得 WiFi/蓝牙能力。BH1750 可以接入 MQTT 智能家居平台,HX711 可以对接云端数据库做长期重量趋势分析。更有趣的是把两者结合:做一个会根据环境光和物品重量同时响应的交互式装置,充分发挥传感器的潜力。

安全提示: 操作时注意区分 5V 和 3.3V 供电,接反可能烧毁模块。I2C 设备共用总线时,确保地址不冲突(BH1750 默认 0x23,OLED 通常 0x3C,互不干扰)。焊接前先用面包板验证电路,避免一次性焊错导致元件报废。

总结

BH1750 自动调光系统让照明设备真正”看懂”环境,节能又舒适;HX711 电子秤用不到 50 元实现了 0.1g 精度称重,是学习微弱信号处理的绝佳项目。

核心要点回顾:

  1. BH1750 通过 I2C 输出数字光照值,比光敏电阻更稳定准确,配合 PWM 即可实现自动调光。
  2. HX711 的 24 位 ADC 把毫伏级传感器信号放大上万倍,是高精度称重的关键。
  3. 两个项目都离不开校准——BH1750 出厂校准,HX711 需要手动计算校准系数。
  4. 软件滤波(指数移动平均)是传感器项目的通用技巧,让输出更平滑稳定。

动手试试吧,让传感器真正为你所用!