嵌入式开发 传感器 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 Nano | 1 | ¥12 | ¥12 |
| LED 灯珠 | 5mm 白光 LED | 3 | ¥0.3 | ¥0.9 |
| 限流电阻 | 220Ω | 3 | ¥0.1 | ¥0.3 |
| 面包板 | 400 孔 | 1 | ¥5 | ¥5 |
| 杜邦线 | 公对公 20cm | 10 | ¥0.2 | ¥2 |
| 合计 | ¥24.7 |
购买建议:淘宝搜索”BH1750 模块”,选择带稳压和上拉电阻的版本,接线更简单。
电路连接
BH1750 使用 I2C 接口,只需要 4 根线:
| BH1750 | Arduino Nano |
|---|---|
| VCC | 5V(模块带稳压) |
| GND | GND |
| SCL | A5(I2C 时钟) |
| SDA | A4(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);
}
代码要点:
- I2C 初始化:
lightSensor.begin()传入测量模式与地址,CONTINUOUS_HIGH_RES_MODE提供 1 Lux 分辨率。 - 指数移动平均滤波:
ALPHA系数平衡响应速度与稳定性,避免 LED 闪烁。 - 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-(信号负)
接线步骤:
- 称重传感器四根线分别接到 HX711 模块的 E+、E-、A+、A- 端子。
- HX711 的 VCC 接 Arduino 5V,GND 接 GND。
- HX711 的 DT 引脚接 Arduino D2(数据)。
- HX711 的 SCK 引脚接 Arduino D3(时钟)。
- 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);
}
校准步骤
校准是电子秤精度的关键,你需要一个已知重量的砝码(或已知重量的物品)。
- 移除秤盘上所有物品,上电等待 5 秒预热。
- 串口输出提示”移除所有重物,准备归零”,等待 3 秒稳定。
- 调用
scale.tare()完成归零。 - 放上已知重量的砝码(如 100g)。
- 串口输入实际重量(克)。
- 代码读取原始值并计算校准系数
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);
}
这个功能特别适合做咖啡萃取曲线记录、宠物进食监控、物流包裹称重归档等需要长期追踪重量的场景。
批量成本优化
- HX711 芯片散装单价降至 ¥6/片。
- 传感器批量 10 片以上可谈到 ¥20/片。
- 主控换成 ESP8266(¥12/片),自带 WiFi 方便物联网扩展。
- 显示屏换成段码屏(¥3/片)替代 OLED,功耗更低。
批量 10 套单套成本约 ¥46。
两个项目的共同要点
| 对比项 | BH1750 自动调光 | HX711 电子秤 |
|---|---|---|
| 传感器类型 | 数字光照 | 24 位 ADC 称重 |
| 接口 | I2C | 自定义串口协议 |
| 信号处理 | 指数移动平均滤波 | 多次采样平均 + 滤波 |
| 核心难点 | PWM 映射曲线 | 校准系数计算 |
| 典型成本 | ¥25 | ¥50 |
| 精度 | ±20% Lux | 0.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 精度称重,是学习微弱信号处理的绝佳项目。
核心要点回顾:
- BH1750 通过 I2C 输出数字光照值,比光敏电阻更稳定准确,配合 PWM 即可实现自动调光。
- HX711 的 24 位 ADC 把毫伏级传感器信号放大上万倍,是高精度称重的关键。
- 两个项目都离不开校准——BH1750 出厂校准,HX711 需要手动计算校准系数。
- 软件滤波(指数移动平均)是传感器项目的通用技巧,让输出更平滑稳定。
动手试试吧,让传感器真正为你所用!