单片机日志记录系统

单片机日志系统架构

说明: 日志记录系统按照API封装的思想只在接口文件中保留功能性程序,及 init ,set ,get;存储器使用华邦的w25q64,最低擦除的为1个sector(4096Bytes);日志系统主要分为三个部分 1、日志索引 ,2、断电日志存储区,3、日志存储区

1、日志索引:

为了避免对单个地址持续擦写造成块损坏,日志索引使用两个sector作为日志的索引存储区,日志索引每写一次地址增加16字节。当开机初始化的时候按照一定的方法将最新的索引页读取出来,用于对日志记录的地址进行记录。

2、断电日志

为了能够记录断电瞬间设备的运行情况,需要存储数据到断电日志区,等待下次开机后将断电日志记录到日志中。然后将断电日志区的数据擦除。

3、日志存储区

目前设计的是4096条日志数据,每条日志占用空间为64Bytes,考虑到增加器件寿命,每次写sector到的起始地址时将该sector擦除,然后将日志总长度减 64.

代码实现

mod_logSysInfo.h

/**
*****************************************************************************
* @文  件: mod_logSysInfo.h 
* @作  者: 00Jackey
* @版  本: V1.0.0
* @日  期: 5-Jun-2018
* @描  述: 日志信息系统接口文件
******************************************************************************
* @修改记录:
*   2018/06/05:初始版本
*    
*
******************************************************************************
**/

#ifndef _MOD_LOGSYSINFO_H_
#define _MOD_LOGSYSINFO_H_

#ifdef _cplusplus
	extern "C" {
#endif

//C库
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

//宏定义
#define LOG_INDEX_TOTAL        	   (uint32_t)(15)
#define EACH_INDEX_SPACE           (uint32_t)(16)

#define LOG_CONTENT_TOTAL          (uint32_t)(52)
#define EACH_LOG_SPACE             (uint32_t)(64)

#define LOG_INFO_TOTAL_CNT         (uint32_t)(4096)

#define LOG_WRITE_FLAG             (uint8_t)(0xA5)
		
//定义枚举
typedef enum {
    LOG_NOT_USE = 0, 
    LOG_BE_WRITE = 1, 
    LOG_BE_READ = 2
}LOG_OPERATE_STATE_ENUM;

typedef enum{
	LOG_PROC_SUCCEED = 0,
	LOG_PROC_FAILED = 1
}LOG_PROC_STATE_ENUM;

//定义结构体
typedef struct{
	uint8_t dateArry[LOG_CONTENT_TOTAL];
	uint32_t curNum;
	uint32_t curTime;
	uint16_t length;
	uint8_t  verifyVal;
	uint8_t  writeFlag;
}LOG_CONTENT_STRUCT;

//定义联合体
typedef union{
	LOG_CONTENT_STRUCT ContentStruct;
	uint8_t ConentArry[EACH_LOG_SPACE];
}LOG_CONTENT_UNION;

//定义结构体
typedef struct{
	uint32_t curIndex;
	uint32_t cntTotal;
    uint32_t rawTotal;
	uint8_t  useless[3]; 	
	uint8_t  writeFlag;
}LOG_INDEX_STRUCT;

//定义联合体
typedef union{
	LOG_INDEX_STRUCT IndexStruct;
	uint8_t IndexArry[LOG_INDEX_TOTAL+1];
}LOG_INDEX_UNION;

//函数封装
typedef struct
{
	LOG_PROC_STATE_ENUM (*init)(void);
	LOG_PROC_STATE_ENUM (*record)(LOG_CONTENT_UNION uLogInfoUnion);
	LOG_PROC_STATE_ENUM (*getRecent)(LOG_CONTENT_UNION* pLogInfoUnion, int32_t recentNum);
    LOG_PROC_STATE_ENUM (*getSerial)(LOG_CONTENT_UNION* pLogInfoUnion, int32_t serialNum);
}LOG_SYS_CONTENT_STRUCT;

typedef struct
{
	LOG_PROC_STATE_ENUM (*clr)(void);
	LOG_PROC_STATE_ENUM (*set)(LOG_CONTENT_UNION  uLogInfoUnion);
	LOG_PROC_STATE_ENUM (*get)(LOG_CONTENT_UNION* pLogInfoUnion);
}LOG_SYS_OUTAGE_STRUCT;

typedef struct
{
	LOG_OPERATE_STATE_ENUM   LogOperateFlag;  //日志读、写、空闲状态

	LOG_SYS_OUTAGE_STRUCT 	 OutageStruct;  //断电日志封装
	LOG_SYS_CONTENT_STRUCT   ContentStruct; //主日志封装

	LOG_PROC_STATE_ENUM (*init)(void);  //日志系统初始化
	
	uint32_t (*getRawTotal)(void);  //获取日志数量
}LOG_SYS_INFO_STRUCT;


//外部调用
extern LOG_SYS_INFO_STRUCT LogSysInfoStruct;


#ifdef _cplusplus
	}
#endif

#endif

mod_logSysInfo.c

/**
*****************************************************************************
* @文  件: mod_logSysInfo.c 
* @作  者: 00Jackey
* @版  本: V1.0.0
* @日  期: 6-Jun-2018
* @描  述: 日志信息系统主文件
******************************************************************************
* @修改记录:
*   2018/06/06:初始版本,待通信完成后做完整性测试
*   2018/07/01:做完完整性测试,改了一些问题 
*
******************************************************************************
**/

//接口头文件
#include "mod_logSysInfo.h"

//硬件驱动
#include "hardware.h"

//宏定义
#define CHIPSET_PAGE               (uint32_t)256
#define CHIPSET_SECTOR_SIZE		   (uint32_t)(CHIPSET_PAGE * 16)
#define CHIPSET_BLOCK_SIZE		   (uint32_t)(CHIPSET_SECTOR_SIZE * 16)
#define CHIPSET_TOTAL_SIZE		   (uint32_t)(CHIPSET_BLOCK_SIZE * 128)

#define LOG_SYS_OUTAGE_ADDRESS     (uint32_t)(CHIPSET_SECTOR_SIZE * 13)
#define LOG_SYS_INDEX_ADDRESS      (uint32_t)(CHIPSET_SECTOR_SIZE * 14)
#define LOG_SYS_INFO_ADDRESS       (uint32_t)(CHIPSET_SECTOR_SIZE * 16)

#define LOG_SYS_INFO_TOAL_SIZE     (uint32_t)(LOG_INFO_TOTAL_CNT * EACH_LOG_SPACE)

#define LOG_SYS_INDEX_TOAL_SIZE    (uint32_t)(CHIPSET_SECTOR_SIZE * 2)

#define LOG_SYS_WRITE				W25qxx_writeBuffer
#define LOG_SYS_READ				W25qxx_readBuffer
#define LOG_SYS_ERASE				W25qxx_eraseOneSector

#define LOG_INDEX_ADDR  			sLogIndexAddr




//静态函数
static LOG_PROC_STATE_ENUM LogSysInfo_initInfo(void);
static LOG_PROC_STATE_ENUM LogSysInfo_recordInfo(LOG_CONTENT_UNION uLogContentUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_getRecentInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t recentNum);
static LOG_PROC_STATE_ENUM LogSysInfo_getSerialInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t serialNum);

static LOG_PROC_STATE_ENUM LogSysInfo_initIndex(void);
static LOG_PROC_STATE_ENUM LogSysInfo_setIndex(LOG_INDEX_UNION uLogIndexUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_getIndex(LOG_INDEX_UNION* pLogIndexUnion);

static LOG_PROC_STATE_ENUM LogSysInfo_clrOutage(void);
static LOG_PROC_STATE_ENUM LogSysInfo_setOutage(LOG_CONTENT_UNION  uLogContentUnion);
static LOG_PROC_STATE_ENUM LogSysInfo_getOutage(LOG_CONTENT_UNION* pLogContentUnion);

static LOG_PROC_STATE_ENUM LogSysInfo_init(void);

static uint32_t LogSysInfo_getRawTotal(void);

static uint8_t LogSysInfo_calcXor8(uint8_t *pVarArry, uint8_t len);

//常量
const LOG_INDEX_UNION  cDefaultLogIndexUnion = {

	.IndexStruct.curIndex = (LOG_SYS_INFO_ADDRESS - EACH_LOG_SPACE),
    .IndexStruct.cntTotal = 0,
	.IndexStruct.rawTotal = 0,
    .IndexStruct.writeFlag = LOG_WRITE_FLAG,
};

//静态变量
LOG_INDEX_UNION sLogIndexUnion;
uint32_t sLogIndexAddr;

//全局变量
LOG_SYS_INFO_STRUCT LogSysInfoStruct = {

	.ContentStruct.init = LogSysInfo_initInfo,
    .ContentStruct.record = LogSysInfo_recordInfo,
    .ContentStruct.getRecent = LogSysInfo_getRecentInfo,
    .ContentStruct.getSerial = LogSysInfo_getSerialInfo,

    .OutageStruct.clr = LogSysInfo_clrOutage,
    .OutageStruct.set = LogSysInfo_setOutage,
    .OutageStruct.get = LogSysInfo_getOutage,

    .init = LogSysInfo_init,
	
	.getRawTotal = LogSysInfo_getRawTotal,
};



/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_init
*	功能说明: 日志系统初始化
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_init(void)
{
	if(LOG_PROC_FAILED == LogSysInfo_initIndex())
		return LOG_PROC_FAILED;
	else 
		return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_getRawTotal
*	功能说明: 获取日志中所存储的日志数量
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
uint32_t LogSysInfo_getRawTotal(void)
{
	return sLogIndexUnion.IndexStruct.rawTotal;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_initIndex
*	功能说明: 日志索引初始化
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_initIndex(void)
{
	
    LOG_PROC_STATE_ENUM rState;
	LOG_INDEX_UNION tLogIndexUnion;
	int32_t i_reord = -1;

	/* 遍历第一个块,判断每个位置是否都有写入标记*/
	for(int32_t i = 0; i < 256; i++){
		LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_SYS_INDEX_ADDRESS+(i*EACH_INDEX_SPACE),sizeof(LOG_INDEX_UNION));
		if(tLogIndexUnion.IndexArry[LOG_INDEX_TOTAL] == LOG_WRITE_FLAG){
			i_reord = i;
		}else{
			break;
		}
	}
	/* 如果255个位置中不全是有标志的,则提前当前位置的日志索引 */
	if((i_reord != 255)&&(i_reord != -1)){
		LOG_INDEX_ADDR =  LOG_SYS_INDEX_ADDRESS + (i_reord * EACH_INDEX_SPACE);
        LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
		memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
		LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS + CHIPSET_SECTOR_SIZE);
		return LOG_PROC_SUCCEED;
	}
	/* 遍历第二个块,判断每个位置是否都有写入标记*/
	for(int32_t i = 256; i < 512; i++){
		LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_SYS_INDEX_ADDRESS+(i*EACH_INDEX_SPACE),sizeof(LOG_INDEX_UNION));
		if(tLogIndexUnion.IndexArry[LOG_INDEX_TOTAL] == LOG_WRITE_FLAG){
			i_reord = i;
		}else{
			break;
		}
	}
	/* 如果255个位置中不全是有标志的,则提前当前位置的日志索引 */
	if((i_reord != 511)&&(i_reord != -1)){
		LOG_INDEX_ADDR =  LOG_SYS_INDEX_ADDRESS + (i_reord * EACH_INDEX_SPACE);
        LOG_SYS_READ(tLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
		memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
		LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS);
		return LOG_PROC_SUCCEED;
	}
	/* 如果两个块中都没有标记,则写入默认值 */
	if(i_reord == -1){
		LOG_SYS_WRITE((uint8_t*)cDefaultLogIndexUnion.IndexArry,LOG_SYS_INDEX_ADDRESS,sizeof(LOG_INDEX_UNION));
		rState = LogSysInfo_getIndex(&tLogIndexUnion);
		if(rState == LOG_PROC_FAILED){
			return LOG_PROC_FAILED;
		}else{
			memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
			return LOG_PROC_SUCCEED;
		}
	}
	/* 所有512个位置都有标记,则设定最后一个为索引存储位置 */
	LOG_INDEX_ADDR = LOG_SYS_INDEX_ADDRESS + (511 * EACH_INDEX_SPACE);
	memcpy(sLogIndexUnion.IndexArry,tLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
	LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS);

	return LOG_PROC_SUCCEED;

}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_setIndex
*	功能说明: 存储日志索引
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_setIndex(LOG_INDEX_UNION uLogIndexUnion)
{
	//memcpy(sLogIndexUnion.IndexArry,uLogIndexUnion.IndexArry,sizeof(LOG_INDEX_UNION));
	LOG_INDEX_ADDR = LOG_INDEX_ADDR + EACH_INDEX_SPACE;
	if(LOG_INDEX_ADDR >= (LOG_SYS_INDEX_ADDRESS + LOG_SYS_INDEX_TOAL_SIZE)){
		LOG_INDEX_ADDR = LOG_SYS_INDEX_ADDRESS;
		LOG_SYS_ERASE(LOG_SYS_INDEX_ADDRESS);
		LOG_SYS_WRITE(uLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
	}else{
		LOG_SYS_WRITE(uLogIndexUnion.IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
	}
	
	return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_getIndex
*	功能说明: 读取日志索引
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getIndex(LOG_INDEX_UNION* pLogIndexUnion)
{
	LOG_SYS_READ(pLogIndexUnion->IndexArry,LOG_INDEX_ADDR,sizeof(LOG_INDEX_UNION));
	if(pLogIndexUnion->IndexArry[LOG_INDEX_TOTAL] != LOG_WRITE_FLAG){
		return LOG_PROC_FAILED;
	}else{
		return LOG_PROC_SUCCEED;
	}
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_initInfo
*	功能说明: 日志系统读取掉电日志到正常日志中
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_initInfo(void)
{
	LOG_INDEX_UNION tLogIndexUnion;
	LOG_CONTENT_UNION  tLogOutageUnion;

	//1st: get the SYS_LOG_INDEX_ADDRESS page 
	LogSysInfo_getIndex(&tLogIndexUnion);
	//2nd: get the powerdown logging
	LogSysInfo_getOutage(&tLogOutageUnion);
	//3rd: write the log at the syslog
	if(tLogOutageUnion.ContentStruct.writeFlag == LOG_WRITE_FLAG){
		LogSysInfo_recordInfo(tLogOutageUnion);
	}else{
		/* warnning  --------------------*/
	}
	//4th: erase the power outage buff page
	LogSysInfo_clrOutage();
	
	return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_recordInfo
*	功能说明: 记录一条日志信息,索引更新
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_recordInfo(LOG_CONTENT_UNION uLogContentUnion)
{

	/*1st: According to index calculate the adress */
	sLogIndexUnion.IndexStruct.cntTotal += 1;
	sLogIndexUnion.IndexStruct.rawTotal = (sLogIndexUnion.IndexStruct.cntTotal >= LOG_INFO_TOTAL_CNT) ?\
		LOG_INFO_TOTAL_CNT : sLogIndexUnion.IndexStruct.cntTotal;
	sLogIndexUnion.IndexStruct.curIndex = (sLogIndexUnion.IndexStruct.cntTotal - 1)%\
        LOG_INFO_TOTAL_CNT * EACH_LOG_SPACE + LOG_SYS_INFO_ADDRESS;
	if(sLogIndexUnion.IndexStruct.curIndex >= (LOG_SYS_INFO_TOAL_SIZE + LOG_SYS_INFO_ADDRESS))
		sLogIndexUnion.IndexStruct.curIndex = LOG_SYS_INFO_ADDRESS;
	/* Earaze the sector , cut down the total log */
	if(0 == (sLogIndexUnion.IndexStruct.curIndex % CHIPSET_SECTOR_SIZE)){
		LOG_SYS_ERASE(sLogIndexUnion.IndexStruct.curIndex);
		sLogIndexUnion.IndexStruct.rawTotal -= (CHIPSET_SECTOR_SIZE / EACH_LOG_SPACE);
	}
	/*2nd: record the log index to eeprom */
    sLogIndexUnion.IndexStruct.writeFlag = LOG_WRITE_FLAG;
	LogSysInfo_setIndex(sLogIndexUnion);
	/*3rd: get the log number */
	uLogContentUnion.ContentStruct.curNum = sLogIndexUnion.IndexStruct.cntTotal;
	uLogContentUnion.ContentStruct.curTime = RTC_GetCounter();	//to update
	uLogContentUnion.ContentStruct.verifyVal = LogSysInfo_calcXor8(uLogContentUnion.ConentArry,LOG_CONTENT_TOTAL);
	uLogContentUnion.ContentStruct.writeFlag = LOG_WRITE_FLAG;
    /*4th: record the loginfo */
	LOG_SYS_WRITE(uLogContentUnion.ConentArry,sLogIndexUnion.IndexStruct.curIndex,EACH_LOG_SPACE);

	return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_getRecentInfo
*	功能说明: 获取最近某一条日志信息
*	形    参: pLogContentUnion:日志信息指针 recentNum: 0表示最近的日志,(0~LOG_INFO_TOTAL_CNT-1)
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getRecentInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t recentNum)
{
	int32_t tSysLogAddr = 0;

	/*Only more than need is ok*/
	if(sLogIndexUnion.IndexStruct.cntTotal <= recentNum){
		return LOG_PROC_FAILED;
	}
	
	/* Get the real index */
	tSysLogAddr = ((sLogIndexUnion.IndexStruct.cntTotal - recentNum - 1) % LOG_INFO_TOTAL_CNT) *\
		EACH_LOG_SPACE + LOG_SYS_INFO_ADDRESS;
	/* For protect , do not reach there */
	if(tSysLogAddr < LOG_SYS_INFO_ADDRESS){
		tSysLogAddr = LOG_SYS_INFO_TOAL_SIZE + LOG_SYS_INFO_ADDRESS - EACH_LOG_SPACE;
	}
	
	LOG_SYS_READ(pLogContentUnion->ConentArry,tSysLogAddr,EACH_LOG_SPACE);
	
	/* Judge the log info is right  */
	if(pLogContentUnion->ContentStruct.writeFlag == LOG_WRITE_FLAG)
		return LOG_PROC_SUCCEED;
	else
		return LOG_PROC_FAILED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_getSerialInfo
*	功能说明: 获取指定序号的日志
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getSerialInfo(LOG_CONTENT_UNION* pLogContentUnion, int32_t serNum)
{
	int32_t tSysLogAddr = 0x000000;
	int32_t tSysLogNum = 0;

	/*Only more than need is ok*/
	if(serNum <= 0){
		return LOG_PROC_FAILED;
	}
	
	if(sLogIndexUnion.IndexStruct.cntTotal < serNum){
		return LOG_PROC_FAILED;
	}
	
	tSysLogNum = serNum % LOG_INFO_TOTAL_CNT;
	tSysLogAddr = (tSysLogNum -1) * EACH_LOG_SPACE + LOG_SYS_INFO_ADDRESS; 

	LOG_SYS_READ(pLogContentUnion->ConentArry,tSysLogAddr,EACH_LOG_SPACE);
	
	/* Judge the log info is right  */
	if(pLogContentUnion->ContentStruct.writeFlag == LOG_WRITE_FLAG)
		return LOG_PROC_SUCCEED;
	else
		return LOG_PROC_FAILED;

}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_clrLogOutage
*	功能说明: 清楚掉电区日志数据
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_clrOutage(void)
{
	uint8_t tBytesFill[EACH_LOG_SPACE]= {0};
	
	LOG_SYS_WRITE(tBytesFill,LOG_SYS_OUTAGE_ADDRESS,EACH_LOG_SPACE);
	
	return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_setLogOutage
*	功能说明: 存储掉电数据
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_setOutage(LOG_CONTENT_UNION uLogContentUnion)
{
	LOG_SYS_WRITE(uLogContentUnion.ConentArry,LOG_SYS_OUTAGE_ADDRESS,EACH_LOG_SPACE);
	
	return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_getSerLogInfo
*	功能说明: 获取掉电数据
*	形    参: 无
*	返 回 值: 执行状态
*********************************************************************************************************
*/
LOG_PROC_STATE_ENUM LogSysInfo_getOutage(LOG_CONTENT_UNION* pLogContentUnion)
{
	LOG_SYS_READ(pLogContentUnion->ConentArry,LOG_SYS_OUTAGE_ADDRESS,EACH_LOG_SPACE);

	return LOG_PROC_SUCCEED;
}

/*
*********************************************************************************************************
*	函 数 名: LogSysInfo_calcXor8
*	功能说明: 计算校验值
*	形    参: pVarArry:需要校验的数组 len:数据长度
*	返 回 值: 执行状态
*********************************************************************************************************
*/
uint8_t LogSysInfo_calcXor8(uint8_t *pVarArry, uint8_t len)
{
	uint8_t rvalue;
	rvalue = pVarArry[0];

	for(uint8_t i = 1; i < len; i++){
		rvalue ^= pVarArry[i];
	}

	return rvalue;
}


<think>嗯,用户想了解单片机日志中实际记录的数据内容。这个问题很具体,看来用户正在开发或维护嵌入式系统,需要深入理解日志机制。从引用内容看,用户已经接触过日志系统的架构设计(引用1、2)、数据类型(引用3)和存储格式(引用4),现在更关注具体的数据层面。 用户可能是个嵌入式工程师,正在调试日志模块,或者需要基于现有日志做二次开发。ta的问题聚焦在“记录什么”而非“如何记录”,说明基础框架已搭建好,现在需要填充具体内容。这类需求通常出现在故障诊断或功能扩展场景中。 结合引用2的代码片段,日志数据明显分为元数据和业务数据两类: - 元数据是日志系统自己需要的管理信息,比如位置、时间戳、环形缓冲区状态等。这些在system_log_t和system_catalog_t结构体里有完整定义。 - 业务数据才是用户关心的核心,包括系统状态变量(电压、温度)、关键事件(复位、错误码)、操作行为(按键、通信)等。 特别注意到引用3提到u8/u16数据类型,这提示用户可能需要处理原始二进制日志。因此回答时要强调数据存储格式,比如多字节数据用大端序还是小端序,时间戳用32位还是64位表示等。 用户没有指定具体应用场景,但工业控制类日志往往侧重状态监测(如电机转速),而消费电子更关注交互事件(如触摸屏坐标)。需要提醒用户根据场景选择记录密度——高频数据可能只需记录异常值,低频操作则应全量记录。 安全相关数据容易被忽略,比如引用2的crc_val字段说明校验很重要。如果用户做的是医疗设备或车载系统,还要补充建议记录操作者ID或安全校验码等合规性内容。 最后考虑用户可能的后续问题:ta或许想知道如何平衡日志详细度和存储空间,或者需要实时传输日志的方案。所以在相关问题里预留了“优化存储空间”和“无线传输”的入口。</think>在单片机系统中,日志记录的数据内容通常分为**核心元数据**和**具体业务数据**两大类,具体内容如下: --- ### 一、核心元数据(日志系统自身管理) 1. **日志索引信息** - 日志ID(唯一标识,如 `uint32_t log_id`) - 存储地址(如 `uint32_t log_addr` 指向Flash/W25Q64物理位置) - 时间戳(记录生成时间,如 `time_t log_time`,精确到秒或毫秒) - 数据长度(如 `uint32_t log_offset`,单位字节) *引用自日志目录结构 `system_catalog_t` [^2]* 2. **系统状态参数** - 当前入位置(`uint32_t write_pos`,避免覆盖有效数据) - 目录项计数(`uint32_t catalog_num`) - 环形缓冲区状态(如 `uint8_t log_cyclic_status` 标记存储区循环入) - 最新日志时间(`time_t log_latest_time`) *引用自日志参数结构 `system_log_t` [^2]* 3. **数据完整性校验** - CRC校验值(如 `single_sav_t crc_val`,防止数据篡改或存储错误)[^2] --- ### 二、业务数据(根据应用场景定制) 1. **关键事件记录** - 系统启动/关机时间 - 硬件异常(如看门狗复位、内存溢出错误码) - 外部中断触发(按键、传感器信号) 2. **运行状态监控** - 电源参数:电池电压 $V_{bat}$、电流 $I$ - 环境数据:温度 $T$、湿度 $H$(通过ADC采集) - 通信状态:CAN/UART错误帧计数、丢包率 3. **操作行为追踪** ```c // 示例:记录用户操作事件 typedef struct { uint8_t event_id; // 事件类型(如按键ID) uint16_t param; // 附加参数(如长按时长) } user_event_t; ``` 4. **调试信息** - 函数调用栈(发生异常时保存) - 变量快照(如 `snapshot(uint8_t* var_addr, size_t size)`) - 断言失败位置(`assert()` 触发时的文件/行号) --- ### 三、数据存储格式示例 以华邦W25Q64 Flash存储为例(最小擦除单位4KB): ```plaintext | 日志索引区 (512B) | 断电保护区 (1KB) | 日志数据区 (3.5KB) | ``` - **索引区**:存储 `system_catalog_t` 数组,通过日志ID快速定位 - **断电保护区**:掉电前紧急保存的未完成日志(防止数据丢失) - **日志数据区**:按二进制或文本格式存储业务数据 > ⚠️ **注意事项** > 1. 时间戳通常用32位Unix时间戳(节省空间),如 `time_t = uint32_t` > 2. 多字节数据需统一字节序(如大端序存储) > 3. 字符串建议定长存储(如 `char msg[32]`)避免解析复杂度 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值