单片机存储 日志_单片机eeprom存储数据为什么与plc存储数据相差那么大 - CSDN
  • 单片机项目研究日志

    千次阅读 2013-12-31 11:54:02
    单片机的学习遇到了较大的问题:   编程方面:与已经学过的纯C相比,单片机的编程与硬件结合比较紧密,具体的:  (1)管脚接口这样的问题比较大  (2)用到的温度传感器等具体的器件还需进一步学习 驱动及...

    04.11

    单片机的学习遇到了较大的问题:

     

    编程方面:与已经学过的纯C相比,单片机的编程与硬件结合比较紧密,具体的:

                             (1)管脚接口这样的问题比较大

                             (2)用到的温度传感器等具体的器件还需进一步学习

    驱动及下载方面也存在较大问题:比如AVR的驱动和程序的烧录

      

    04.20

    收获:

    对温度传感器、液晶显示屏、数码管的工作原理、驱动程序有了进一步的了解,可以实现在1602液晶屏上显示检测到的温度,单片机的学习有一定进展。

     

    下一步工作:

         (1)对已经实现功能的程序做更深的研究、学习,从中总结规律、编程技巧;

          (2)用温湿度传感器代替温度传感器,编程实现在1602液晶屏上显示温湿度 ;

      

    5.11

       上次的目标已经解决:温湿度传感器已经可以把传感到的温湿度显示在单片机里。

     

    这次的成果:

          一:串口功能的实现 (1pl2303VCC需要接 

                         (2)液晶显示屏的接法:v0的接法 需要有电压差

          二:Labview与单片机的通信也已经基本实现,还需进一步完善学习

     下一步的计划:(1)复习总结已经做好的每一小步;

                  (2)综合! 将C程序写的更规范  labview编程

    6月 期末

    7月 大连实习

    8月 

     

       购买 二氧化碳传感器*2   光照传感器*2

       将1602显示屏换位彩屏显示,并完成后续的编程,完成中期检查报告

     

    成果:完成了以前程序的整合,并实现了用彩屏显示

    困难:对二氧化碳浓度和光照强度的值的读取遇到了较大的困难

       具体为:二氧化碳传感器模拟信号输出管脚的接法

               光照传感器购买失误 ,暂时使用学习板的光敏电阻     

     

    11

    11.13再次购买一些器件、报账、更换项目成员后重新开始下位机程序的编写

      完成了co2传感器、光照传感器的程序。下位机已有的程序基本完成。(11.13

    11.17中发市场、天作购买物品

         网上购买传感器等

         实现了上位机和下位机的通信,自动手动都可以调节

    下一步:完善下位机的调节功能

    12月:

    报账工作完成

    上位机功能和界面得到进一步完善

    下位机:增加红外遥控功能

            串口初始函数和接受数据的分配函数assign()进一步修改

            执行器的指示灯功能完成

    整体的调试

    下一步:书写结题报告、录制视频

    展开全文
  • 单片机日志记录系统

    千次阅读 2018-09-20 10:43:03
    单片机日志系统架构 说明:日志记录系统按照API封装的思想只在接口文件中保留功能性程序,及 init ,set ,get;存储器使用华邦的w25q64,最低擦除的为1个sector(4096Bytes);日志系统主要分为三个部分 1、日志索引...

    单片机日志系统架构

    说明: 日志记录系统按照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;
    }
    
    
    
    展开全文
  • FLASH日志文件系统设计

    千次阅读 2013-08-26 12:59:05
    大家都知道,目前主要流利的日志文件系统有JFFS,YAFFS等,这些都是目前在Linux中应用较多的日志文件系统。前期在做嵌入式方面的开发工作时,发现原来同事使用FLASH存储数据时使用了非常多的全局变量来保存FLASH的...

    写在前面

    大家都知道,目前主要流利的日志文件系统有JFFS,YAFFS等,这些都是目前在Linux中应用较多的日志文件系统。前期在做嵌入式方面的开发工作时,发现原来同事使用FLASH存储数据时使用了非常多的全局变量来保存FLASH的状态,同时在数据写入、读取和删除代码中又引用了大量的代码,感觉很乱。当时想,难道在ARM7上就没有一个好用的FLASH文件系统吧,当时也有人研究FAT32,但基本上是应用于SD卡的。其实操作FLASH并写入想要写的数据,并不难,所以这方面的封装库不多见,也属正常。再者,由于转入到编写嵌入式代码工作时间也不长,因此对于此行业的状态也了解不多。作为监控领域的嵌入式行业,最重要的两点就是数据采集和数据历史存储。数据采集与监控的目标对象有关,数据历史存储,目前在低端的ARM7或者Cortex-M3系统的架构上,基本上使用外部FLASH来做存储。随着目前芯片集成技术的推进,目前在一片CPU上也有好几十上百K的FLASH空间,这样一来,实现廉价的监控方案就方便了。然后,在软件行业,面向对象、封装已经风行多年,由于单片系统资源有限,在此领域内封装的库不多,但随着芯片制造技术的飞跃,32位单片机已经非常常见,而且便宜。因此在单片机系统上,进行封装开发也会越来越多。像目前Cortex-M3提供的外围设备库已经属于标配,因此在单片系统开发已经不是懂硬件人的专利了。当我看到外围设备库,看到原来混乱的数据处理代码,我决定对这些代码进行良好封装,以提高自己的开发效率。


    FLASH日志文件系统在应用中需要解决的问题主要有两个:

    1、FLASH平均擦写能力

    2、FLASH在掉电或者异常时恢复问题

    由于在单片系统(裸奔)中,大部分使用的都是NOR FLASH,此类FLASH可靠性高,因此NAND FLASH的坏块问题不多见,只要处理好基本的异常情况,基本上可敷使用。

    然后,在使用FLASH存储数据时,需要解析的问题也有两个:

    1、操作接口方便、抽象,无需考虑过多细节

    2、异常时,不需要过多操心


    基于自己对封装的理解,设计出了自己的FLASH日志文件系统,该系统功能有限,但对于单片系统而言,对数据的写入、读取和删除都可以很好的支持,最关键的就是支持裸奔、代码简洁(5K左右)。


    设计 思路:

    FLASH一般按扇区组织,最小的擦除单位也是扇区,因此此文件系统按扇区建立最小的操作单位。按一般文件系统设计理念,针对每扇区记录分区表,以索引记录。


    本文件系统将所有日志记录形成一个链表记录,即指定头和尾,即可找到记录位置,删除只能头删除,添加只在尾添加,如此可保证日志文件系统的有序性(是监控系统必须保证的)。如果将各扇区有组织的统一管理起来,需要在扇区中包含一部分索引信息,以方便初始化和操作。为保证数据的正确性,数据写入时,要求写入校验和。同时为支持不定长记录,数据写入时还包括数据的写入长度。

    各扇区形成链表,需要在各扇区中保存链信息,由于数据的写入和读出,会导致链表信息更新,因此需要合理利用扇区的物理特性来记录各扇区的状态。

    定义的扇区状态要如下:

    扇区分区由扇区头,扇区数据标识区和数据区三部分组成,前二部分构成扇区分区信息。

    扇区区定义了扇区的必要信息,结构如下:

    typedef struct _sector_lfs
    {
    	unsigned char flag; //标志字节:未初始化为:0xFFFF
    	unsigned char type;
    	unsigned short id;
    	unsigned short logsize;
    	unsigned short mapbytes;
    }sector_lfs_t, *psector_lfs;
    此结构为FLASH中结构标识,此结构为外部FLASH的标识,通过SPI总线的NOR FLASH具有写0有效的编程特性,因此利用此特性,可以将扇区的标志状态使用一字节表示。

    type表示此文件的唯一标识,如果与文件描述的不相同时会重新初始化引扇区。

    id暂时未使用

    logsize表示此日志的最大记录大小

    mapbytes为本扇区数据标识区占用的大小,此结构之后为数据标识区,数据标识区按扇区最大可容量量计算


    扇区数据标识区为位图表示方式,同时利用FLASH的物理特性,利用两个位表示一条记录的状态(写入,删除)。


    日志文件表示结构:

    // 扇区字节数  0x10000
    #define SECTOR_SIZE 0x10000
    // 扇区个数(支持最大扇区数65535)
    #define SECTOR_CNT 	128
    
    typedef struct _lfs
    {
    	unsigned int    start;   // 开始扇区号 , 范围范围为[start, end)
    	unsigned int    end;     // 结束的扇区号
    	unsigned char   type;    // 该文件系统的类型标识
    	unsigned short  logsize; // 记录的日志最大大小
    	         int    head;	   // 用于内部表示开始的头(写的位置),初始化时需start
    			 int    tail;    // 用于内部表示开始的尾(读的位置)
    	unsigned int    count;   // 可用日志记录条数
    	unsigned int    rd_id;   // 当前读的头位置(扇区的ID位置)
    }lfs_t;


    通过指定扇区开始和结束号,就相当于指定了此文件可使用的扇区数量及位置,通过此结构可以在内存中表示一个文件,并实时反映了此文件的物理状态。


    文件系统的加载

    文件系统的加载过程是必须的步骤,在系统准备使用此日志文件前,必须进行文件加载。

    通过指定lfs_t结构的start,end, type, logsize四个参数后,使用lfs_load即可加载此文件。加载文件的过程会扫描指定的扇区,并试图扫描扇区链表的前、尾,和记录数量。对于不属于此文件或者与扇区保留信息不相同的扇区时,将重新初始化此扇区。


    文件系统的操作

    文件系统的操作在文件系统加载之后,可以对记录进行读、写和删除。读可以从有效记录的任意位置进行读,写将在尾部写入。删除只能在链表头删除。


    展开全文
  • 中心化日志记录架构

    千次阅读 2015-02-08 13:54:09
    在中心化日志记录一文中,我介绍了几个工具,用于解决中心化日志记录的问题。但这些工具一般仅能解决这个问题的一部分, 这意味着需要综合使用几个工具来构建一个健壮的解决方案。 你需要解决问题的这几个主要...
     在中心化日志记录一文中,我介绍了几个工具,用于解决中心化日志记录的问题。但这些工具一般仅能解决这个问题的一部分,
     这意味着需要综合使用几个工具来构建一个健壮的解决方案。
    你需要解决问题的这几个主要方面:收集传输存储、以及分析。某些特殊的应用场景下,也许还希望具备告警的能力。
    收集

    应用程序以不同的方式产生日志,一些是通过syslog,其他一些是直接写到文件。考虑一个运行在linux主机上的典型web应用,在/var/log目录会有十几个甚至更多的日志文件, 如果一些应用指定日志存放在HOME目录或者其他位置,则这些目录下也是如此。
    如果你正在运营一个基于web的应用,开发人员或者运维同事需要快速地访问日志数据以便对线上问题进行排错,那么就需要一个能够近乎实时监控日志文件变化的方案。 如果使用基于日志拷贝的方式 — 文件以固定的时间间隔拷贝到一台中心服务器上,那么仅能检查与复制操作频率相同的新增日志数据。当站点已经挂掉,而你正在等待相关日志数据的复制, 那么一分钟一次的 rsync cron 任务也许还不够快。
    从另外一个角度来看,如果需要分析线下日志数据,计算各种度量指标,或者其他批量的工作,文件复制的策略也许正合适。
    传输

    日志数据会在多个主机上快速地累积起来。为了高效传输日志数据到中心位置,并保证数据不丢失,可能需要额外的工具。
    Scribe、Flume、Heka、Logstash、 Chukwa、fluentd、nsq、Kafka 这些框架正是被设计用于 从一个主机到另一个主机可靠地传输大量数据。虽然它们都是用于解决数据传输问题,但做法却不相同。
    例如,Scribe、nsq 以及 Kafka,要求客户端通过它们的API记录日志数据, 通常,应用程序代码会编写成直接将日志写到这些工具中,这样能够减小延迟,提高可靠性。如果你需要的是中心化的日志文件数据,那么就需要跟踪(tail)日志文件变更, 然后将日志数据通过这些工具各自的API流式写入。如果产生需要收集的日志数据的应用由你控制着,一切会高效得多。
    Logstash、Heka、fluentd 以及 Flume 则提供许多输入源方式, 支持本机跟踪(tailing)文件变化并可靠地传输数据。对于更广泛的日志收集来说,是个更合适的选择。
    虽然 rsyslog和Syslog-ng 通常被认为是事实上的日志收集器,但并不是所有应用程序都使用 syslog。
    存储

    现在可以传输日志数据了,但数据存放在哪呢?中心化的存储系统需要能够处理数据随着时间的增长。每天都会增加一定量的数据存储,数据量和产生日志数据的主机和进程数量相关。
    如何存储依赖于以下几个问题:
    需要存储多长时间 — 如果日志是用于长期归档的目的,并且不需要即时分析,那么 S3、AWS Glacier 或磁带备份 也许是合适的选择,因为它们对于大量数据的存储相对比较廉价。如果仅需要几天或者几个月的日志,将数据存储到某种分布式存储系统, 如:HDFS、Cassandara、 MongoDB 或ElasticSearch也是不错的。如果仅需要保留几个小时的数据用于实时分析,使用Redis也可以。
    应用场景的数据量 — Google一天的日志数据量肯定远大于ACME运输物资公司(译注:原文是ACME Fishing Supplies,正确的应该是ACME Shipping Supplies)一天的日志。 你选择的存储系统当数据量增大时应该允许水平扩展。
    需要如何访问日志 — 某些存储系统是适于实时甚至批量分析的。AWS Glacier 或磁盘备份加载一个文件就需要花费若干小时,如果需要访问日志进行产品排错,这就不好使了。 如果计划进行更多的交互式数据分析,将日志数据存储到 ElasticSearch 或 HDFS 让你能够更加有效地使用原始数据。某些日志数据非常庞大,就只能使用面向批量处理的框架进行分析了。这种情况下事实上的标准方案是 Apache Hadoop 配合 HDFS。
    分析

    一旦日志已经存到一个中心化存储平台,就需要一种方式来分析日志。最常见的方式是定期执行一个面向批量处理的进程。如果日志是存储在 HDFS 中, 那么 Hive 或 Pig 相比编写原生MapReduce任务,更易于帮助分析数据。
    如果需要一个用于分析的用户界面,可以将解析过的日志数据存到 ElasticSearch,然后使用一个前端方案,如 Kibana 或 Graylog2来查询检查数据。日志解析可以通过 Logstash 或 Heka来处理, 应用程序也可以直接以JSON格式记录日志。这种方式允许更加实时、交互式的数据获取,但不适于大批量的处理。
    告警

    最后一个组件,有时是可以锦上添花的 — 针对日志模式或基于日志数据计算出来的度量指标进行告警。两种常见用法是:错误报告和监控。
    多数日志数据是无关紧要的,但错误日志则通常说明存在问题。让日志系统在问题发生时给相关人员发送邮件或通知,相比让某个人重复地监视事件,要高效得多。 有几种服务组件可单独提供应用错误日志记录的功能,如 Sentry 或 HoneyBadger 。这些服务也可以聚合重复的异常, 方便你获知错误发生的频率是怎样的。
    另一个使用案例是监控。例如,你可能有上百个web服务器,想知道它们是否开始返回500响应状态码。如果可以解析web日志文件,根据状态码记录一个度量指标, 当度量指标超过了一个特定的阈值就可以触发告警。 Riemann 就是被设计用于检测这种场景的。
    希望本文能提供一个基本模型帮助你针对你的应用环境设计一个中心化日志记录方案。
    展开全文
  • 1.LinkList* Insertlist(){ uint8 n; n=pdatafrm->databuf[2]; listnode *q;} 这是会出错的,结点定义必须放在前面  LinkList* Insertlist(){ uint8 n; listnode *q; n=pdatafrm->databuf[2]; }  ...
  • 本篇博客主要讲授华大半导(STM32、C51等单片机均可适用)复位(以看门狗复位为例)后变量数据保存的方法。 这里将用到__not_init属性,其用于变量声明,可禁止系统启动时变量的初始化,有了__not_init属性,编译器...
  • --[2014年07月04日] 项目研发开始!
  • 把数据存储到外部SD卡上

    千次阅读 2016-11-06 19:57:07
    一、运行效果图 二、核心代码 package com.example.filepersistencetest; import java.io.File; import java.io.FileOutputStream; import java.io.IOException;...import java.io.OutputSt
  • 1. Elasticsearch - 一个基于Lucene的文档存储,主要用于日志索引、存储和分析。 2. Fluentd - 日志收集和发出 3. Flume - 分布式日志收集和聚合系统 4. Graylog2 - 具有报警选项的可插入日志和事件分析服务器 5...
  • • Flash中的内容一般用来存储代码和一些定义为 const的数据,断电不丢失。 • 内部Flash的构成: • STM32 的内部 FLASH 包含主存储器、系统存储器、 OTP 区域以及选项字节区域。 内部FLASH...
  • 同时我们用SD卡极大扩充了系统内存存储空间,可以充分满足存储1000个商品价目表以及2000条销售日志的要求。收银机的液晶显示采用LCM240128ZK液晶屏,可滚动显示扫描到的购物条目信息,并利用OCM4X8C液晶显示器来突出...
  • 实训日志

    2018-07-13 20:38:50
    苏嵌 项目实战 学习日志 姓名:胡超 日期:18/07/13 今日学习任务 1、了解C 语言特点(优缺点、嵌入式开发中的地位,如何学习语言编程)2、了解基本数据类型的定义及输入输出;(内置类型)3、掌握字节长度与...
  • Linux中使用syslog进行日志的打印

    千次阅读 2019-01-09 07:52:18
    对于一个从单片机开发转向操作系统中的应用程序开发的攻城狮来说,对程序的调试方法的转换也是非常重要的。单片机的开发,一般使用jlink进行单步调试较多,但是对于在操作系统上进行应用程序一般都是比较庞大的,...
  • 电力供应继续提供新功能来提高效率,安全,和可管理性要求通信、工业和医疗应用程序。越来越多的单片机是一个关键因素在这些智能电源和实现...控制电源的启动条件是一个明显的需求,但传感、日志记录和交流电源操作也许...
  • 做公号两月,遇到一些初学单片机的同学,刚刚入手做单片机开发,还没有涉及到使用RTOS,且刚入手直接上RTOS可能会有些难度,有的使用的相对较老单片机资源还有限,也不适合跑RTOS。或者使用RTOS,在整体思路上比较...
  • 同时我们用AT24C512极大扩充了系统存储空间,可以充分满足存储1000个商品价目表和2000个销售日志的要求。收银机的液晶显示采用RT240128GB液晶屏,可滚动显示输入的购物条目信息,并利用FYD12864-0402B液晶显示器来...
  • MCS-51单片机的存储器组织结构

    千次阅读 2007-01-26 19:56:00
    MCS-51单片机的存储器组织结构
  • 本节书摘来异步社区《例说51单片机(C语言版)(第3版)》一书中的第1章,第1.1节,作者:张义和,王敏男,许宏昌,余春长,更多章节内容可以访问云栖社区“异步社区”公众号查看 1-1 微型计算机与单片机 例说51单片机...
  • 超轻量级、高性能C日志库--EasyLogger

    千次阅读 2017-02-14 12:33:29
    EasyLogger是一款超轻量级(ROM, RAM)、高性能的C日志库,非常适合对资源敏感的软件项目,例如:IoT产品、可穿戴设备、智能家居等等。相比log4c、zlog这些知名的C日志库,EasyLogger的功能更加简单,提供给用户的接口...
  • 计算机中的存储器   1.简单介绍 ...为了区分不同的存储单元,系统给每个存储单元赋予一个唯一的编号,这个编号称为存储单元的地址,即存储地址。   存储器的种类 (寄存器、缓存、内存、...
1 2 3 4 5 ... 20
收藏数 1,731
精华内容 692
关键字:

单片机存储 日志