Chaos-nano 操作系统在手持式 VOC 检测设备上的应用
产品开发背景VOC 的危害
VOC(挥发性有机化合物)是常温下易挥发的有机化学物质,广泛存在于室内装修材料(甲醛、苯)、家具板材、汽车内饰、日用化学品(清洁剂、香水)等场景中,对人体健康具有显著危害。尤其对老人与孕妇这两类特殊群体,VOC 危害更为突出:
孕妇:孕期免疫力较低,长期接触 VOC 可能影响胎儿正常发育,增加胎儿畸形、早产、流产的风险,其中甲醛、苯等物质已被证实具有明确的生殖毒性;
老人:身体机能衰退,呼吸系统、心血管系统及肝脏肾脏功能较弱,VOC 刺激易引发呼吸道感染、头晕胸闷、血压波动等症状,长期暴露可能加重慢性疾病(如哮喘、冠心病)。
此外,VOC 还会导致室内空气质量下降,引发眼睛干涩、皮肤瘙痒等不适,影响特殊群体的日常生活质量。
产品开发的必要性
随着居民对健康重视程度的提升,老人与孕妇的居住环境安全成为家庭核心关注点,但传统 VOC 检测存在明显痛点:
专业检测机构服务价格高昂(单次检测费用数百至数千元),且检测周期长,无法满足日常高频监测需求;
大型实验室仪器体积庞大、操作复杂,老人与孕妇难以独立使用,更无法随身携带;
普通家用检测工具体积大多数续航较短,无法支撑长时间外出检测;
针对老人与孕妇群体的使用需求,需要一款可以随身携带、可以长时间工作的 VOC 检测设备;同时需要具备操作极简、数据直观、安全无辐射等核心特性。基于该思路开发面向老人与孕妇的手持式 VOC 检测设备,具有极强的现实必要性与社会价值。
产品介绍


该产品以“极致便携+长续航”为核心设计目标:
为了能够满足便携,在外观设计上采用了这种直径 4 cm 的圆形的外观设计;
为了能够长时间工作,在器件选择上选用了低功耗的 8 位单片机 STM8L151F3 ,并且在系统软件设计上采用了 Chaos-nano 操作系统——该系统是轻量级的异步协作式操作系统,可以在任务不执行的时候阻塞任务,且可以在合适的时候进入到低功耗状态——进一步降低了产品的功耗。
产品结构
手持式 VOC 检测设备基于 Chaos-nano 操作系统与 STM8L151F3 芯片构建,针对老人与孕妇的使用习惯,采用“极简设计+核心功能聚焦”的模块化结构,核心组成包括:
硬件层:
控制核心:STM8L151F3 微控制器(小巧封装,降低设备体积);
传感模块:高精度低功耗 VOC 传感器,温湿度传感器 SHT21;
显示模块:0.95 英寸 OLED 显示屏;
操作模块:一键式操作按键(仅保留开机/唤醒、显示切换 2 个核心按键,简化操作);
电源模块:限于产品体积,该产品采用了 150 mAh ,并采用 usb-micro 接口(支持 5V 充电,适配家庭常用充电器);
系统层:搭载 Chaos-nano 操作系统,提供轻量化任务调度、中断处理、低功耗管理等核心功能,适配 STM8L151F3 的硬件资源限制,确保设备运行稳定、续航持久。
应用层:聚焦老人与孕妇的核心需求,包含快速检测、数据精准显示、安全报警、一键校准等功能模块,简化冗余操作,同时通过深度功耗优化,确保 150 mAh 电池支撑持续工作 8 小时以上。
核心优势:极致便携性设计
依托 150 mAh 紧凑锂电池与 STM8L151F3 芯片的小巧封装,以及轻量级的 Chaos-nano 操作系统,设备实现“口袋级便携”:
尺寸:长 40 mm × 宽 40 mm × 厚 10 mm,并配有钥匙孔,便于老人与孕妇可轻松放入口袋、手提包或随身悬挂,几乎无携带负担;
材质:外壳采用 ABS 塑料表面防滑处理,手感舒适,便于握持;边角圆润无棱角,避免磕碰伤害;与铝合金铝块结合,使整体不显单调;
续航适配: usb-micro 接口支持充电宝、手机充电器、电脑 USB 口等多种充电方式,外出时可随时补充电量,配合 8 小时以上持续工作能力,满足全天外出检测需求(如就医、购物、探访亲友等场景)。
核心芯片:STM8L151F3 详细介绍
STM8L151F3 是意法半导体推出的超低功耗 8 位微控制器,基于 STM8 内核架构,专为电池供电的便携式智能设备设计,其特性与“150 mAh 电池+8 小时续航”的产品定位及老人、孕妇的使用需求高度适配,是设备的理想控制核心:
内核与主频:采用 STM8 增强型内核,最高工作频率 16 MHz,支持 16 位乘法指令与硬件除法,指令执行效率高,可快速响应传感器数据采集、按键操作等实时任务,确保设备“开机即测、数据秒出”,无需老人与孕妇长时间等待。
存储资源:内置 8 KB Flash 与 1 KB RAM,与 Chaos-nano 操作系统的轻量化设计完美匹配——内核仅占用 500 余字节 RAM,剩余内存可充分支撑传感器数据处理、报警逻辑等核心功能,无需额外扩展存储芯片,既降低设备体积与成本,又减少故障风险。
运行模式(持续检测状态):16 MHz 主频下芯片自身功耗仅 240 μA/MHz(约 3.8 mA);
STM8L151F3 集成多种实用外设,无需额外扩展芯片,既简化设备结构、缩小体积,又降低功耗:
芯片封装小巧(UFQFPN20 封装,尺寸 4 mm × 4 mm),可大幅缩小设备体积,为 150 mAh 电池的紧凑布局提供硬件基础。
系统整体框架


系统采用“硬件驱动-操作系统-应用层”三层架构:
底层驱动层:由 STM8L15x_StdPeriph_Driver 驱动库与自定义设备驱动组成,实现 STM8L151F3 芯片外设(ADC、I2C、GPIO 等)及 VOC 传感器、显示模块、按键等硬件的底层控制,重点优化低功耗驱动逻辑与数据采集精度,对应代码中的 devices 目录及 stm8l15x_it.c/stm8l15x_it.h 中断处理文件。
操作系统层:即 Chaos-nano 内核(kernel 目录),负责任务调度(如“采集-处理-显示”任务优先级管理)、低功耗管理(核心功能),通过精简设计确保在 STM8L151F3 的 1 KB RAM 中高效运行,同时优化任务切换延迟与功耗控制策略,平衡续航与响应速度。
应用层:优化核心逻辑,包括:
传感器快速采集(handle.c/handle.h);
数据直观显示;
操作逻辑简化(仅 2 个按键,开机自动检测,无操作自动休眠);
产品系统实现分析
工作流程
按下开机键之后,系统进行初始化并启动开机键检测任务。当检测到开机键持续 3 s 按下后,设置电源开机并显示第一屏内容;
按下切屏按键后:
会触发相应的中断,在中断中启动切屏任务;
当从中断返回后,调度器优先调度切屏任务;
在切屏任务中会切换显示内容;
上电后,系统会按照一定的延迟进行数据采集:
每 1 s 启动温湿度任务采集一次温湿度,当采集到数据后刷新显示;
每 1 s 启动 VOC 任务采集一次 VOC 数据,当采集到数据后刷新显示;
每 2 s 启动电池任务采集一次电池的电量和充电状态,然后刷新显示;
显示刷新:
显示刷新没有设定单独的任务,因此显示刷新属于同步操作——这里没有采用单独的任务进行异步刷新显示;
通过全局标志来判断当前处于哪个屏幕显示,当有当前屏幕的内容需要刷新时会对屏幕进行刷新,否则直接返回;
电池标志在每个屏幕上都有,所以当有电池数据需要刷新时会及时刷新该部分显示;
软件实现
任务分类与优先级设定
该软件基于 IAR for STM8 开发环境,搭配 Chaos-nano 操作系统,采用“任务化”设计,将功能拆解为5个独立的任务:
电源按键检测任务;
切屏按键检测任务;
温湿度(SHT21)检测任务;
VOC 检测任务;
电池状态与电量检测任务;
通过基于优先级调度实现高效协同工作。
| 任务 ID | 任务名称 | 核心功能 | 优先级 | 触发方式 |
| TASK_ID_POWER | 电源按键检测 | 检测电源按键是否在规定的时间内保持按下状态 | 0 | 中断 |
| TASK_ID_KEY | 切屏按键检测 | 切换显示屏幕 | 1 | 中断 |
| TASK_ID_SHT21 | 温湿度检测 | 获取温湿度检测数据 | 2 | 定时器 |
| TASK_ID_TVOC | VOC 检测 | 获取 VOC 检测数据 | 3 | 定时器 |
| TASK_ID_BAT | 电池检测 | 检测电池的充电状态与电池电量 | 4 | 定时器 |
核心任务代码逻辑解析
主调度逻辑
主函数通过 “获取下一个高优先级任务→执行任务→状态重置” 的循环,实现任务调度,核心逻辑如下:
void start_kernel(void)
{
board_init();
task_init();
time_init();
device_on();
while (1)
{
switch (task_getNextPriority())
{
case TASK_ID_POWER:
powerOnHandle();
break;
case TASK_ID_KEY:
keyHandle();
break;
case TASK_ID_SHT21:
Get_TempHum();
break;
case TASK_ID_TVOC:
Get_Tvoc();
break;
case TASK_ID_BAT:
Check_Charge_Bat();
break;
case TASK_ID_DISP:
//bat_pic(3,50, pow_bat[1]);
break;
default:
task_restoreAll();
if (IDLE_PRI == task_getNextPriority())
{
sleep_cpu();
}
break;
}
}
}
电源键检测
当按下电源按键后,会通过中断触发 TASK_ID_POWER 任务
如果在电源关闭的状态下按下:该任务中会先延迟 3 s 后再次判断该按键是否保持按下状态,如果保持按钮下状态则设置相应的引脚和标志位;
如果在电源开启的状态下按下:该任务中会先延迟 5 s 后再次判断该按键是否保持按下状态,如果保持按钮下状态则设置相应的引脚和标志位;
void powerOnHandle(void)
{
static bool flag = false;
if(!powerOn){
if(!flag){
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)!=RESET) {
time_create(TASK_ID_POWER, 3000, &flag, true);
} else {
time_cancel(TASK_ID_POWER);
}
} else {
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)!=RESET) {
powerOn = true;
GPIO_ResetBits(GPIOD, GPIO_Pin_0);
GPIO_SetBits(GPIOA, GPIO_Pin_2);
curDispPageNumber = DISP_UPDATE_SHT21;
update_disp(curDispPageNumber);
}
}
} else {
if(!flag){
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)!=RESET) {
time_create(TASK_ID_POWER, 5000, &flag, true);
} else {
time_cancel(TASK_ID_POWER);
}
} else {
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)!=RESET) {
powerOn = false;
GPIO_SetBits(GPIOD, GPIO_Pin_0);
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
curDispPageNumber = DISP_UPDATE_POWER_OFF;
update_disp(curDispPageNumber);
}
}
}
task_setBlock(TASK_ID_POWER);
flag = false;
return;
}
温度检测任务
当温湿度传感器初始化时,会启动一个定时器。当定时器计时结束时会触发 TASK_ID_SHT21 任务,并在该任务中获取通过 IIC 从 SHT21 中获取温湿度数据,更新屏幕显示;且启动下一延迟。
void Get_TempHum(void)
{
if(flag){
flag = false;
Get_TempHum_1();
update_disp(DISP_UPDATE_SHT21);
time_create(TASK_ID_SHT21, DELAY_MS, &flag, true);
}
task_setBlock(TASK_ID_SHT21);
}
Chaos-nano 操作系统在开发中带来的优势
由于使用的是 8 位单片机所以产品最初是使用的是传统的软件开发方式;在 Chaos-nano 操作系统被开发后,使用 Chaos-nano 操作系统对该项目进行了重构。
新旧软件代码对比
以下代码时传统模式开发中的按键处理部分:
void KeyHandle()
{
OLED_CLS();
while(1)
{
if(Sleeping==0){
if(PowerStatus==ENABLE) //表示开机
{
Delay(3000);
Check_Charge_Bat();
Dis_Bat();
if(page_nums==0) {//显示温度
my_page = 3;
Delay(1000);
if(FlagChange == ENABLE) //按下S2翻页
{
page_nums=1;
OLED_CLS();
Dis_Uin();
FlagChange=DISABLE;
}
Get_TempHum();
Check_Charge_Bat();
Dis_Bat();
//OLED 显示
Dis_Data(page_nums);
}else if(page_nums==1) {//显示RH
my_page = 0;
Delay(1000);
if(FlagChange == ENABLE)
{
page_nums=2;
OLED_CLS();
Check_Charge_Bat();
FlagChange=DISABLE;
}
Get_TempHum();
Check_Charge_Bat();
//OLED 显示
Dis_Data(page_nums);
}else if(page_nums==3) {//显示TVOC
my_page = 2;
Delay(1000);
if(FlagChange == ENABLE)
{
page_nums=0;
OLED_CLS();
FlagChange=DISABLE;
}
Get_Tvoc();
//OLED 显示
Dis_Data(page_nums);
}else if(page_nums==2) {//显示OC2
my_page = 1;
Delay(1000);
if(FlagChange == ENABLE)
{
page_nums=3;
OLED_CLS();
Check_Charge_Bat();
FlagChange=DISABLE;
}
Check_Charge_Bat();
Get_Tvoc();
//OLED 显示
Dis_Data(page_nums);
}
} else if(PowerStatus==DISABLE)//充电状态关机
{
Delay(3000);
if(FlagS==ENABLE){
FlagChange=DISABLE;
page_nums=0;
FlagS=DISABLE;
//关闭OLED屏幕
OLED_CLS();
}
}
}
ScreenDispose();
}
}
使用 Chaos-nano 操作系统后的代码
void keyHandle(void)
{
if(!powerOn)
return;
curDispPageNumber = (curDispPageNumber == DISP_UPDATE_SHT21) ? DISP_UPDATE_TVOC : DISP_UPDATE_SHT21;
OLED_CLS();
update_disp(DISP_UPDATE_BAT);
update_disp(curDispPageNumber);
task_setBlock(TASK_ID_KEY);
}
void update_disp(enum disp_update_t disp_update_number)
{
switch(disp_update_number){
case DISP_UPDATE_SHT21:
{
if(disp_update_number != curDispPageNumber)
return;
//显示温湿度
... ...
}
break;
case DISP_UPDATE_TVOC:
{
uint16_t Tvocmg_L = 0;
uint16_t eCO2PPM = 0;
if(disp_update_number != curDispPageNumber)
return;
//显示甲醛和空气质量
... ...
}
break;
case DISP_UPDATE_BAT:
{
if( (curDispPageNumber == DISP_UPDATE_SHT21) || (curDispPageNumber == DISP_UPDATE_TVOC) ){
Dis_Bat(true);
} else {
Dis_Bat(false);
}
}
break;
case DISP_UPDATE_POWER_OFF:
{
OLED_CLS();
Dis_Bat(true);
}
break;
}
}
传统开发模式带来的问题:
逻辑冗余且耦合度极高
代码将按键检测、页面切换、数据采集(温湿度、TVOC)、OLED 显示、电池检测等功能 “堆叠” 在一个无限循环中,各模块职责边界模糊。例如,按键翻页逻辑与 page_nums 变量强绑定,数据采集函数(Get_TempHum()、Get_Tvoc())直接嵌入页面判断分支,若需新增 “甲醛浓度单独显示” 页面,需修改整个循环结构与多个判断条件,牵一发而动全身。
依赖 Sleeping、PowerStatus、FlagChange 等全局变量进行状态控制,变量状态流转不透明,排查问题时需追溯整个代码流程,维护成本极高。
阻塞式设计影响用户体验
代码中大量使用 Delay(1000)、Delay(3000) 等阻塞延时函数,期间 CPU 无法响应其他操作。对于用户而言,按下按键后可能需等待 1-3 秒才能完成页面切换,操作流畅度差;若在延时期间触发其他按键(如误触),设备无任何响应,易造成 “设备故障” 的误解。
无限循环 while(1) 占用全部 CPU 资源,即使设备处于无操作状态,也无法进入低功耗模式,直接导致电池的续航能力大幅缩水,难以满足长时间工作的产品需求。
扩展性差,适配需求变更成本高
页面切换逻辑通过 page_nums 的多分支 if-else 实现,若需新增检测参数(如温湿度、TVOC 之外增加 PM2.5 显示),需新增 page_nums 枚举值、扩展判断分支、修改翻页逻辑,代码量呈线性增长,且容易引入逻辑错误。
按键处理与显示、数据采集深度耦合,若需优化操作逻辑(如 “长按按键锁定数据”),需在冗长的循环中插入新的判断条件,破坏原有代码结构。
使用 Chaos-nano 操作系统后的代码优势
模块化拆分,职责单一清晰
将原代码拆分为 “按键处理(keyHandle())” 与 “显示更新(update_disp())” 两大独立模块,按键仅负责触发页面切换,显示仅负责根据页面类型更新内容,数据采集可独立封装为任务,各模块通过 curDispPageNumber 枚举变量通信,职责边界明确。
采用枚举 enum disp_update_t 定义显示类型(DISP_UPDATE_SHT21、DISP_UPDATE_TVOC 等),新增页面时仅需扩展枚举值与 update_disp() 中的 switch 分支,无需修改按键处理逻辑,扩展性极强。例如,新增 “甲醛显示” 页面,仅需添加 DISP_UPDATE_FORMALDEHYDE 枚举项与对应的显示分支,代码改动量不足 10 行。
非阻塞式设计,适配特殊群体操作需求
彻底摒弃阻塞延时,借助 Chaos-nano 的任务调度机制实现异步处理。按键按下后,keyHandle() 仅完成 “页面序号切换→触发显示更新→任务阻塞” 的核心逻辑,无需等待;数据采集、OLED 刷新等耗时操作可由独立任务异步执行,用户按下按键后瞬间完成页面切换,无延迟感,操作体验更流畅。
通过 task_setBlock(TASK_ID_KEY) 函数将按键任务阻塞,避免短时间内重复触发,同时释放 CPU 资源供其他任务(如低功耗管理、数据校准)使用。配合 Chaos-nano 的低功耗调度,设备无操作时可快速进入休眠模式,最大化延长电池的续航时间。
状态管理透明,维护效率大幅提升
页面状态通过 curDispPageNumber 枚举变量统一管理,取值范围明确(仅对应已定义的显示类型),避免了裸机代码中全局变量状态混乱的问题。例如,update_disp() 函数通过判断枚举值直接定位显示逻辑,无需追溯全局变量的修改记录。
逻辑分支从 4 个 if-else 简化为 1 个 switch 语句,可读性极强。开发人员无需理解复杂的循环嵌套与延时逻辑,即可快速定位问题或进行功能扩展,大幅缩短产品迭代周期。
低耦合设计,适配产品功能迭代
按键处理与数据采集、显示逻辑完全解耦。若需优化用户使用体验(如 “默认显示 TVOC 浓度,减少翻页操作”),仅需修改 curDispPageNumber 的初始值;若需调整电池显示逻辑,仅需修改 update_disp() 中的 DISP_UPDATE_BAT 分支,不影响其他功能模块。
依托 Chaos-nano 的任务管理能力,可轻松新增独立任务(如 “低电量报警”“一键校准”),无需担心与原有按键、显示逻辑冲突。例如,新增 “校准任务” 时,仅需创建新任务并添加新功能的代码,原有代码无需改动。
Chaos-nano 带来的核心价值总结
对于本项目而言,Chaos-nano 不仅是 “让代码更简洁”,更是通过架构革新实现了三大核心价值:
1. 提升产品易用性
非阻塞式设计消除了按键操作的延迟感,模块化逻辑保障了设备运行的稳定性,让老人与孕妇 “一键操作、即刻响应” 的核心需求得到充分满足,降低了特殊群体的使用门槛。
2. 降低开发与维护成本,加速产品迭代
简洁的代码结构、清晰的模块划分,让开发人员无需花费大量时间梳理逻辑关系,新增功能、修改需求时的代码改动量减少 60% 以上,显著缩短产品开发周期与维护成本。
3. 释放硬件潜力,保障核心产品特性
Chaos-nano 的低功耗调度机制,配合非阻塞式代码设计,同时确保设备体积小巧、重量轻盈,完美实现 “极致便携 + 长续航” 的产品定位。
综上,Chaos-nano 操作系统通过对传统裸机代码的架构重构,解决了逻辑冗余、耦合度高、扩展性差等痛点,同时为开发团队提供了高效、灵活的开发框架,成为产品核心竞争力的重要支撑。
代码位置:https://gitee.com/kongrong77/Chaos-nano/tree/main/examples/nose_chaos_nano

我要赚赏金
