1. 项目概述
合宙Air780EGG是一款基于Lua语言的嵌入式开发板,其强大的I2C接口能力使其成为连接各类传感器的理想选择。SHT30作为一款高精度数字温湿度传感器,通过I2C接口与主控通信,是环境监测项目的常见选择。本文将详细解析如何在Air780EGG上使用Lua语言驱动SHT30传感器,包括完整的通信协议解析、CRC校验实现和数据处理流程。
在实际物联网项目中,温湿度监测是最基础也最关键的环节之一。相比常见的DHT11/DHT22等单总线传感器,SHT30采用I2C接口,具有更高的精度(±2%RH湿度精度,±0.2℃温度精度)和更稳定的通信性能。通过本案例,开发者可以掌握I2C设备驱动开发的核心方法,并扩展到其他I2C传感器应用。
2. I2C接口基础与API详解
2.1 I2C通信原理
I2C(Inter-Integrated Circuit)是一种同步、多主从架构的串行通信总线,由Philips公司开发。它仅需两根线(SCL时钟线和SDA数据线)即可实现设备间通信,特别适合短距离、低速率的设备互联。在Air780EGG上,I2C接口的工作电压为3.3V,最大支持400kHz(快速模式)的通信速率。
I2C通信的几个关键特性:
- 每个设备都有唯一的7位或10位地址(SHT30默认为0x44)
- 支持多主多从架构,通过地址识别设备
- 数据有效性规则:SCL高电平时SDA必须保持稳定
- 起始条件(SDA由高到低,SCL为高)和停止条件(SDA由低到高,SCL为高)
2.2 合宙I2C API详解
合宙Lua固件提供了简洁的I2C操作API,核心函数如下:
lua复制-- 初始化I2C总线
-- 参数说明:
-- id: I2C接口编号(Air780EGG通常为0或1)
-- speed: 通信速率,i2c.SLOW(约100kHz)或i2c.FAST(约400kHz)
-- polling: 是否使用轮询模式(false表示使用中断模式)
i2c.setup(id, speed, polling)
-- 发送数据
-- 参数说明:
-- id: I2C接口编号
-- addr: 从设备地址(7位地址,不需要右移)
-- data: 要发送的数据(可以是字符串或table)
-- stop: 是否在传输后产生停止条件
i2c.send(id, addr, data, stop)
-- 接收数据
-- 参数说明:
-- id: I2C接口编号
-- addr: 从设备地址
-- len: 要接收的字节数
i2c.recv(id, addr, len)
重要提示:在初始化I2C时,如果总线上有多个设备,应以最低速设备的最高速率作为总线速率。SHT30最高支持1MHz通信,但实际使用中100kHz(i2c.SLOW)已能满足需求,且稳定性更好。
3. SHT30传感器驱动实现
3.1 SHT30通信协议解析
SHT30采用标准的I2C通信协议,其测量流程如下:
- 主机发送启动测量命令(0x2C06表示高重复性测量)
- 等待测量完成(典型时间15ms)
- 读取6字节数据(温度高8位、温度低8位、温度CRC8,湿度高8位、湿度低8位、湿度CRC8)
测量命令格式说明:
- 0x2C:命令高字节
- 0x06:命令低字节(表示高重复性测量)
- 其他常用命令:
- 0x2400:中重复性测量
- 0x2C0D:高重复性测量,带时钟拉伸
3.2 CRC校验算法实现
SHT30使用CRC-8校验算法(多项式0x31,初始值0xFF)来验证数据传输的正确性。以下是Lua实现:
lua复制local function sht30_crc(data, len)
local crc = 0xFF -- 初始CRC值
local POLYNOMIAL = 0x31 -- CRC-8多项式
for byteCtr = 0, len - 1 do
crc = bit.bxor(crc, data:byte(byteCtr + 1))
-- 逐位计算
for bitIdx = 8, 1, -1 do
if bit.band(crc, 0x80) ~= 0 then
crc = bit.bxor(bit.lshift(crc, 1), POLYNOMIAL)
else
crc = bit.lshift(crc, 1)
end
crc = bit.band(crc, 0xFF) -- 确保8位
end
end
return crc
end
调试技巧:当CRC校验失败时,建议先检查I2C线路质量(线长、上拉电阻)和电源稳定性。SHT30对电源噪声敏感,建议在VDD和GND之间加0.1μF去耦电容。
3.3 温湿度数据转换
SHT30的原始数据需要按特定公式转换为实际值:
lua复制-- 温度转换(单位:℃)
temp = (raw_temp * 175.0) / 65535 - 45
-- 湿度转换(单位:%RH)
humi = (raw_humi * 100.0) / 65535
其中raw_temp是温度高8位和低8位组合的16位无符号整数(raw_temp = data1*256 + data2),raw_humi同理。
4. 完整驱动实现与优化
4.1 驱动初始化
lua复制PROJECT = "SHT30-I2C"
VERSION = "001.000.000"
local i2cid = 1 -- 使用I2C1接口
local SHT30_ADDR = 0x44 -- SHT30默认地址
-- 初始化I2C总线
local function sht30_init()
-- 使用低速模式(100kHz),中断模式
i2c.setup(i2cid, i2c.SLOW, false)
end
4.2 数据读取主逻辑
lua复制local function sht30_read()
-- 发送高重复性测量命令
local ret = i2c.send(i2cid, SHT30_ADDR, {0x2c, 0x06}, 0)
if ret then
sys.wait(20) -- 等待测量完成
-- 读取6字节数据
local data = i2c.recv(i2cid, SHT30_ADDR, 6)
local _, data1, data2, data3, data4, data5, data6 = pack.unpack(data, "b6")
-- CRC校验
local crc1 = sht30_crc(data, 2) -- 温度数据CRC
local crc2 = sht30_crc(data:sub(4, 5), 2) -- 湿度数据CRC
local ret = 0
local temp, humi = 0, 0
-- 校验失败处理
if crc1 ~= data3 then ret = ret + 1 end
if crc2 ~= data6 then ret = ret + 2 end
-- 根据校验结果处理数据
if ret == 0 then -- 全部校验通过
temp = (data1 * 256 + data2) * 175.0 / 65535 - 45
humi = (data4 * 256 + data5) * 100.0 / 65535
elseif ret == 1 then -- 仅温度校验失败
humi = (data4 * 256 + data5) * 100.0 / 65535
elseif ret == 2 then -- 仅湿度校验失败
temp = (data1 * 256 + data2) * 175.0 / 65535 - 45
end
return temp, humi
end
return nil, nil -- 读取失败
end
4.3 主任务循环
lua复制sys.taskInit(function()
sht30_init()
while true do
local temp, humi = sht30_read()
if temp and humi then
log.info("SHT30", string.format("温度:%.1f℃ 湿度:%.1f%%", temp, humi))
else
log.warn("SHT30", "读取失败")
end
sys.wait(2000) -- 2秒读取一次
end
end)
sys.run()
5. 常见问题与调试技巧
5.1 I2C通信失败排查
-
设备无响应
- 检查硬件连接:SCL、SDA是否接反,电源是否正常
- 用逻辑分析仪或示波器观察I2C波形
- 尝试调整上拉电阻值(通常4.7kΩ)
-
CRC校验频繁失败
- 降低I2C通信速率(改用i2c.SLOW)
- 缩短I2C线缆长度(建议<30cm)
- 检查电源稳定性,增加去耦电容
-
数据明显异常
- 确认设备地址正确(SHT30默认0x44,也有型号是0x45)
- 检查字节序处理是否正确
- 验证计算公式实现是否准确
5.2 性能优化建议
-
降低功耗
- 在不需要测量时关闭传感器(发送0x3093命令进入休眠)
- 适当延长测量间隔(根据应用需求调整)
-
提高稳定性
- 添加软件重试机制(失败后自动重试3次)
- 实现数据平滑滤波(移动平均或卡尔曼滤波)
-
扩展功能
- 实现报警功能(当温湿度超过阈值时触发)
- 添加温度补偿(某些情况下需要补偿传感器自身发热)
6. 项目扩展与进阶应用
6.1 多传感器组网
通过I2C总线可以连接多个SHT30传感器(需修改地址引脚),实现多点监测:
lua复制-- SHT30地址配置
local sensors = {
{addr = 0x44, name = "室内"},
{addr = 0x45, name = "室外"}
}
for _, sensor in ipairs(sensors) do
local temp, humi = sht30_read(sensor.addr)
log.info(sensor.name, string.format("温度:%.1f℃ 湿度:%.1f%%", temp, humi))
end
6.2 数据上报与云端集成
结合合宙Air780EGG的通信能力,可以将数据上传至云平台:
lua复制local function upload_data(temp, humi)
local data = {
device = "air780e_001",
temp = temp,
humi = humi,
timestamp = os.time()
}
-- 通过MQTT或HTTP上传
mqtt.publish("/sensors", json.encode(data))
end
6.3 低功耗优化实践
对于电池供电的应用,需要特别考虑功耗:
lua复制sys.taskInit(function()
sht30_init()
while true do
-- 唤醒传感器
i2c.send(i2cid, SHT30_ADDR, {0x2C, 0x06})
sys.wait(20)
-- 读取数据
local temp, humi = sht30_read()
-- 让传感器进入休眠
i2c.send(i2cid, SHT30_ADDR, {0x30, 0x93})
-- 上报数据并进入深度睡眠
if temp and humi then
upload_data(temp, humi)
end
sys.wait(180*1000) -- 3分钟采集一次
end
end)
在实际部署中发现,合理配置测量间隔和休眠策略,可以使系统平均电流从5mA降低到200μA以下,显著延长电池寿命。