04 AirVOC_1000
作者:沈园园
一、AirVOC_1000 概述
AirVOC_1000是合宙设计生产的一款I2C接口的VOC(挥发性有机化合物)气体传感器配件板,其中:
- 气体传感器,奥松AGS02MA;
- I2C接口;
- 适用于Air780E系列/Air8000系列/Air8101系列/Air6101系列;
二、演示功能概述
AirVOC_1000是合宙设计生产的一款I2C接口的VOC(挥发性有机化合物)气体传感器配件板;
主要用于检测甲醛、一氧化碳、可燃气体、酒精、氨气、硫化物、苯系蒸汽、烟雾、其它有害气体的监测;
本demo演示的核心功能为:
Air8000核心板+AirVOC_1000配件板,每隔1秒读取1次TVOC空气质量数据;
三、准备硬件环境


1、Air8000核心板一块
2、TYPE-C USB数据线一根
3、AirVOC_1000配件板
4、母对母的杜邦线4根
5、Air8000核心板和数据线的硬件接线方式为
- Air8000核心板通过TYPE-C USB口连接TYPE-C USB 数据线,数据线的另外一端连接电脑的USB口;
- 核心板正面的 供电/充电 拨动开关 拨到供电一端;
- 核心板背面的 USB ON/USB OFF 拨动开关 拨到USB ON一端;
Air8000核心板和AirVOC_1000配件板的硬件接线方式为
| Air8000核心板 | AirVOC_1000配件板 |
|---|---|
| VDD_EXT | 3V3 |
| GND | GND |
| I2C1_SDA | SDA |
| I2C1_SCL | SCL |
四、准备软件环境
4.1 软件环境
在开始实践本示例之前,先筹备一下软件环境:
1、烧录工具:Luatools 下载调试工具
2、内核固件:Air8000 最新版本的内核固件
3、脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/accessory_board/AirVOC_1000
4、lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件
准备好软件环境之后,接下来查看如何烧录项目文件到Air8000核心板,将本篇文章中演示使用的项目文件烧录到Air8000核心板中。
4.2 API 介绍
I2C库:https://docs.openluat.com/osapi/core/i2c/
五、程序结构
AirVOC_1000/
│── main.lua
│── voc_app.lua
│── AirVOC_1000.lua
│── readme.md
5.1 文件说明
main.lua:主程序入口文件。voc_app.lua:每隔1秒读取1次TVOC空气质量数据。AirVOC_1000.lua:AirVOC_1000驱动文件。
六、代码详解
6.1 main.lua
主程序文件 main.lua 是整个项目的入口点。它负责初始化系统环境。
6.2 voc_app.lua
每隔1秒读取1次TVOC空气质量数据。
6.2.1 每隔1秒读取一次TVOC数据
--每隔1秒读取一次TVOC数据
local function read_voc_task_func()
--打开voc硬件
air_voc.open(1)
while true do
--读取TVOC的ppb,ppm,quality_level值
local ppb = air_voc.get_ppb()
local ppm = air_voc.get_ppm()
local level, description = air_voc.get_quality_level()
--读取成功
if ppb then
log.info("空气质量",
string.format("TVOC: ppb %d, ppm %.3f, 等级 %d(%s)",
ppb, ppm, level, description))
--读取失败
else
log.error("空气质量", "读取数据失败")
end
--等待1秒
sys.wait(1000)
end
--关闭voc硬件
air_voc.close()
end
6.3 AirVOC_1000.lua
AirVOC_1000驱动配置文件。
6.3.1 读取AirVOC_1000的寄存器中指定长度的数据
-- 从机地址为0x1A
local slave_address = 0x1A
-- TVOC数据的寄存器地址
local DATA_REG_ADDR = 0x00
-- TVOC数据的长度
local DATA_REG_LEN = 0x05
-- 计算数据表data中所有数据元素的crc8校验值
local function crc8(data)
local crc = 0xFF
for i = 1, #data do
crc = bit.bxor(crc, data[i])
for j = 1, 8 do
crc = crc * 2
if crc >= 0x100 then
crc = bit.band(bit.bxor(crc, 0x31), 0xff)
end
end
end
return crc
end
-- 读取AirVOC_1000的寄存器中指定长度的数据
--reg:number类型;
-- 表示AirVOC_1000上的寄存器地址;
-- 必须传入,不允许为空;
--返回值:失败返回false;成功返回读取到的指定长度的数据(string类型)
local function read_register(reg, len)
-- 发送寄存器地址
i2c.send(AirVOC_1000.i2c_id, slave_address, reg)
-- sys.wait(20)
-- 读取应答的数据
local data = i2c.recv(AirVOC_1000.i2c_id, slave_address, len)
-- log.info("read_register", data:toHex())
-- 读取到的数据为指定的长度,则表示读取成功
-- 否则读取失败
if type(data)=="string" and data:len()==len then
return data
else
log.error("AirVOC_1000 read_register error", type(data), type(data)=="string" and data:len() or "invalid type", len)
return false
end
end
6.3.2 打开AirVOC_1000
--打开AirVOC_1000;
--i2c_id:number类型;
-- 主机使用的I2C ID,用来控制AirVOC_1000;
-- 取值范围:仅支持0和1;
-- 如果没有传入此参数,则默认为0;
--返回值:成功返回true,失败返回false
function AirVOC_1000.open(i2c_id)
--如果i2c_id为nil,则赋值为默认值0
if i2c_id==nil then i2c_id=0 end
--检查参数的合法性
if not (i2c_id == 0 or i2c_id == 1) then
log.error("AirVOC_1000.open", "invalid i2c_id", i2c_id)
return false
end
AirVOC_1000.i2c_id = i2c_id
--初始化I2C
if i2c.setup(i2c_id, i2c.FAST) ~= 1 then
log.error("AirVOC_1000.open", "i2c.setup error", i2c_id)
return false
end
return true
end
6.3.3 读取TVOC的ppb值
--读取TVOC的ppb值;
--ppb: 代表 parts per billion,即 十亿分之一。 1 ppb TVOC 表示在每 10 亿个体积单位的空气中,含有 1 个体积单位的 TVOC
--返回值:失败返回false;
-- 成功返回ppb值(number类型)
function AirVOC_1000.get_ppb()
--从寄存器DATA_REG_ADDR中读取DATA_REG_LEN长度的数据
local raw = read_register(DATA_REG_ADDR, DATA_REG_LEN)
--读取数据出错
if not raw then
log.error("AirVOC_1000.get_ppb", "read_register error")
return false
end
--检查校验值
if crc8({raw:byte(1), raw:byte(2), raw:byte(3), raw:byte(4)}) ~= raw:byte(5) then
log.error("AirVOC_1000.get_ppb", "crc error")
return false
end
--解析数据: 大端格式
local tvoc = (raw:byte(2) << 16) |
(raw:byte(3) << 8) |
raw:byte(4)
return tvoc
end
6.3.4 读取TVOC的ppm值
--读取TVOC的ppm值;
--ppm: 代表 parts per million,即 百万分之一。 1 ppm TVOC 表示在每 100 万个体积单位的空气中,含有 1 个体积单位的 TVOC
--返回值:失败返回false;
-- 成功返回ppb值(number类型)
function AirVOC_1000.get_ppm()
--读取ppb值
local ppb = AirVOC_1000.get_ppb()
--如果ppb读取失败
if not ppb then
log.error("AirVOC_1000.get_ppm", "get_ppb error")
return false
end
--ppb = ppm*1000
return ppb/1000
end
6.3.5 读取TVOC的空气质量等级
--读取TVOC的空气质量等级;
-- 根据 TVOC 浓度(通常以 ppb 或 ppm 表示)划分的等级,用于评估室内空气质量的优劣和对人体健康的潜在风险;
-- 不同国家、地区或机构的标准可能略有差异,但核心划分逻辑相似:浓度越低,等级越好,风险越低。
--返回值:失败返回false;
-- 成功返回空气质量等级值(number类型,数值越小,表示空气质量越好)和空气质量描述(string类型,例如优、良好、轻度污染、中度污染、重度污染)
-- 1:表示优
-- 2:表示良好
-- 3:表示轻度污染
-- 4:表示中度污染
-- 5:表示重度污染
function AirVOC_1000.get_quality_level()
--读取ppb值
local ppb = AirVOC_1000.get_ppb()
--如果ppb读取失败
if not ppb then
log.error("AirVOC_1000.get_qulity_level", "get_ppb error")
return false
end
--根据ppb值计算空气质量等级
if ppb < 200 then
return 1,"优"
elseif ppb < 1000 then
return 2,"良好"
elseif ppb < 3000 then
return 3,"轻度污染"
elseif ppb < 5000 then
return 4,"中度污染"
else
return 5,"重度污染"
end
end
6.6.6 关闭AirVOC_1000
--关闭AirVOC_1000
--返回值:成功返回true,失败返回false
function AirVOC_1000.close()
--close接口没有返回值,理论上不会关闭失败
i2c.close(AirVOC_1000.i2c_id)
return true
end
七、运行结果展示
通过观察Luatools的运行日志,每隔1秒出现一次类似于下面的打印,就表示测试正常:
[2025-09-25 11:28:01.193][000002293.756] I/user.空气质量 TVOC: ppb 93, ppm 0.093, 等级 1(优)
[2025-09-25 11:28:02.194][000002294.761] I/user.空气质量 TVOC: ppb 91, ppm 0.091, 等级 1(优)
八、总结
通过本章内容的学习,你可以学习到Air8000核心板+AirVOC_1000配件板,通过I2C读取TVOC空气质量数据的应用。