嵌入式故障码管理系统设计实现
文章目录
- 前言
- 一、故障码管理系统概述
- 二、核心数据结构设计
- 2.1 故障严重等级定义
- 2.2 模块 ID 定义
- 2.3 故障代码结构
- 2.4 故障记录结构
- 三、故障管理核心功能实现
- 3.1 初始化功能
- 3.2 故障记录功能
- 3.3 记录查询与清除功能
- 3.4 系统自检功能
- 四、故障存储实现
- 4.1 Flash 存储实现
- 4.2 RAM 存储实现
- 五、测试案例
- 六、源码
- 6.1 fault_manager.c
- 6.2 fault_manager.h
- 6.3 fault_storage.h
- 6.4 fault_storage_flash.c
- 6.5 fault_storage_ram.c
- 6.6 example_usage
前言
在嵌入式系统开发中,故障管理是保障系统稳定运行的关键一环。当系统出现异常时,及时准确地记录和处理故障信息,不仅有助于快速定位问题,还能为系统的优化和维护提供重要依据。本文将基于一套实际的嵌入式故障码管理系统代码,详细介绍其设计思路与实现方法。
一、故障码管理系统概述
该故障码管理系统旨在为嵌入式设备提供全面的故障记录、存储与处理能力。它能够记录系统运行过程中出现的各种故障,包括不同模块产生的不同类型故障,并根据故障的严重程度进行分类处理。同时,系统还支持故障记录的存储、查询、清除以及自检等功能,确保故障信息的完整性和准确性。
故障码管理系统主要分为两大模块:
-
FaultManager(故障管理器)
负责对外提供初始化、记录故障、查询故障、清除故障、系统自检等功能接口,并维护内部状态(如是否已初始化、已记录故障数量等)。 -
FaultStorage(故障存储)
提供对故障记录的持久化后端支持,可根据需求选择 Flash 存储或 RAM 环境下的环形/数组存储实现。包含初始化、添加记录、获取记录、删除记录和清空记录等操作。
两者通过明确定义的接口契约解耦,FaultManager 不关心底层存储细节,只要调用 FaultStorage_* 系列接口即可。
设计特点:
-
多级分类:支持Info/Warning/Error/Critical四级故障
-
模块化设计:各功能模块独立,便于扩展
-
双存储引擎:RAM缓存+Flash持久化
-
低资源占用:适合资源受限的MCU环境
二、核心数据结构设计
2.1 故障严重等级定义
typedef enum {FAULT_SEVERITY_INFO = 0, // 信息类故障FAULT_SEVERITY_WARNING, // 警告类故障FAULT_SEVERITY_ERROR, // 错误类故障FAULT_SEVERITY_CRITICAL // 严重故障
} FaultSeverity_t;
通过枚举类型定义了故障的四种严重等级。信息类故障用于提示系统的一般运行信息,如软件版本更新提示;警告类故障表示系统出现潜在问题,如磁盘空间即将不足;错误类故障会导致部分功能失效,如网络连接中断;严重故障则可能危及系统安全,如电源电压骤降,为后续分级处理故障提供了清晰标准。
2.2 模块 ID 定义
typedef enum {FAULT_MODULE_SYSTEM = 0, // 系统模块FAULT_MODULE_POWER, // 电源模块FAULT_MODULE_COMM, // 通信模块FAULT_MODULE_SENSOR, // 传感器模块FAULT_MODULE_ACTUATOR, // 执行器模块FAULT_MODULE_CUSTOM // 自定义模块
} FaultModule_t;
该枚举类型明确标识了嵌入式系统中常见的故障模块。不同模块对应不同的硬件或软件功能单元,例如电源模块负责供电,通信模块处理数据传输,传感器模块采集环境数据等,使得故障定位更具针对性。
2.3 故障代码结构
typedef union {uint32_t code;struct {uint16_t module_id : 8; // 模块IDuint16_t error_id : 8; // 错误IDuint16_t severity : 4; // 严重等级uint16_t reserved : 12; // 保留位} fields;
} FaultCode_t;
采用联合体与结构体结合的设计,code 作为一个 32 位整数可整体存储和传输故障码,fields 结构体则将其拆分为具体信息。8 位的模块 ID 能区分多达 256 种不同模块,8 位的错误 ID 可定义 256 种具体错误类型,4 位的严重等级对应前述四种故障级别,12 位保留位为未来功能扩展预留空间。
2.4 故障记录结构
typedef struct {FaultCode_t fault_code; // 故障代码uint32_t timestamp; // 时间戳(ms)uint8_t context[4]; // 上下文数据
} FaultRecord_t;
FaultRecord_t 结构体完整描述一次故障。fault_code 包含故障的类型和严重程度信息;timestamp 基于系统时钟获取故障发生的精确时刻,单位为毫秒,便于分析故障发生的时序;context 数组存储与故障相关的额外数据,如传感器的异常读数、通信数据包片段等,为故障分析提供更丰富的细节。
三、故障管理核心功能实现
3.1 初始化功能
bool FaultManager_Init(void)
{if (fm_state.initialized) {return true;}// 初始化存储子系统if (!FaultStorage_Init()) {return false;}// 获取记录数量fm_state.record_count = FaultStorage_GetRecordCount();fm_state.initialized = true;return true;
}
FaultManager_Init 函数首先检查系统是否已经初始化,如果已初始化则直接返回 true。接着调用 FaultStorage_Init 函数初始化故障存储子系统,若初始化失败则返回 false。成功初始化存储子系统后,获取已有的故障记录数量,并将系统初始化状态标志 fm_state.initialized 设置为 true,最后返回 true 表示初始化成功。
3.2 故障记录功能
void FaultManager_LogFault(FaultCode_t code, const uint8_t* context)
{if (!fm_state.initialized) {return;}FaultRecord_t record;record.fault_code = code;record.timestamp = HAL_GetTick(); // 假设使用HAL库if (context != NULL) {memcpy(record.context, context, sizeof(record.context));} else {memset(record.context, 0, sizeof(record.context));}// 存储记录if (FaultStorage_AddRecord(&record)) {fm_state.record_count++;}// 根据故障等级处理switch (code.fields.severity) {case FAULT_SEVERITY_CRITICAL:// 严重故障可能需要系统复位break;case FAULT_SEVERITY_ERROR:// 错误处理逻辑break;default:break;}
}
FaultManager_LogFault 函数用于记录故障信息。首先检查系统是否已经初始化,若未初始化则直接返回。然后创建一个 FaultRecord_t 类型的变量 record,将传入的故障代码 code 和当前时间戳(通过 HAL_GetTick 函数获取)赋值给 record。如果存在上下文数据,则将其复制到 record.context 中;否则将 record.context 清零。接着调用 FaultStorage_AddRecord 函数将故障记录存储到存储系统中,如果存储成功则更新故障记录数量。最后根据故障的严重程度,在 switch 语句中执行相应的处理逻辑,对于严重故障可能需要考虑系统复位等操作,对于其他故障可进行相应的错误处理。
3.3 记录查询与清除功能
uint16_t FaultManager_GetRecordCount(void)
{return fm_state.record_count;
}bool FaultManager_GetRecord(uint16_t index, FaultRecord_t* record)
{if (!fm_state.initialized || record == NULL) {return false;}if (index >= fm_state.record_count) {return false;}return FaultStorage_GetRecord(index, record);
}void FaultManager_ClearAllRecords(void)
{if (!fm_state.initialized) {return;}FaultStorage_ClearAll();fm_state.record_count = 0;
}
FaultManager_GetRecordCount 函数直接返回当前已记录的故障数量。FaultManager_GetRecord 函数用于获取指定索引的故障记录,首先检查系统是否初始化以及传入的记录指针是否有效,然后判断索引是否越界,若都满足条件则调用 FaultStorage_GetRecord 函数从存储系统中获取记录。FaultManager_ClearAllRecords 函数用于清除所有故障记录,同样先检查系统初始化状态,然后调用 FaultStorage_ClearAll 函数清除存储系统中的所有记录,并将记录数量清零。
3.4 系统自检功能
bool FaultManager_SelfTest(void)
{if (!fm_state.initialized) {return false;}// 测试存储系统FaultRecord_t test_record = {.fault_code = {.fields = {.module_id = FAULT_MODULE_SYSTEM,.error_id = 0xFF,.severity = FAULT_SEVERITY_INFO}},.timestamp = HAL_GetTick(),.context = {0xAA, 0x55, 0xAA, 0x55}};uint16_t old_count = fm_state.record_count;// 添加测试记录FaultManager_LogFault(test_record.fault_code, test_record.context);// 验证记录FaultRecord_t read_record;if (!FaultManager_GetRecord(old_count, &read_record)) {return false;}// 比较记录内容if (memcmp(&test_record, &read_record, sizeof(FaultRecord_t)) != 0) {return false;}// 恢复原始状态FaultStorage_DeleteRecord(old_count);fm_state.record_count = old_count;return true;
}
FaultManager_SelfTest 函数用于对故障管理系统进行自检。先检查系统是否初始化,若未初始化则返回 false。创建一个测试用的 FaultRecord_t 类型变量 test_record,设置好故障代码、时间戳和上下文数据。记录下当前的故障记录数量 old_count,然后调用 FaultManager_LogFault 函数添加测试记录。接着尝试获取刚刚添加的测试记录,如果获取失败则返回 false。将获取到的记录与测试记录进行内容比较,如果不一致也返回 false。最后删除测试记录,恢复原始的记录数量,并返回 true 表示自检通过。
四、故障存储实现
4.1 Flash 存储实现
bool FaultStorage_Init(void)
{// 检查Flash是否为空uint32_t addr = FLASH_BASE_ADDR;storage_state.record_count = 0;while (addr < FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {uint32_t value = *(__IO uint32_t*)addr;if (value == 0xFFFFFFFF) {break;}storage_state.record_count++;addr += RECORD_SIZE;}storage_state.next_write_addr = FLASH_BASE_ADDR + (storage_state.record_count * RECORD_SIZE);return true;
}
FaultStorage_Init 函数用于初始化 Flash 存储。通过遍历 Flash 存储区域,检查每个记录存储单元的值,如果值为 0xFFFFFFFF(表示未使用)则停止遍历,同时记录已有的记录数量 record_count,并计算出下一个可写入地址 next_write_addr。
bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || storage_state.record_count >= MAX_RECORDS) {return false;}// 如果需要擦除扇区if (storage_state.next_write_addr >= FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {FLASH_EraseInitTypeDef erase = {.TypeErase = FLASH_TYPEERASE_SECTORS,.Sector = FLASH_SECTOR,.NbSectors = 1,.VoltageRange = FLASH_VOLTAGE_RANGE_3};uint32_t sector_error;HAL_FLASH_Unlock();if (HAL_FLASHEx_Erase(&erase, §or_error) != HAL_OK) {HAL_FLASH_Lock();return false;}storage_state.next_write_addr = FLASH_BASE_ADDR;storage_state.record_count = 0;}// 写入FlashHAL_FLASH_Unlock();uint32_t src = (uint32_t)record;uint32_t dst = storage_state.next_write_addr;uint32_t remaining = RECORD_SIZE;while (remaining > 0) {if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, dst, *(uint32_t*)src) != HAL_OK) {HAL_FLASH_Lock();return false;}dst += 4;src += 4;remaining -= 4;}HAL_FLASH_Lock();storage_state.record_count++;storage_state.next_write_addr += RECORD_SIZE;return true;
}
FaultStorage_AddRecord 函数用于向 Flash 存储中添加故障记录。首先检查传入的记录指针是否有效以及存储记录数量是否达到上限,若不满足条件则返回 false。然后判断是否需要擦除扇区(当达到存储区域末尾时),如果需要则进行扇区擦除操作,擦除成功后更新存储状态。接着进行数据写入操作,将故障记录按字写入 Flash,写入过程中若出现错误则立即锁定 Flash 并返回 false。成功写入后更新记录数量和下一个写入地址,并返回 true。
4.2 RAM 存储实现
bool FaultStorage_Init(void)
{memset(&ram_storage, 0, sizeof(ram_storage));return true;
}
FaultStorage_Init 函数对于 RAM 存储的初始化非常简单,直接使用 memset 函数将存储状态结构体 ram_storage 清零即可。
bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || ram_storage.record_count >= MAX_RAM_RECORDS) {return false;}memcpy(&ram_storage.records[ram_storage.next_index], record, sizeof(FaultRecord_t));ram_storage.next_index = (ram_storage.next_index + 1) % MAX_RAM_RECORDS;if (ram_storage.record_count < MAX_RAM_RECORDS) {ram_storage.record_count++;}return true;
}
FaultStorage_AddRecord 函数向 RAM 存储中添加故障记录。同样先检查记录指针有效性和存储数量上限,然后将记录复制到 ram_storage.records 数组的当前写入位置,更新写入索引 next_index,并根据记录数量是否达到上限决定是否增加记录数量,最后返回 true 表示添加成功。
五、测试案例
#include "fault_manager.h"void example_usage(void)
{// 初始化故障管理系统FaultManager_Init();// 记录一个电源模块的警告故障FaultCode_t power_warning = {.fields = {.module_id = FAULT_MODULE_POWER,.error_id = 0x01, // 假设0x01表示电压低.severity = FAULT_SEVERITY_WARNING}};uint8_t context[] = {0x0C, 0x22, 0x00, 0x00}; // 12.34VFaultManager_LogFault(power_warning, context);// 记录一个通信模块的错误故障FaultCode_t comm_error = {.fields = {.module_id = FAULT_MODULE_COMM,.error_id = 0x02, // 假设0x02表示超时.severity = FAULT_SEVERITY_ERROR}};FaultManager_LogFault(comm_error, NULL);// 查询并打印所有故障记录uint16_t count = FaultManager_GetRecordCount();for (uint16_t i = 0; i < count; i++) {FaultRecord_t record;if (FaultManager_GetRecord(i, &record)) {printf("[%lu] Module:%d, Error:%d, Sev:%d\n",record.timestamp,record.fault_code.fields.module_id,record.fault_code.fields.error_id,record.fault_code.fields.severity);}}
}
在 example_usage 测试函数中,首先调用 FaultManager_Init 函数初始化故障管理系统。接着模拟两个故障场景:记录一个电源模块的警告故障,设置故障代码表示电源模块电压低,同时提供包含电压数据的上下文信息;记录一个通信模块的错误故障,设置故障代码表示通信超时,未提供上下文数据。最后通过 FaultManager_GetRecordCount 和 FaultManager_GetRecord 函数查询并打印所有故障记录,直观展示故障记录功能的有效性,验证系统能够准确记录和查询故障信息,确保故障管理系统在实际应用中的可靠性。
谢谢你的翻阅,希望可以对你有所帮助!
六、源码
6.1 fault_manager.c
#include "fault_manager.h"
#include "fault_storage.h"
#include <string.h>// 内部状态
static struct {bool initialized;uint16_t record_count;
} fm_state;// 初始化故障管理系统
bool FaultManager_Init(void)
{if (fm_state.initialized) {return true;}// 初始化存储子系统if (!FaultStorage_Init()) {return false;}// 获取记录数量fm_state.record_count = FaultStorage_GetRecordCount();fm_state.initialized = true;return true;
}// 记录故障
void FaultManager_LogFault(FaultCode_t code, const uint8_t* context)
{if (!fm_state.initialized) {return;}FaultRecord_t record;record.fault_code = code;record.timestamp = HAL_GetTick(); // 假设使用HAL库if (context != NULL) {memcpy(record.context, context, sizeof(record.context));} else {memset(record.context, 0, sizeof(record.context));}// 存储记录if (FaultStorage_AddRecord(&record)) {fm_state.record_count++;}// 根据故障等级处理switch (code.fields.severity) {case FAULT_SEVERITY_CRITICAL:// 严重故障可能需要系统复位break;case FAULT_SEVERITY_ERROR:// 错误处理逻辑break;default:break;}
}// 获取故障记录数量
uint16_t FaultManager_GetRecordCount(void)
{return fm_state.record_count;
}// 获取指定索引的故障记录
bool FaultManager_GetRecord(uint16_t index, FaultRecord_t* record)
{if (!fm_state.initialized || record == NULL) {return false;}if (index >= fm_state.record_count) {return false;}return FaultStorage_GetRecord(index, record);
}// 清除所有故障记录
void FaultManager_ClearAllRecords(void)
{if (!fm_state.initialized) {return;}FaultStorage_ClearAll();fm_state.record_count = 0;
}// 系统自检
bool FaultManager_SelfTest(void)
{if (!fm_state.initialized) {return false;}// 测试存储系统FaultRecord_t test_record = {.fault_code = {.fields = {.module_id = FAULT_MODULE_SYSTEM,.error_id = 0xFF,.severity = FAULT_SEVERITY_INFO}},.timestamp = HAL_GetTick(),.context = {0xAA, 0x55, 0xAA, 0x55}};uint16_t old_count = fm_state.record_count;// 添加测试记录FaultManager_LogFault(test_record.fault_code, test_record.context);// 验证记录FaultRecord_t read_record;if (!FaultManager_GetRecord(old_count, &read_record)) {return false;}// 比较记录内容if (memcmp(&test_record, &read_record, sizeof(FaultRecord_t)) != 0) {return false;}// 恢复原始状态FaultStorage_DeleteRecord(old_count);fm_state.record_count = old_count;return true;
}
6.2 fault_manager.h
#ifndef FAULT_MANAGER_H
#define FAULT_MANAGER_H#include <stdint.h>
#include <stdbool.h>#ifdef __cplusplus
extern "C" {
#endif// 故障严重等级定义
typedef enum {FAULT_SEVERITY_INFO = 0, // 信息类故障FAULT_SEVERITY_WARNING, // 警告类故障FAULT_SEVERITY_ERROR, // 错误类故障FAULT_SEVERITY_CRITICAL // 严重故障
} FaultSeverity_t;// 模块ID定义
typedef enum {FAULT_MODULE_SYSTEM = 0, // 系统模块FAULT_MODULE_POWER, // 电源模块FAULT_MODULE_COMM, // 通信模块FAULT_MODULE_SENSOR, // 传感器模块FAULT_MODULE_ACTUATOR, // 执行器模块FAULT_MODULE_CUSTOM // 自定义模块
} FaultModule_t;// 故障代码结构
typedef union {uint32_t code;struct {uint16_t module_id : 8; // 模块IDuint16_t error_id : 8; // 错误IDuint16_t severity : 4; // 严重等级uint16_t reserved : 12; // 保留位} fields;
} FaultCode_t;// 故障记录结构
typedef struct {FaultCode_t fault_code; // 故障代码uint32_t timestamp; // 时间戳(ms)uint8_t context[4]; // 上下文数据
} FaultRecord_t;// 初始化故障管理系统
bool FaultManager_Init(void);// 记录故障
void FaultManager_LogFault(FaultCode_t code, const uint8_t* context);// 获取故障记录数量
uint16_t FaultManager_GetRecordCount(void);// 获取指定索引的故障记录
bool FaultManager_GetRecord(uint16_t index, FaultRecord_t* record);// 清除所有故障记录
void FaultManager_ClearAllRecords(void);// 系统自检
bool FaultManager_SelfTest(void);#ifdef __cplusplus
}
#endif#endif // FAULT_MANAGER_H
6.3 fault_storage.h
#ifndef FAULT_STORAGE_H
#define FAULT_STORAGE_H#include "fault_manager.h"#ifdef __cplusplus
extern "C" {
#endif// 初始化存储系统
bool FaultStorage_Init(void);// 添加故障记录
bool FaultStorage_AddRecord(const FaultRecord_t* record);// 获取故障记录数量
uint16_t FaultStorage_GetRecordCount(void);// 获取指定索引的故障记录
bool FaultStorage_GetRecord(uint16_t index, FaultRecord_t* record);// 删除指定索引的故障记录
bool FaultStorage_DeleteRecord(uint16_t index);// 清除所有故障记录
void FaultStorage_ClearAll(void);#ifdef __cplusplus
}
#endif#endif // FAULT_STORAGE_H
6.4 fault_storage_flash.c
#include "fault_storage.h"
#include "stm32f4xx_hal.h" // 根据实际MCU修改
#include <string.h>// Flash存储配置
#define FLASH_SECTOR FLASH_SECTOR_6
#define FLASH_BASE_ADDR 0x08040000 // 假设使用Sector 6
#define MAX_RECORDS 100 // 最大记录数
#define RECORD_SIZE sizeof(FaultRecord_t)// 存储状态
static struct {uint16_t record_count;uint32_t next_write_addr;
} storage_state;// 初始化Flash存储
bool FaultStorage_Init(void)
{// 检查Flash是否为空uint32_t addr = FLASH_BASE_ADDR;storage_state.record_count = 0;while (addr < FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {uint32_t value = *(__IO uint32_t*)addr;if (value == 0xFFFFFFFF) {break;}storage_state.record_count++;addr += RECORD_SIZE;}storage_state.next_write_addr = FLASH_BASE_ADDR + (storage_state.record_count * RECORD_SIZE);return true;
}// 添加记录到Flash
bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || storage_state.record_count >= MAX_RECORDS) {return false;}// 如果需要擦除扇区if (storage_state.next_write_addr >= FLASH_BASE_ADDR + (MAX_RECORDS * RECORD_SIZE)) {FLASH_EraseInitTypeDef erase = {.TypeErase = FLASH_TYPEERASE_SECTORS,.Sector = FLASH_SECTOR,.NbSectors = 1,.VoltageRange = FLASH_VOLTAGE_RANGE_3};uint32_t sector_error;HAL_FLASH_Unlock();if (HAL_FLASHEx_Erase(&erase, §or_error) != HAL_OK) {HAL_FLASH_Lock();return false;}storage_state.next_write_addr = FLASH_BASE_ADDR;storage_state.record_count = 0;}// 写入FlashHAL_FLASH_Unlock();uint32_t src = (uint32_t)record;uint32_t dst = storage_state.next_write_addr;uint32_t remaining = RECORD_SIZE;while (remaining > 0) {if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, dst, *(uint32_t*)src) != HAL_OK) {HAL_FLASH_Lock();return false;}dst += 4;src += 4;remaining -= 4;}HAL_FLASH_Lock();storage_state.record_count++;storage_state.next_write_addr += RECORD_SIZE;return true;
}// 获取记录数量
uint16_t FaultStorage_GetRecordCount(void)
{return storage_state.record_count;
}// 从Flash获取记录
bool FaultStorage_GetRecord(uint16_t index, FaultRecord_t* record)
{if (index >= storage_state.record_count || record == NULL) {return false;}uint32_t addr = FLASH_BASE_ADDR + (index * RECORD_SIZE);memcpy(record, (void*)addr, RECORD_SIZE);return true;
}// 删除记录(Flash中不支持单独删除,只能全部擦除)
bool FaultStorage_DeleteRecord(uint16_t index)
{// Flash实现中不支持单独删除return false;
}// 清除所有记录
void FaultStorage_ClearAll(void)
{FLASH_EraseInitTypeDef erase = {.TypeErase = FLASH_TYPEERASE_SECTORS,.Sector = FLASH_SECTOR,.NbSectors = 1,.VoltageRange = FLASH_VOLTAGE_RANGE_3};uint32_t sector_error;HAL_FLASH_Unlock();HAL_FLASHEx_Erase(&erase, §or_error);HAL_FLASH_Lock();storage_state.record_count = 0;storage_state.next_write_addr = FLASH_BASE_ADDR;
}
6.5 fault_storage_ram.c
#include "fault_storage.h"
#include <string.h>// RAM存储配置
#define MAX_RAM_RECORDS 50 // RAM中最大记录数// 存储状态
static struct {FaultRecord_t records[MAX_RAM_RECORDS];uint16_t record_count;uint16_t next_index;
} ram_storage;// 初始化RAM存储
bool FaultStorage_Init(void)
{memset(&ram_storage, 0, sizeof(ram_storage));return true;
}// 添加记录到RAM
bool FaultStorage_AddRecord(const FaultRecord_t* record)
{if (record == NULL || ram_storage.record_count >= MAX_RAM_RECORDS) {return false;}memcpy(&ram_storage.records[ram_storage.next_index], record, sizeof(FaultRecord_t));ram_storage.next_index = (ram_storage.next_index + 1) % MAX_RAM_RECORDS;if (ram_storage.record_count < MAX_RAM_RECORDS) {ram_storage.record_count++;}return true;
}// 获取记录数量
uint16_t FaultStorage_GetRecordCount(void)
{return ram_storage.record_count;
}// 从RAM获取记录
bool FaultStorage_GetRecord(uint16_t index, FaultRecord_t* record)
{if (index >= ram_storage.record_count || record == NULL) {return false;}uint16_t actual_index;if (ram_storage.record_count < MAX_RAM_RECORDS) {actual_index = index;} else {actual_index = (ram_storage.next_index + index) % MAX_RAM_RECORDS;}memcpy(record, &ram_storage.records[actual_index], sizeof(FaultRecord_t));return true;
}// 删除RAM中的记录
bool FaultStorage_DeleteRecord(uint16_t index)
{if (index >= ram_storage.record_count) {return false;}if (ram_storage.record_count < MAX_RAM_RECORDS) {// 简单数组,移动后面的元素for (uint16_t i = index; i < ram_storage.record_count - 1; i++) {memcpy(&ram_storage.records[i], &ram_storage.records[i + 1], sizeof(FaultRecord_t));}} else {// 环形缓冲区,实现更复杂// 这里简化处理,不支持删除return false;}ram_storage.record_count--;return true;
}// 清除所有RAM记录
void FaultStorage_ClearAll(void)
{ram_storage.record_count = 0;ram_storage.next_index = 0;
}
6.6 example_usage
#include "fault_manager.h"void example_usage(void)
{// 初始化故障管理系统FaultManager_Init();// 记录一个电源模块的警告故障FaultCode_t power_warning = {.fields = {.module_id = FAULT_MODULE_POWER,.error_id = 0x01, // 假设0x01表示电压低.severity = FAULT_SEVERITY_WARNING}};uint8_t context[] = {0x0C, 0x22, 0x00, 0x00}; // 12.34VFaultManager_LogFault(power_warning, context);// 记录一个通信模块的错误故障FaultCode_t comm_error = {.fields = {.module_id = FAULT_MODULE_COMM,.error_id = 0x02, // 假设0x02表示超时.severity = FAULT_SEVERITY_ERROR}};FaultManager_LogFault(comm_error, NULL);// 查询并打印所有故障记录uint16_t count = FaultManager_GetRecordCount();for (uint16_t i = 0; i < count; i++) {FaultRecord_t record;if (FaultManager_GetRecord(i, &record)) {printf("[%lu] Module:%d, Error:%d, Sev:%d\n",record.timestamp,record.fault_code.fields.module_id,record.fault_code.fields.error_id,record.fault_code.fields.severity);}}
}
相关文章:
嵌入式故障码管理系统设计实现
文章目录 前言一、故障码管理系统概述二、核心数据结构设计2.1 故障严重等级定义2.2 模块 ID 定义2.3 故障代码结构2.4 故障记录结构 三、故障管理核心功能实现3.1 初始化功能3.2 故障记录功能3.3 记录查询与清除功能3.4 系统自检功能 四、故障存储实现4.1 Flash 存储实现4.2 R…...
若依框架Consul微服务版本
1、最近使用若依前后端分离框架改造为Consul微服务版本 在这里分享出来供大家参考 # Consul微服务配置参数已经放置/bin/Consul微服务配置目录 仓库地址: gitee:https://gitee.com/zlxls/Ruoyi-Consul-Cloud.git gitcode:https://gitcode.c…...
【风控】用户特征画像体系
一、体系架构概述 1.1 核心价值定位 风控特征画像体系是通过多维度数据融合分析,构建客户风险全景视图的智能化工具。其核心价值体现在: 全周期覆盖:贯穿客户生命周期的营销、贷前、贷中、贷后四大场景立体化刻画:整合基础数据…...
【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 目录 引言设计一个共享数据中心选择数据模型键值对设计 数据可靠性设计持久化快照 (…...
数据库--向量化基础
本文包含内容有: 向量化、SIMD的概念及关系SSE,AVX-512八种基础的SIMD操作,并用具体例子解释,给出伪代码。一、快速了解向量化、SIMD 1.1 向量化 向量化是指将原本需要循环处理的多个数据元素,通过一条指令同时处理多个数据,从而减少循环次数,提高计算效率。 传统方式…...
handsome主题美化及优化:10.1.0最新版 - 2
文章目录 前言基础设置优化开启全站 HTTPS添加 GZIP 压缩美化永久链接自定义后台路径启用 Emoji 支持 功能增强每日新闻自动更新文章嵌入外部网页时光机栏目配置自定义音乐播放器音量 自定义CSS配置文章标题居中显示标题背景美化文章版式优化LOGO 扫光特效头像动画效果图片悬停…...
JWT令牌
1. JWT概述 JWT即JSON Web Token,是一个开放标准,用于在各方之间安全地传输信息。并且JWT经过数字签名,安全性高。通俗来说,也就是以JSON形式作为Web应用中的令牌,用于信息传输,在数据传输过程中可以完成数…...
Qwen3技术报告解读
https://github.com/QwenLM/Qwen3/blob/main/Qwen3_Technical_Report.pdf 节前放模型,大晚上的发技术报告。通义,真有你的~ 文章目录 预训练后训练Long-CoT Cold StartReasoning RLThinking Mode FusionGeneral RLStrong-to-Weak Distillation 模型结构…...
RAG-MCP:突破大模型工具调用瓶颈,告别Prompt膨胀
大语言模型(LLM)的浪潮正席卷全球,其强大的自然语言理解、生成和推理能力,为各行各业带来了前所未有的机遇。然而,正如我们在之前的探讨中多次提及,LLM并非万能。它们受限于训练数据的时效性和范围…...
Flask框架入门与实践
Flask框架入门与实践 Flask是一个轻量级的Python Web框架,以其简洁、灵活和易于上手的特点深受开发者喜爱。本文将带您深入了解Flask的核心概念、基本用法以及实际应用。 什么是Flask? Flask是由Armin Ronacher于2010年开发的微型Web框架。与Django等…...
PD 分离推理的加速大招,百度智能云网络基础设施和通信组件的优化实践
为了适应 PD 分离式推理部署架构,百度智能云从物理网络层面的「4us 端到端低时延」HPN 集群建设,到网络流量层面的设备配置和管理,再到通信组件和算子层面的优化,显著提升了上层推理服务的整体性能。 百度智能云在大规模 PD 分离…...
罗杰斯高频板技术解析:低损耗基材如何定义 5G 通信未来
在 5G 通信与尖端电子技术加速融合的时代,高频 PCB 作为信号传输的核心载体,对材料性能与工艺精度提出了极致要求。猎板 PCB 深耕行业多年,始终以罗杰斯(Rogers)板材为核心介质,构建起从材料适配到精密制造…...
QML 动画控制、顺序动画与并行动画
目录 引言相关阅读基础属性说明工程结构示例代码解析示例1:手动控制动画(ControlledAnimation.qml)示例2:顺序动画(SequentialAnimationDemo.qml)示例3:并行动画(ParallelAnimationD…...
【动态导通电阻】GaN HEMT动态导通电阻的精确测量
2023 年 7 月,瑞士洛桑联邦理工学院的 Hongkeng Zhu 和 Elison Matioli 在《IEEE Transactions on Power Electronics》期刊发表了题为《Accurate Measurement of Dynamic ON-Resistance in GaN Transistors at Steady-State》的文章,基于提出的稳态测量方法,研究了氮化镓(…...
2:OpenCV—加载显示图像
加载和显示图像 从文件和显示加载图像 在本节中,我将向您展示如何使用 OpenCV 库函数从文件加载图像并在窗口中显示图像。 首先,打开C IDE并创建一个新项目。然后,必须为 OpenCV 配置新项目。 #include <iostream> #include <ope…...
Qt控件:交互控件
交互控件 1. QAction核心功能API 1.2 实例应用情况应用场景 1. QAction ##1. 1简介与API QAction 是一个核心类,用于表示应用程序中的一个操作(如菜单项、工具栏按钮或快捷键触发的功能)。它将操作的逻辑与 UI 表现分离,使代码更…...
在vue3中使用Cesium的保姆教程
1. 软件下载与安装 1. node安装 Vue.js 的开发依赖于 Node.js 环境,因此我们首先需要安装 Node.js。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它允许你在服务器端运行 JavaScript 代码,同时也为前端开发提供了强大的工具支…...
zst-2001 下午题-历年真题 试题一到三
试题一 问题一 1 问题一 2 注意每句话中的“给”… 问题一 3 问题二 1 问题二 2 问题二 3 问题三 1 步骤一.看父图的数据流在子图有没有缺失 步骤二.看加工有没有输入输出 步骤三.阅读理解 问题三 2 实体和存储不能划线 问题三 3 试题二 问题一 1 问题一 2 问题一 3 问题二…...
STM32的ADC模块中,**采样时机(Sampling Time)**和**转换时机(Conversion Time),获取数据的时机详解
在STM32的ADC模块中,**采样时机(Sampling Time)和转换时机(Conversion Time)**是ADC工作流程中的两个关键阶段,直接影响采样精度和系统实时性。以下是详细解析: 1. 采样时机(Samplin…...
iOS音视频解封装分析
首先是进行解封装的简单的配置 /// 解封装配置 class KFDemuxerConfig {// 媒体资源var asset: AVAsset?// 解封装类型,指定是音频、视频或两者都需要var demuxerType: KFMediaType .avinit() {} }然后是实现解封装控制器 import Foundation import CoreMedia i…...
探究电阻分压的带负载能力
我们经常使用两个电阻去分压来获得特定的电压,那么我是两个大阻值电阻分压获得的电压驱动能力强,还是小阻值电阻分压得到的电压驱动能力强呢? 一、电压相同时,电流的大小 下面是两个阻值分压得到的仿真图 电路分析: VCC都是5V,探针1和探针2测到的电压都是1.67V; 根据…...
14、Python时间表示:Unix时间戳、毫秒微秒精度与time模块实战
适合人群:零基础自学者 | 编程小白快速入门 阅读时长:约5分钟 文章目录 一、问题:计算机中的时间的表示、Unix时间点?1、例子1:计算机的“生日”:Unix时间点2、答案:(1)U…...
PCL 绘制二次曲面
文章目录 一、简介二、实现代码三、实现效果一、简介 这里基于二次曲面的公式: z = a 0 + a 1 x + a 2 y + a...
消息队列与Kafka基础:从概念到集群部署
目录 一、消息队列 1.什么是消息队列 2.消息队列的特征 3.为什么需要消息队列 二、Kafka基础与入门 1.Kafka基本概念 2.Kafka相关术语 3.Kafka拓扑架构 4.Topic与partition 5.Producer生产机制 6.Consumer消费机制 三、Zookeeper概念介绍 1.zookeeper概述 2.zooke…...
计算机指令分类和具体的表示的方式
1.关于计算机的指令系统 下面的这个就是我们的一个简单的计算机里面涉及到的指令: m就是我们的存储器里面的地址,可以理解为memory这个意思,r可以理解为rom这样的单词的首字母,帮助我们去进行这个相关的指令的记忆,不…...
pcie phy-电气层-gen1/2(TX)
S IP物理层讲解 在synopsys IP中对于phy层的内容分离的比较多: cxpl中: u_cx_phy_logical:包含ts序列的解析(smlh); pipe层协议的转换(rmlh,xmlh);pipe转dllp包(rplh&…...
Baklib加速企业AI数据智理转型
Baklib智理AI数据资产 在AI技术深度渗透业务场景的背景下,Baklib通过构建企业级知识中台架构,重塑了数据资产的治理范式。该平台采用智能分类引擎与语义分析模型,将分散在邮件、文档、数据库中的非结构化数据转化为标准化的知识单元…...
深度学习驱动下的目标检测技术:原理、算法与应用创新
一、引言 1.1 研究背景与意义 目标检测作为计算机视觉领域的核心任务之一,旨在识别图像或视频中感兴趣目标的类别,并确定其在图像中的位置,通常以边界框(Bounding Box)的形式表示 。其在现实生活中有着极为广泛且…...
window 显示驱动开发-使用有保证的协定 DMA 缓冲区模型
Windows Vista 的显示驱动程序模型保证呈现设备的 DMA 缓冲区和修补程序位置列表的大小。 修补程序位置列表包含 DMA 缓冲区中命令引用的资源的物理内存地址。 在有保证的协定模式下,用户模式显示驱动程序知道 DMA 缓冲区和修补程序位置列表的确切大小,…...
《指针与整数相加减的深入解析》
🚀个人主页:BabyZZの秘密日记 📖收入专栏:C语言 🌍文章目入 一、指针与整数相加的原理二、指针与整数相减的原理三、使用场景(一)数组操作(二)内存遍历 四、注意事项&…...
C++_STL_map与set
1. 关联式容器 在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、 forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 存储的是元素本身。那什么是…...
1949-2022年各省农作物播种面积数据(22个指标)
1949-2022年各省农作物播种面积数据(22个指标) 1、时间:1949-2022年 2、来源:各省年鉴、国家统计局、农业部、农业年鉴 3、范围:31省 4、指标:年度标识、省份编码、省份名称、农作物总播种面积、粮食作…...
汽车二自由度系统模型以及电动助力转向系统模型
汽车二自由度系统模型与电动助力转向系统(EPS)的详细建模方案,包含理论推导、MATLAB/Simulink实现代码及参数说明: 一、二自由度汽车模型 1. 模型描述 包含以下两个自由度: 横向运动(侧向加速度…...
【学习笔记】计算机操作系统(四)—— 存储器管理
第四章 存储器管理 文章目录 第四章 存储器管理4.1 存储器的层次结构4.1.1 多层结构的存储器系统4.1.2 主存储器与寄存器4.1.3 高速缓存和磁盘缓存 4.2 程序的装入和链接4.2.1 程序的装入4.2.2 程序的链接 4.3 连续分配存储管理方式4.3.1 单一连续分配4.3.2 固定分区分配4.3.3 …...
51单片机的lcd12864驱动程序
#include <reg51.h> #include <intrins.h>#define uchar...
(03)数字化转型之库存管理:从进库到出库的数字化运营
在当今竞争激烈的商业环境中,高效的库存管理已成为企业降低成本、提高运营效率的关键。本文将系统性地介绍库存管理的全流程,包括进库、出库、移库、盘点等核心环节,帮助企业构建科学合理的库存管理体系。 一、进库管理:从计划到执…...
windows编程中加载DLL的两种典型方式的比较
文章目录 DLL定义头文件定义CPP实现DLL的调用代码直接使用通过LoadLibrary调用导入表的依赖LoadLibrary使用DLL库中的类DLL中定义工厂函数调用时的代码补充:为什么LoadLibrary不能直接导出类在windows的编程中,使用DLL是一个非常常见的操作。一般来说,有两种集成DLL的方式:…...
存储器上如何存储1和0
在计算机存储器中,数据最终以**二进制形式(0和1)**存储,这是由硬件特性和电子电路的物理特性决定的。以下是具体存储方式的详细解析: 一、存储的物理基础:半导体电路与电平信号 计算机存储器(…...
【笔记】记一次PyCharm的问题反馈
#工作记录 最近更新至 PyCharm 社区版的最新版本后,我遇到了多个影响使用体验的问题。令人感到不便的是,一些在旧版本中非常便捷的功能,在新版本中却变得操作复杂、不够直观。过去,我一直通过 PyCharm 内置的故障报告与反馈机制反…...
logrotate按文件大小进行日志切割
✅ 编写logrotate文件,进行自定义切割方式 adminip-127-0-0-1:/data/test$ cat /etc/logrotate.d/test /data/test/test.log {size 1024M #文件达到1G就切割rotate 100 #保留100个文件compressdelaycompressmissingoknotifemptycopytruncate #这个情况服务不用…...
基于大模型的脑出血智能诊疗与康复技术方案
目录 一、术前阶段1.1 数据采集与预处理系统伪代码实现流程图1.2 特征提取与选择模块伪代码实现流程图1.3 大模型风险评估系统伪代码实现流程图二、术中阶段2.1 智能手术规划系统伪代码实现流程图2.2 麻醉智能监控系统伪代码实现流程图三、术后阶段3.1 并发症预测系统伪代码片段…...
P21-RNN-心脏病预测
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、RNN 循环神经网络(Recurrent Neural Network,简称 RNN)是一类以序列数据为输入,在序列的演进方向进行递归…...
懒汉式单例模式的线程安全实现
懒汉式单例模式的线程安全实现 懒汉式单例模式的核心特点是延迟实例化(在第一次使用时创建对象),但其基础实现存在线程安全问题。以下是不同线程安全实现方式的详细说明和对比: 1. 非线程安全的基础懒汉式 public class UnsafeLazySingleton {private static UnsafeLazyS…...
Java 常用的Arrays函数
文章目录 ArrayssorttoStringbinarySearchequalsfill 数组拷贝copyOfcopyOfRangearraycopy 二维数组定义遍历deepToString空指针异常 Arrays sort int[] array new int[]{1,20,3}; Arrays.sort(array);// 1 3 20toString 帮助数组转为字符串 int[] array new int[]{1,2,3…...
FEKO许可证与版本兼容性问题
随着电磁仿真技术的不断进步,FEKO软件不断更新迭代,为用户提供更强大的功能和更优秀的性能。然而,在升级过程中,FEKO许可证与版本兼容性问题往往成为用户关注的焦点。本文将为您详细解读FEKO许可证与版本兼容性问题,帮…...
HarmonyOs开发之——— ArkWeb 实战指南
HarmonyOs开发之——— ArkWeb 实战指南 谢谢关注!! 前言:上一篇文章主要介绍HarmonyOs开发之———合理使用动画与转场:CSDN 博客链接 一、ArkWeb 组件基础与生命周期管理 1.1 Web 组件核心能力概述 ArkWeb 的Web组件支持加载本地或在线网页,提供完整的生命周期回调体…...
冰箱磁力贴认证标准16CFR1262
在亚马逊平台,冰箱磁力贴这类可能被儿童接触到的产品,有着严格的规范哦。必须得遵守 16 CFR 1262 标准,还得有符合该标准的测试报告和 GCC 证书,不然产品就可能被禁止销售或者面临召回,那可就损失大啦! …...
Java中的锁机制全解析:从synchronized到分布式锁
在多线程编程中,锁是保证线程安全的核心工具。本文将详解Java中常见的锁机制及其实际应用场景,帮助开发者选择最合适的锁方案。 一、内置锁:synchronized 原理 通过JVM内置的监视器锁(Monitor)实现,可修…...
OptiStruct实例:3D实体转子分析
上一节介绍了1D转子的临界转速分析。在1D转子模型中,转子是以集中质量单元的形式建模的。此种建模方法不可避免地会带来一些简化和局部特征的缺失。接下来介绍OptiStruct3D实体转子的建模及临界转速分析实例。 3D实体转子建立详细的转子网格模型,然后将…...
简单记录坐标变换
以三维空间坐标系为例 rTt代表机械手末端相对robot root坐标系的变换关系 rTt dot p_in_tool 可以把tool坐标系下表示的某点转到root坐标系表示 其中rTt表示tool相对于root坐标系的平移和旋转 以二维图像坐标系为例说明 1坐标系定为图片坐标系左上角,横平竖直的…...