资讯动态

NodeMCU Firmware 中使用 BH1750 环境光传感器:init / read / getlux 完整实战指南

发布时间:2026/9/27 10:19:12 来源:尧图企业网站定制
物联网嵌入式【免费下载链接】nodemcu-firmwareLua based interactive firmware for ESP8266, ESP8285 and ESP32项目地址https://gitcode.com/gh_mirrors/no/nodemcu-firmware点击查看免费下载BH1750兼容 GY-30 模块是一款基于 I²C 总线的数字环境光强度传感器可直接输出 Lux勒克斯照度值。本文围绕仓库内 lua_modules/bh1750/bh1750_EN.md 定义的 Lua 模块完整讲解在 NodeMCU FirmwareESP8266 / ESP8285 / ESP32上通过bh1750.init()、bh1750.read()、bh1750.getlux()三个接口驱动该传感器的接线、API 用法、源码原理与周期采集实战方案。读完本文你可以在 NodeMCU 设备上稳定采集环境光照度并将其用于自动调光、智能家居上报等场景。一、模块概览与引入方式该模块的官方文档位于 docs/lua-modules/bh1750.md其实现在 lua_modules/bh1750/bh1750.lua贡献者 Martin Han2015-01-30 加入仓库。它属于纯 Lua 模块不需要编译进固件但依赖固件内置的i2cC 模块实现见 app/modules/i2c.c。加载模块Requirebh1750 require(bh1750)模块代码第一行local moduleName ...会记录加载名随后将函数表挂到全局命名空间因此加载后即可直接调用bh1750.init()等函数。释放模块Release当不再需要传感器时可以同时清空全局变量与package.loaded缓存避免残留引用bh1750 nil package.loaded[bh1750] nil注意bh1750模块本身只封装了 I²C 读写若后续还想使用同一条 I²C 总线上的其他设备释放本模块不会影响i2c总线状态。二、硬件接线与引脚选择BH1750GY-30是 I²C 从设备默认 7 位从机地址为0x23在源码 bh1750.lua 中以GY_30_address 0x23硬编码。硬件上只需四根线VCC→ 3.3V部分模块也兼容 5V请以模块说明书为准GND→ GNDSDA→ 开发板 SDA 引脚SCL→ 开发板 SCL 引脚ESP8266 没有硬件 I²C 控制器NodeMCU 使用软件 I²C 驱动可以选用任意 GPIO。但引脚参数是IO indexIO 索引而非 GPIO 编号这一点最容易踩坑。根据 docs/modules/gpio.md 中的索引映射表IO indexESP8266 pinIO indexESP8266 pin0 [*]GPIO167GPIO131GPIO58GPIO152GPIO49GPIO33GPIO010GPIO14GPIO211GPIO95GPIO1412GPIO106GPIO12[*] D0(GPIO16) 仅支持 GPIO 读写不支持 open-drain / 中断 / PWM / I²C / one-wire因此不要将 BH1750 的 SDA/SCL 接到 IO index 0。此外若你的模块将 GPIO16 复用于 RESET深度睡眠接入 I²C 会导致复位。I²C 总线是开漏结构SDA 与 SCL 需要 1k10k 的上拉电阻多数 GY-30 模块板载上拉电阻可直接工作。多片同地址设备可考虑使用不同 I²C 总线但本模块固定使用总线id 0见 bh1750.lua 的local id 0因此务必把 BH1750 接在总线 0 对应的引脚上。三、API 详解本模块共三个公开函数init()、read()、getlux()。其中read()负责向传感器发起一次读取并更新内部缓存getlux()返回最近一次读取的照度值放大 100 倍的整数便于保留两位小数。3.1 bh1750.init(sda, scl)描述设置 BH1750 所在的 I²C 引脚SDA / SCL以i2c.SLOW100kHz标准速率初始化 I²C 总线 0并将模块内部init标志置为true。语法bh1750.init(sda, scl)参数参数取值范围说明sda1~12SDA 引脚对应的 IO indexscl1~12SCL 引脚对应的 IO index返回值nil示例SDA_PIN 6 -- sda pin, GPIO12 SCL_PIN 5 -- scl pin, GPIO14 bh1750 require(bh1750) bh1750.init(SDA_PIN, SCL_PIN) -- release module bh1750 nil package.loaded[bh1750]nil在底层init()实际执行的是i2c.setup(id, sda, scl, i2c.SLOW)。参照 docs/modules/i2c.mdi2c.setup支持i2c.SLOW100kHz、i2c.FAST400kHz、i2c.FASTPLUS1MHz需 160MHz CPU 频率或 250001000000 Hz 的自定义频率BH1750 手册额定工作频率最高 400kHz模块按 100kHz 标准速率驱动最为稳妥。在 app/modules/i2c.c 的i2c_setup()中SDA/SCL 参数会经过MOD_CHECK_ID( gpio, ... )校验非法引脚会直接报错特别地源码明确拒绝sda 0i2c SDA on D0 is not supported。3.2 bh1750.read()描述向 BH1750 发送测量指令并读取 2 字节结果换算后存入内部缓存变量l。此函数不返回照度值读取后必须配合getlux()取值。语法bh1750.read()参数无nil返回值nil。若在未调用init()之前调用会打印提示init() must be called before read.并跳过读取见 bh1750.lua 的守卫逻辑。示例SDA_PIN 6 -- sda pin, GPIO12 SCL_PIN 5 -- scl pin, GPIO14 bh1750 require(bh1750) bh1750.init(SDA_PIN, SCL_PIN) bh1750.read() -- release module bh1750 nil package.loaded[bh1750]nil3.3 bh1750.getlux()描述返回最近一次read()缓存的照度值。返回值为整数实际照度Lux等于该值除以 100即保留两位小数的放大表示。语法bh1750.getlux()参数无nil返回值l整数Lux 计数放大了 100 倍。首次read()之前调用会得到初始值 0。示例SDA_PIN 6 -- sda pin, GPIO12 SCL_PIN 5 -- scl pin, GPIO14 bh1750 require(bh1750) bh1750.init(SDA_PIN, SCL_PIN) bh1750.read() l bh1750.getlux() print(lux: ..(l / 100).....(l % 100).. lx) -- release module bh1750 nil package.loaded[bh1750]nilprint(lux: ..(l / 100).....(l % 100).. lx)利用 Lua 的字符串拼接把放大 100 倍的整数拆成整数部分.小数部分例如l 12345时输出lux: 123.45 lx即 123.45 勒克斯。四、源码级原理解读4.1 I²C 读写流程核心读取过程在read_data(ADDR, commands, length)中完成bh1750.lua完整调用链为local function read_data(ADDR, commands, length) i2c.start(id) -- I2C START i2c.address(id, ADDR, i2c.TRANSMITTER) -- 寻址 0x23写方向 i2c.write(id, commands) -- 写入命令字节 i2c.stop(id) -- STOP i2c.start(id) -- 再次 START重复起始 i2c.address(id, ADDR, i2c.RECEIVER) -- 寻址 0x23读方向 tmr.delay(200000) -- 等待 200ms 测量完成 local c i2c.read(id, length) -- 读取 2 字节原始数据 i2c.stop(id) return c end这里发出的是命令CMD 0x10bh1750.lua。对照 BH1750 数据手册0x10为连续高分辨率模式H-Resolution Mode分辨率为 1 lx典型测量时间约 120ms因此代码中tmr.delay(200000)200ms足够覆盖最坏情况。i2c.address/i2c.read/i2c.write的底层实现可继续查阅 app/modules/i2c.c其中i2c.address()返回布尔值表示是否收到 ACKi2c.read()以 Lua 字符串形式返回读取到的字节序列。4.2 Lux 换算公式原始 16 位数据转换为照度值的逻辑在read_lux()中bh1750.lualocal UT dataT:byte(1) * 256 dataT:byte(2) -- 高位在前拼成 16 位整数 l (UT*1000/12) -- 放大 100 倍的 Lux 值 return(l)换算依据是 BH1750 高分辨率模式下照度公式lux raw / 1.2。代码将结果放大 100 倍以保留两位小数l raw / 1.2 × 100 raw × 1000 / 12例如原始计数raw 12345则l 12345 × 1000 / 12 1028750实际照度即10287.50 lx。这也是上一节示例中用l / 100和l % 100拼接打印的原因。4.3 状态管理模块用局部变量init记录是否已初始化只有init()调用成功后init trueread()才会真正执行读取照度缓存在l中getlux()仅是return l的访问器。这种发起读取与取值分离的设计使你可以先read()再处理其他任务稍后随时getlux()拿到同一份数据。五、周期采集与云端上报实战仓库提供了两个可直接运行的示例程序。5.1 每 10 秒周期采集bh1750_Example1.lua使用tmr定时器每 10 秒自动采集一次并打印照度local bh1750 require(bh1750) local sda 6 -- sda pin, GPIO12 local scl 5 -- scl pin, GPIO14 do bh1750.init(sda, scl) tmr.create():alarm(10000, tmr.ALARM_AUTO, function() bh1750.read() local l bh1750.getlux() print(lux: ..(l / 100).....(l % 100).. lx) end) end要点说明tmr.create()创建一次性定时器对象alarm(10000, tmr.ALARM_AUTO, cb)表示 10000ms 周期、自动重复触发回调定时器回调中先read()再getlux()保证每次拿到的都是最新测量值由于 BH1750 处于连续测量模式命令0x10即使两次读取间隔小于测量周期读到的也是最近一次完成的测量结果。5.2 每 60 秒上报云端bh1750_Example2.lua第二个示例展示了把照度通过 TCP/HTTP POST 上报到乐联Lelian / lewei50.com云平台的完整链路可作为接入其他云平台的模板local bh1750 require(bh1750) local sda 6 -- sda pin, GPIO12 local scl 5 -- scl pin, GPIO14 local ServerIP do bh1750.init(sda, scl) tmr.create():alarm(60000, tmr.ALARM_AUTO, function() bh1750.read() local l bh1750.getlux() --定义数据变量格式 Define the veriables formate local PostData [{\Name\:\T\,\Value\:\ ..(l / 100).....(l % 100)..\}] --创建一个TCP连接 Create a TCP Connection local socket net.createConnection(net.TCP, 0) --域名解析IP地址并赋值 DNS...it socket:dns(www.lewei50.com, function(_, ip) ServerIP ip print(Connection IP: .. ServerIP) end) --开始连接服务器 Connect the sever socket:connect(80, ServerIP) socket:on(connection, function() end) --HTTP请求头定义 HTTP Head socket:send(POST /api/V1/gateway/UpdateSensors/LW_GATEWAY HTTP/1.1\r\n .. Host: www.lewei50.com\r\n .. Content-Length: .. string.len(PostData) .. \r\n .. userkey: USERKEY\r\n\r\n .. PostData .. \r\n) --HTTP响应内容 Print the HTTP response socket:on(receive, function(sck, response) -- luacheck: no unused print(response) end) end) end接入前必改两处源码注释中已明确指出LW_GATEWAY替换为你自己的乐联设备标识Device IDUSERKEY替换为你自己的乐联 userkey。该示例同时示范了 NodeMCU 上两种基础库的协作方式net.createConnection(net.TCP, 0)建立 TCP 连接、socket:dns()做域名解析、socket:connect(80, ServerIP)连接 80 端口并构造 HTTP/1.1 请求socket:on(receive)打印服务器响应。把其中的 URL、请求头与PostData格式替换为其他物联网平台如 Thingspeak、自有服务器等即可复用这套定时采集 网络上报框架。六、常见问题与使用注意事项必须先 init 再 read模块对调用顺序有严格约束未初始化就read()只会打印提示而不执行任何 I²C 操作getlux()将永远返回 0。引脚是 IO index 而非 GPIO 编号init(6, 5)对应的是 GPIO12 / GPIO14NodeMCU 开发板丝印上的 D6 / D5不要直接填 GPIO 编号完整映射见 docs/modules/gpio.md 的索引表。固定使用 I²C 总线 0模块内部硬编码id 0若此前在总线 0 上初始化过其他设备会以最后一次i2c.setup的引脚与速度为准注意引脚冲突。从机地址固定为 0x23GY-30 / BH1750 常见地址即0x23ADDR 引脚接高电平为0x5C本模块未开放地址参数若你的传感器地址不同则需修改 bh1750.lua 中的GY_30_address。测量等待时间read()内部以tmr.delay(200000)阻塞等待约 200ms期间 CPU 被占用不适合在时间敏感的任务中高频调用周期采集建议间隔不小于测量时间。总线速率模块以i2c.SLOW100kHz初始化远超 BH1750 正常工作需求若与其他高速设备共用总线可参照 docs/modules/i2c.md 的i2c.setup说明自行调整需同步修改模块源码。Lua 数值精度放大 100 倍后的l在 ESP8266 默认整数模式下是安全的整数运算输出时按l / 100与l % 100拆分即可得到带两位小数的照度文本。七、延伸阅读BH1750 Lua 模块官方文档API 与贡献者信息汇总模块源码完整实现与换算逻辑周期采集示例 与 云端上报示例I²C 模块文档总线速度、多总线、GPIO16 限制等底层细节i2c.c 实现i2c.setup/i2c.address/i2c.read的 C 层校验与参数约束赞分享物联网嵌入式【免费下载链接】nodemcu-firmwareLua based interactive firmware for ESP8266, ESP8285 and ESP32项目地址https://gitcode.com/gh_mirrors/no/nodemcu-firmware点击查看免费下载相关推荐NodeMCU 固件 BH1750 环境光传感器 Lua 模块完整指南NodeMCU 固件 BH1750 环境光传感器 Lua 模块完整指南 导读 本文面向在 NodeMCUESP8266/ESP8285上使用 Lua 开发环物联网嵌入式基于 NodeMCUESP8266的 BH1750 光照传感器 Lua 驱动模块使用指南基于 NodeMCUESP8266的 BH1750 光照传感器 Lua 驱动模块使用指南 本指南以本仓库 bh1750_CN.md https://link物联网嵌入式Johnny-Five Light 模块实战使用 BH1750 数字环境光传感器测量照度与光照强度Johnny Five Light 模块实战使用 BH1750 数字环境光传感器测量照度与光照强度 本篇技术指南聚焦 Johnny Five 中的 LightIoT机器人嵌入式上一篇RabbitMQ 3.11.10 维护版本全解析经典镜像队列 Operator Policy 覆盖、AMQP 1.0 JWT 认证与 OAuth 2 配置增强下一篇抖音无水印下载神器douyin-downloader完全使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑