极物科技 | DALI协议栈 - EEPROM持久化机制
前言
在智能控制领域,"协议壁垒"与"系统稳定性"始终是绕不开的难题。极物科技(Zeewo)以 "重构空间交互体验" 为使命,通过自研的 极物 OS,实现了 KNX、DALI、CAN、RS485 等多种总线协议在单一主机上的深度融合。
我们认为,一个真正优秀的智能系统,不仅要实现灯光、遮阳、温控、音乐、安防等全生态设备的无界融合 ,更要确保本地运行、断网可用 ,并具备WEB 远程调试 和 OTA 固件升级的能力。基于此底层架构,我们推出了诸如带双路 DALI 的 KNX 主机、HomeKit 网桥等核心硬件,并将极物 OS 成功接入了 Apple HomeKit、小度、纯血鸿蒙及 HomeAssistant 等主流生态系统。
一句话概述:本文深入解析极物 DALI 协议栈 EEPROM 持久化机制,展示配置数据从 RAM 到 EEPROM 的完整保存与加载流程。
本文聚焦于 DALI 设备配置数据的持久化存储,涵盖数据加载、差异写入、更新标志管理(VAR_UPDATE/BANK0_UPDATE/BANK1_UPDATE)、数据校验、断电恢复等核心内容。通过源码级剖析,帮助读者理解 DALI 从设备如何实现可靠的非易失性数据存储。


1. EEPROM持久化概述
在DALI智能照明系统中,设备断电后需要保留关键配置信息(如短地址、分组、场景值、色温参数等),EEPROM(Electrically Erasable Programmable Read-Only Memory)是实现数据持久化的核心组件。
1.1 需要持久化的数据
根据DALI标准,以下数据必须保存到非易失性存储器:
| 数据类型 | 字段 | 说明 |
|---|---|---|
| 设备地址 | short_address |
0-63短地址或0xFF未寻址 |
| 分组信息 | group_0_7, group_8_15 |
16个分组归属 |
| 场景值 | scene[0-15] |
16个场景亮度值 |
| 系统参数 | power_on_level |
上电亮度 |
| 系统参数 | system_failure_level |
故障亮度 |
| 系统参数 | minimum_level |
最小亮度 |
| 系统参数 | maximum_level |
最大亮度 |
| 渐变参数 | fade_rate |
渐变率 |
| 渐变参数 | fade_time |
渐变时间 |
| DT8参数 | tc_scene[0-15] |
16个场景色温值 |
| DT8参数 | tc_powon_level |
上电色温 |
| DT8参数 | tc_config_maxcold_level |
配置最冷色温 |
| DT8参数 | tc_config_maxwarn_level |
配置最暖色温 |
1.2 EEPROM模块接口
c
// dali_eeprom.h - EEPROM模块接口
bool dali_load_from_eeprom(void); // 从EEPROM加载数据
void dali_update_to_eeprom(void); // 更新数据到EEPROM
void dali_eeprom_update_tick(void); // 触发更新
void dali_eeprom_init(void); // EEPROM初始化
二、数据加载机制
2.1 dali_load_from_eeprom
系统启动时从EEPROM加载持久化数据到RAM:
c
// dali_eeprom.c - 从EEPROM加载数据
bool dali_load_from_eeprom()
{
int i;
uint8_t flag[2];
uint8_t errom_data;
// 1. 获取DALI数据区大小和地址
g_dali_data_size = dali_get_data_size_from_stack();
g_dali_data_P = dali_get_data_addr_from_stack();
// 2. 检查EEPROM数据状态
if (eeprom_get_data_status() != 1) {
// printf("get eprom data error \r\n");
return false;
}
// 3. 从EEPROM读取数据到RAM
// 跳过DALI_DATA_NO_SAVE_INDEX+1之前的字节(不保存的数据)
for (i = DALI_DATA_NO_SAVE_INDEX + 1; i < g_dali_data_size; i++) {
*(g_dali_data_P + i) = eeprom_read_cache(i);
// printf("i %hx data %bx \r\n", i, *(g_dali_data_P + i));
}
return true;
}
2.2 数据区结构
c
// dali_top.h - 更新标志位定义
#define VAR_UPDATE (1 << 0) // DALI变量更新
#define BANK0_UPDATE (1 << 1) // Bank0更新
#define BANK1_UPDATE (1 << 2) // Bank1更新
数据区布局:
+------------------+------------------+------------------+
| 不保存的数据区 | Bank0数据区 | Bank1数据区 |
| (target_level等) | (场景/分组等) | (设备类型等) |
+------------------+------------------+------------------+
DALI_DATA_NO_SAVE_INDEX+1之前 需要持久化的数据
2.3 不保存的数据
部分运行时数据不需要保存到EEPROM:
c
// dali_cmd.h - 不保存数据索引
#define DALI_DATA_NO_SAVE_INDEX 1
struct var {
/* 以下数据不需要保存 */
uint8_t target_level; // 目标亮度(运行时)
uint8_t tc_target_level; // 目标色温(运行时)
uint8_t data_check_1; // 校验位
/* 以下数据需要保存 */
uint8_t power_on_level; // 上电亮度
uint8_t system_failure_level; // 故障亮度
// ... 其他持久化数据
};
三、数据更新机制
3.1 dali_update_to_eeprom
将RAM中的变更数据写回EEPROM:
c
// dali_eeprom.c - 更新数据到EEPROM
void dali_update_to_eeprom()
{
uint8_t i = 0;
uint8_t errom_data;
uint8_t count = 0;
// 1. 检查是否有更新标志
if (update_flag == 0) {
return; // 无更新,直接返回
}
printf("update_flag \r\n");
// 2. 逐字节比对并写入变更数据
for (i = DALI_DATA_NO_SAVE_INDEX + 1; i < g_dali_data_size; i++) {
// 头两个字节不保存
errom_data = eeprom_read_cache(i);
if (*(g_dali_data_P + i) != errom_data) {
eeprom_write_cache(i, *(g_dali_data_P + i));
}
}
// 3. 标记写入成功
eeprom_data_is_write_sucess();
// 4. 清除更新标志
update_flag = 0;
return;
}
3.2 更新触发时机
以下操作会设置update_flag触发EEPROM写入:
| 操作 | 设置的标志 | 说明 |
|---|---|---|
| 设置短地址 | BANK0_UPDATE |
地址分配完成 |
| 设置分组 | BANK0_UPDATE |
分组配置变更 |
| 设置场景 | BANK0_UPDATE |
场景值变更 |
| RESET命令 | `BANK0_UPDATE | BANK1_UPDATE` |
| 配置参数变更 | VAR_UPDATE |
亮度/色温等参数变更 |
示例:
c
// dali_cmd.c - SET SHORT ADDRESS命令
case PROGRAM_SHORT_ADDRESS:
if (repeat_flag == false) {
return RECEIVE_FIRST;
}
dali_ram.variable.short_address = dtr0;
update_flag |= BANK0_UPDATE; // 触发EEPROM更新
break;
// dali_cmd.c - SET SCENE命令
case STORE_DTR0_AS_SCENE0:
// ...
dali_ram.variable.scene[scene_index] = dtr0;
update_flag |= BANK0_UPDATE; // 触发EEPROM更新
break;
3.3 dali_eeprom_update_tick
立即触发EEPROM更新的接口:
c
// dali_eeprom.c - 触发EEPROM更新
void dali_eeprom_update_tick(void)
{
dali_update_to_eeprom();
return;
}
调用场景:
c
// dali_hal.c - HAL层保存持久化变量
void dali_hal_save_persistent_variables(void)
{
/* Execute update immediately */
dali_eeprom_update_tick();
}
四、EEPROM初始化
4.1 初始化标志
c
// dali_eeprom.h - EEPROM初始化成功标志
#define EEROM_DATA_INIT_SUCESS_DATA_1 0X55
#define EEROM_DATA_INIT_SUCESS_DATA_2 0XAA
4.2 初始化流程
c
// dali_eeprom.c - EEPROM初始化
void dali_eeprom_init()
{
// 1. 检查EEPROM是否已初始化
if (eeprom_get_data_status() != 1) {
// 2. 未初始化,执行初始化
eeprom_init();
// 3. 写入初始化成功标志
eeprom_write_cache(0, EEROM_DATA_INIT_SUCESS_DATA_1);
eeprom_write_cache(1, EEROM_DATA_INIT_SUCESS_DATA_2);
// 4. 标记写入成功
eeprom_data_is_write_sucess();
}
}
五、目标亮度特殊处理
5.1 读取目标亮度
c
// dali_eeprom.c - 从EEPROM读取目标亮度
uint8_t dali_read_target_level_from_eeprom(void)
{
// printf("\n");
return 1;
}
5.2 写入目标亮度
c
// dali_eeprom.c - 写入目标亮度到EEPROM
void dali_write_target_level_to_eeprom(uint8_t level)
{
// printf("\n");
return;
}
说明:这两个函数当前为占位实现,实际项目中可根据需求扩展。
六、数据校验机制
6.1 启动时校验
系统启动时检查EEPROM数据有效性:
c
// dali_eeprom.c - 加载数据时校验
bool dali_load_from_eeprom()
{
// 检查EEPROM数据状态
if (eeprom_get_data_status() != 1) {
return false;
}
// 加载数据...
return true;
}
6.2 写入时校验
写入完成后验证数据正确性:
c
// dali_eeprom.c - 更新数据后校验
void dali_update_to_eeprom()
{
// 写入数据...
// 标记写入成功(内部包含校验逻辑)
eeprom_data_is_write_sucess();
update_flag = 0;
}
七、EEPROM写入优化
7.1 差异写入
只写入变更的字节,减少EEPROM写入次数:
c
// dali_eeprom.c - 差异写入
for (i = DALI_DATA_NO_SAVE_INDEX + 1; i < g_dali_data_size; i++) {
errom_data = eeprom_read_cache(i);
if (*(g_dali_data_P + i) != errom_data) {
eeprom_write_cache(i, *(g_dali_data_P + i));
}
}
优势:
- 减少EEPROM写入次数,延长寿命
- 提高写入效率
- 降低功耗
7.2 批量写入
多个更新标志合并为一次写入:
c
// 多个操作触发更新
update_flag |= VAR_UPDATE; // 参数变更
update_flag |= BANK0_UPDATE; // Bank0变更
// 统一触发一次写入
dali_eeprom_update_tick();
八、数据持久化流程
8.1 完整流程图
系统启动
↓
EEPROM初始化检查
↓
dali_load_from_eeprom()
↓
检查EEPROM数据状态
↓
读取数据到RAM(跳过不保存区)
↓
数据校验
↓
dali_cmd_init() 初始化命令状态
↓
dali_cmd_init_check() 校验配置参数
↓
系统正常运行
↓
配置变更触发update_flag
↓
dali_eeprom_update_tick()
↓
dali_update_to_eeprom()
↓
差异比对,只写入变更字节
↓
eeprom_data_is_write_sucess()
↓
清除update_flag
8.2 断电恢复流程
设备上电
↓
EEPROM初始化
↓
dali_load_from_eeprom()
↓
恢复short_address
↓
恢复group_0_7, group_8_15
↓
恢复scene[0-15]
↓
恢复tc_scene[0-15]
↓
恢复power_on_level
↓
恢复system_failure_level
↓
恢复fade_rate, fade_time
↓
设备恢复到断电前状态
九、关键设计亮点
9.1 分层数据管理
+------------------+
| 运行时数据区 | ← 不保存到EEPROM
| (target_level) |
+------------------+
| Bank0数据区 | ← 保存到EEPROM
| (场景/分组/地址) |
+------------------+
| Bank1数据区 | ← 保存到EEPROM
| (设备类型/版本) |
+------------------+
9.2 标志位驱动更新
c
// 更新标志位
#define VAR_UPDATE (1 << 0) // 变量更新
#define BANK0_UPDATE (1 << 1) // Bank0更新
#define BANK1_UPDATE (1 << 2) // Bank1更新
// 设置更新标志
update_flag |= VAR_UPDATE;
// 检查并执行更新
if (update_flag != 0) {
dali_update_to_eeprom();
}
9.3 差异写入优化
c
// 只写入变更的字节
if (*(g_dali_data_P + i) != errom_data) {
eeprom_write_cache(i, *(g_dali_data_P + i));
}
9.4 立即更新接口
c
// HAL层提供立即更新接口
void dali_hal_save_persistent_variables(void)
{
dali_eeprom_update_tick();
}
十、应用场景
10.1 设备地址持久化
设备通过DALI总线分配短地址后,必须保存到EEPROM:
c
case PROGRAM_SHORT_ADDRESS:
if (repeat_flag == false) {
return RECEIVE_FIRST;
}
dali_ram.variable.short_address = dtr0;
update_flag |= BANK0_UPDATE; // 触发EEPROM更新
break;
10.2 场景值持久化
用户配置的场景值需要断电保存:
c
case STORE_DTR0_AS_SCENE0:
dali_ram.variable.scene[0] = dtr0;
update_flag |= BANK0_UPDATE; // 触发EEPROM更新
break;
10.3 DT8色温参数持久化
双色温设备的色温范围配置需要保存:
c
case SET_TC_MAX_COLD:
dali_ram.variable.tc_config_maxcold_level = dtr0;
update_flag |= VAR_UPDATE; // 触发EEPROM更新
break;
11. 总结
本文详细解析了DALI协议栈中EEPROM持久化机制的实现,涵盖:
- 数据加载机制:系统启动时从EEPROM加载数据到RAM
- 数据更新机制:运行时变更数据写回EEPROM
- 差异写入优化:只写入变更字节,延长EEPROM寿命
- 标志位驱动:VAR_UPDATE/BANK0_UPDATE/BANK1_UPDATE分层管理
- 数据校验:确保数据完整性和正确性
- 立即更新接口:HAL层提供dali_eeprom_update_tick()
通过本文的解析,读者可以深入理解DALI设备数据持久化的完整实现,为智能照明系统的开发提供技术参考。
关于极物科技(ZEEWO)
极物科技(Zeewo)致力于为用户提供智能控制系统及硬件产品。我们以总线系统为技术底座,以**"稳定、可靠、快速响应"**为产品底线,是国内少有的拥有 KNX、DALI 全套软硬件自主研发能力的厂商之一。
我们的核心能力:
- 系统架构:自研极物 OS,支持多协议无界融合(KNX/DALI/CAN/RS485/IP)。
- 核心硬件:带双路 DALI 的 KNX 主机、超薄全金属定制面板、各类智选传感器及网关。
- 生态互联:深度融入 Apple HomeKit、Matter、小度、HomeAssistant 及纯血鸿蒙生态。
- 调试交付:独家支持 ETS 导出 XML 直接导入进行 APP 免编程调试,支持远程 WEB 运维。
我们的市场覆盖:
服务网点已覆盖全国核心城市(含长三角、珠三角、成渝等),并以高品质的方案深耕家居生活、酒店民宿、企业办公、疗愈康养、餐馆会所等多个细分领域。
(如果您在开发或落地中遇到技术问题,欢迎通过官网或后台私信与我交流探讨)

