2018-08-08 14:36:49 jickjiang 阅读数 1711
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

单片机日志系统架构

说明: 日志记录系统按照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;
}


2019-01-25 16:29:06 qq_31441951 阅读数 65
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏
  • _align(n):指示编译器在n 字节边界上对齐变量。
      对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。
例如:
	_align(8) char buffer[128];  // buffer starts on eight-byte boundary

详细参考:https://www.cnblogs.com/xidongs/p/5655440.html

  • __asm:此关键字用于将信息从编译器传递到 ARM 汇编器armasm
e.g:
1. __asm void my_strcpy(const char *src, char *dst);//使用 __asm 关键字声明或定义嵌入式汇编函数
2. register int foo __asm("r0");   //使用 __asm 关键字声明已命名的寄存器变量
3. 用#pragma asm,和#pragma endasm语句包含嵌入的汇编语言程序:
	void delay(void)
	{
		#pragma asm
		MOV R4,#08H
		DJNZ R4,$
		#pragma endasm
	}


  • _packed:将所有有效类型的对齐边界设置为 1。
       使用 __packed 限定符声明结构或联合后,__packed 将应用于该结构或联合的所有成员。成员之间或结构末尾均没有填充。必须使用__packed 声明压缩结构的所有子结构。可以单独压缩非压缩结构的整型子字段。若要将结构映射到外部数据结构或访问未对齐数据,__packed 限定符非常有用;但由于访问开销相对较高,通常对节省数据大小并没有什么帮助。通过仅对需要压缩的结构中的字段进行压缩,可以减少未对齐访问的数量。
1.压缩结构
    typedef __packed struct
    {
        char x;                   // 结构体所有成员都会被__packed限定    
        int y;
    } X;


  • attribute((at(address))):指定变量的绝对地址
    链接器并非始终能够放置 at 变量属性生成的节。如果无法将节放置在指定地址,链接器将显示一条错误消息。
	int x1 __attribute__((at(0x10000))) = 10;
  • 冷启动和热启动
      冷启动,也就是一般所说的上电复位,冷启动后片内外RAM的内容是随机的;单片机的热启动是通过外部电路给运行中的单片机的复位端一复位电平而实现的,也就是所说的按键复位或看门狗复位。复位后,RAM的内容都没有改变。
2009-10-29 22:32:00 monkeyxxxx 阅读数 2140
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

      最近想研究研究嵌入式系统,由于虽然是计算机专业的,但是硬件知识很差,再加上毕业若干年,全部忘光光。可以说,一切几乎是从零开始了。我还是从简单点的单片机开始学习,看了一眼,感觉比较容易些,从浅入深的学习吧。原来学东西好囫囵吞枣,学了一大堆几乎都是些皮毛,我这次写这个日志,一个是把它当做我的学习笔记,另外也是敦促我自己踏踏实实的学习。

      言归正传,去年在二手市场上花了¥2.00(也够抠门的了)买来了一本《单片微型机 原理、应用与实验》,复旦大学出版社的(我就是由买书的爱好,有没有用看到就想买),就拿它当做我的课本了吧。单片机这个东西,要理论联系实际,没有实验啥都是白学!于是跑到淘宝上花了3百多RMB买来开发板一套,附赠视频教程。预览了一遍,都是简单介绍一下理论(很多东西都没有说清楚),主要就是讲解了一下C代码,一切都得靠自己,哪有那么多现成的。

      教材上用的是汇编语言,写程序真是麻烦,还是用C吧,大不了C搞不定的时候嵌汇编不就完了么!

      还是从51,这个虽然比较老,但是很经目前典用应仍然很广泛的这类芯片开始学习,下面是一个典型的8051引脚图。

 

 8051引脚

 

                            图1.1 8051引脚图

      制造工艺为HMOS(参考数电)的MSC-51单片机采用的是只引脚双列直插封装。12个时钟是一个机器周期,51的指令1~4个机器周期。

1 电源引脚:

Vcc接(+5v)电源

Vss接地。

2 时钟引脚:

XTAL1XTAL2外接晶体振荡器。

3 控制引脚:

RST/Vpd:复位信号/备用电源输入(H/L

ALE/PROC:地址锁存允许信号/编程脉冲输入端(H/L

PSEN:程序存储器输出控制(L

EA/Vpp:内外程序存储器选择控制端/施加较高编程电压(+21V12V)的输入端(L/H

4I/O口引脚

 

P0口:是双向8位三态I/O口,在外接存储器时,与地址总线的低8位及数据总线复用,能以吸收电流的方式驱动8LS型的TTL负载。

P1口:是准双向8I/O口。由于这种接口输出没有高阻状态,输入也不能锁存,故不是真正的双向I/O口。P1口能驱动(吸收或输出电流)4LS型的TTL负载。对80528032P1.0引脚的第二功能为T2定时/计数器的外部输入,P1.1引脚的第二功能为T2EX捕捉、重装触发,即T2的外部控制端。对EPROM编程和程序验证时,它接收低8位地址。

P2口:是准双向8I/O口。在访问外部存储器时,它可以作为扩展电路高8位地址总线送出高8位地址。在对EPROM编程和程序验证期间,它接收高8位地址。P2可以驱动(吸收或输出电流)4LS型的TTL负载。

P3口:是准双向8I/O口,在MCS-51中,这8个引脚还用于专门功能,是复用双功能口。P3能驱动(吸收或输出电流)4LS型的TTL负载。

P3.0 10 RXD(串行输入口)

P3.1 11 TXD(串行输出口)

P3.2 12 INT0(外部中断0

P3.3 13 INT1(外部中断1

P3.4 14 T0(定时器0外部输入)

P3.5 15 T1(定时器1外部输入)

P3.6 16 WR(外部数据存储器写脉冲)

P3.7 17 RD(外部数据存储器读脉冲)

4个端口当中,只有P0是真正的双向口,其他都是准双向口。其他都是准双向口。

 

单片机控制的时候就是向4I/O口送高低电平,另外我们需要关注的是它的存贮器,和寻址方式。

1)程序存贮器:

可以在单片机内部或者在外部,PC就是从0地址开始执行的,此时要设置一个跳转指令,跳向用户设计的主程序。MSC-51的中断入口是固定的,它们的地址是0BH13H1BH23H……。地址通常从3开始,每隔8个字节安排一个中断入口。

2)内部RAM数据存贮器

工作寄存器区(由PSW的第三和第四位指示):在需要的时候它们也可以作为数据缓冲器。

00H~07H:工作寄存器区0R0~R7

08H~0FH:工作寄存器区1R0~R7

10H~17H:工作寄存器区2R0~R7

18H~1FH:工作寄存器区3R0~R7

位寻址区:20H~2FH,它们每一位都占据地址空间00H~7FH,用于存放程序标志、位控制信息,同样它们也可以作为一般的数据缓冲器。

堆栈和数据缓冲器:30H~7FH。进栈是,SP先加1在写入,复位后SP07H。所以对SP初始化时SP=6FH

3)特殊功能寄存器(地址空间80H~FFH

复位时寄存器的状态如下:PC0),PSW0),SP07H),P0~P3FFH),SBUF(未知)

4)外部RAMI/O

MSC-51可以扩展64KBRAMI/O口,它们是统一编址的。

 

 

8051中断系统

 

 8051中断系统结构图

5个中断源:INT0(P3.2),INT1(P3.3)外部中断源;TF0(定时器0),TF1(定时器1),RI/TI(串口输入输出中断)三个内部中断源。

2级的中断优先级(如图所示)

与中断有关的寄存器:

TCON

D7 D6 D5 D4 D3 D2 D1 D0
TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0

 

IT0:外部中断INT0触发方式选择(0,电平触发L;1,跳沿触发H2L),软件设置

IE0:外部中断INT0请求标志位,CPU响应中断后硬件清零

IT1:外部中断INT0触发方式选择,与IT0类似

IE1:外部中断INT0请求标志位,,与IE0类似

TR0:与TR1类似

TF0:T0溢出请求标志位,CPU响应中断后清零,查询方式下由软件清零

TR1:T1运行控制位。TR11时,T1开始工作;TR10时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

TF1:T1溢出请求标志位,与TF0类似

 

SCON

D7 D6 D5 D4 D3 D2 D1 D0
            TI RI

 

TI:串口发送中断请求标志位,硬件自动置位,在中断服务程序中软件清零

RI:串口接受中断请求标志位,硬件自动置位,在中断服务程序中软件清零

 

 

IE

D7 D6 D5 D4 D3 D2 D1 D0
EA     ES ET1 EX1 ET0 EX0

 

EA:中断允许控制位,1-开中断 0-关中断

ES:串口输入输出中断控制位,1-允许中断 0-禁止中断

ET1:T1中断控制位,1-允许中断 0-禁止中断

EX1:INT1中断控制位,1-允许中断 0-禁止中断

ET0:T0中断控制位,1-允许中断 0-禁止中断

EX0:INT0中断控制位,1-允许中断 0-禁止中断

 

IP

D7 D6 D5 D4 D3 D2 D1 D0
      PS PT1 PX1 PT0 PX0

 

PS:串口输入输出中断优先级控制位,1-高 0-低

PT1:T1中断优先级控制位,1-高 0-低

PX1:INT1中断优先级控制位,1-高 0-低

PT0:T0中断优先级控制位,1-高 0-低

PX0:INT0中断优先级控制位,1-高 0-低

2018-07-12 19:49:40 qq_42657769 阅读数 61
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

1、 嵌入式开发与传统开发的区别?(同类问题:单片机开发与嵌入式开发的区别)

是否有无操作系统。(单片机就是完成运算、逻辑控制、通信等功能的单一模块。嵌入式系统是一种专用的计算机系统,作为装置或设备的一部分。通常,嵌入式系统是一个控制程序存储在ROM中的嵌入式处理器控制板。嵌入式系统是将应用程序、操作系统、和计算机硬件连接在一起的系统,是指以应用为中心,以计算机技术为基础,软硬件可裁剪,其针对的用户应用对功能、可靠性、成本、体积、功耗和使用环境有特殊要求的专用计算机系统。

2、 移植操作系统的好处有哪些?

提供多任务机制;提供网络协议栈;提供开源的软件和工具。

3、 嵌入式工程师的岗位划分有哪些?所具备的能力是什么?

系统构建工程师、上层驱动开发工程师、上层应用程序开发工程师

1、计算机应用、自动化、通信或相关专业学士或硕士学历;如为应届生要求在校期间有实际相关工作经验;
2、精通Vxworks操作系统内核程序设计;
3、深入掌握一种或几种高端嵌入式处理器系统(熟悉Intel  Xscale者优先);
4、精通Vxworks环境下的系统开发环境与工具,包括VxWorks平台移植驱动开发及调试;
5、熟悉Vxworks环境下的 C 语言程序设计和汇编语言程序设计;
6、有Vxworks环境下的反汇编以及反向开发经验;
7、精通 DSP 浮点算法的定点实现;
8、熟悉无线网络(Wi-Fi、Ad-Hoc、Wimax)协议者优先;
9、能够熟练阅读英文资料,并能使用英语进行一般性的交流;
10、性格开朗,精力充沛,能够承受工作压力和适应经常性的加班;热爱研发工作,享受技术工作带来的痛苦和乐趣。

4、 人工智能和嵌入式之间有什么关系?人工智能和大数据、云计算的关系?

 

5、 CPU、GPU、DPU、TPU 分别是什么?

CPU( Central Processing Unit, 中央处理器)就是机器的“大脑”, 主要包括运算器(ALU, Arithmetic and Logic Unit)、控制单元(CU, Control Unit)、寄存器(Register)、高速缓存器(Cache)和它们之间通讯的数据、控制及状态的总线。由计算单元、控制单元和存储单元三大部分组成。

GPU(Graphics Processing Unit),中文为图形处理器,GPU最初是用在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上运行绘图运算工作的微处理器。

并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来共同求解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计算

DPU深度学习处理器最早由国内深鉴科技提出,基于Xilinx可重构特性的FPGA芯片,设计专用的深度学习处理单元,且抽象出定制化的指令集和编译器,从而实现快速的开发与产品迭代。 

TPU是Google于2016年5月提出的一个针对Tensorflow平台的可编程AI加速器,TPU可以提供高吞吐量的低精度计算,用于模型的前向运算而不是模型训练,且能效(TOPS/w)更高。TPU与同期的CPU和GPU相比,可以提供15-30倍的性能提升,以及30-80倍的效率(性能/瓦特)提升。1)深度学习的定制化研发:TPU 是谷歌专门为加速深层神经网络运算能力而研发的一款芯片,其实也是一款 ASIC(专用集成电路)。

2)大规模片上内存:TPU 在芯片上使用了高达 24MB 的局部内存,6MB 的累加器内存以及用于与主控处理器进行对接的内存。

3)低精度 (8-bit) 计算:TPU 的高性能还来源于对于低运算精度的容忍,TPU 采用了 8-bit 的低精度运算,也就是说每一步操作 TPU 将会需要更少的晶体管。

6、 嵌入式操作系统有哪些?vxwork 的特点?ucossii 的特点?

Windows CEVxWorks pSOSQNXPalm OSOS-9LynxO

 

可靠性

    操作系统的用户希望在一个工作稳定,可以信赖的环境中工作,所以操作系统的可靠性是用户首先要考虑的问题。而稳定、可靠一直是VxWorks的一个突出优点。自从对中国的销售解禁以来,VxWorks以其良好的可靠性在中国赢得了越来越多的用户。

实时性

   实时性是指能够在限定时间内执行完规定的功能并对外部的异步事件作出响应的能力。实时性的强弱是以完成规定功能和作出响应时间的长短来衡量的。

    VxWorks 的实时性做得非常好,其系统本身的开销很小,进程调度、进程间通信、中断处理等系统公用程序精练而有效,它们造成的延迟很短。VxWorks 提供的多任务机制中对任务的控制采用了优先级抢占(Preemptive Priority Scheduling)和轮转调度(Round-Robin Scheduling)机制,也充分保证了可靠的实时性,使同样的硬件配置能满足更强的实时性要求,为应用的开发留下更大的余地。

可裁减性

   用户在使用操作系统时,并不是操作系统中的每一个部件都要用到。例如图形显示、文件系统以及一些设备驱动在某些嵌入系统中往往并不使用。

  VxWorks 由一个体积很小的内核及一些可以根据需要进行定制的系统模块组成。VxWorks 内核最小为 8kB,即便加上其它必要模块,所占用的空间也很小,且不失其实时、多任务的系统特征。由于它的高度灵活性,用户可以很容易地对这一操作系统进行定制或作适当开发,来满足自己的实际应用需要。

开源性、可移植性、可固化、可裁剪、抢占试、多任务、可确定性、任务栈、系统服务、中断管理,支持嵌套。

 

 

7、 什么是实时性?哪些操作系统具有实时性?

实时性,指时钟信号能够准确的定时,各处的时钟能够达到一致,在不同的场合需要达到ns级、μs级。

VxWorks(商业使用须缴费)-->RT Linux --> Linux--->Android

8、 嵌入式的就业前景和以后的发展方向如何?

近几年来,随着移动互联网、物联网的迅猛发展,嵌入式技术无处不在,笼罩着各行各业,在通讯、网络、工控、医疗、电子等领域发挥着越来越重要的作用;随着嵌入式技术及相关产品不断渗透到人们日常生活,同时大大小小的公司对于嵌入式开发人才招聘需求猛增,不同类型的嵌入式人才可根据自己学习方向进行选择。

 

9、 Linux 操作系统有哪些特点?

1、支持多种平台。Linux可以运行在多种硬件平台上,如具有x86、680x0、SPARC、Alpha等处理器的平台。此外Linux还是一种嵌入式操作系统,可以运行在掌上电脑、机顶盒或游戏机上。2001年1月份发布的Linux2.4版内核已经能够完全支持Intel64位芯片架构。同时Linux也支持多处理器技术。多个处理器同时工作,使系统性能大大提高。

2、多用户、多任务。Linux支持多用户,各个用户对于自己的文件设备有自己特殊的权利,保证了各用户之间互不影响。多任务则是现在电脑最主要的一个特点,Linux可以使多个程序同时并独立地运行。

3、完全兼容POSIX1.0标准。这使得可以在Linux下通过相应的模拟器运行常见的DOS、Windows的程序。这为用户从Windows转到Linux奠定了基础。许多用户在考虑使用Linux时,就想到以前在Windows下常见的程序是否能正常运行,这一点就消除了他们的疑虑。

4、良好的界面。Linux同时具有字符界面和图形界面。在字符界面用户可以通过键盘输入相应的指令来进行操作。它同时也提供了类似Windows图形界面的X-Window系统,用户可以使用鼠标对其进行操作。在X-Window环境中就和在Windows中相似,可以说是一个Linux版的Windows。

5、完全免费。Linux是一款免费的操作系统,用户可以通过网络或其他途径免费获得,并可以任意修改其源代码。这是其他的操作系统所做不到的。

 

10、 Linux 和 unix 操作系统的区别?

Linux和UNIX的最大的区别是,前者是开发源代码的自由软件,而后者是对源代码实行知识产权保护的传统商业软件。这应该是他们最大的不同,这种不同体现在用户对前者有很高的自主权,而对后者却只能去被动的适应;这种不同还表现在前者的开发是处在一个完全开放的环境之中,而后者的开发完全是处在一个黑箱之中,只有相关的开发人员才能够接触的产品的原型。UNIX系统大多是与硬件配套的,而Linux则可运行在多种硬件平台上.UNIX是商业软件,而Linux是自由软件,免费、公开源代码的.

 

11、虚拟机的作用是什么?主流的虚拟机有哪些?

1.演示环境,可以安装各种演示环境,便于做各种例子

2.保证主机的快速运行,减少不必要的垃圾安装程序,偶尔使用的程序,或者测试用的程序在虚拟机上运行

3.避免每次重新安装,银行等常用工具,不经常使用,而且要求保密比较好的,单独在一个环境下面运行

4.想测试一下不熟悉的应用,在虚拟机中随便安装和彻底删除

5.体验不同版本的操作系统,如Linux、Mac等。

Bochs、DOSBox、DOSEMU、Hypen-V、KVM、Logical Domains、OpenVZ、Oracle VM、Parallela Workstation

PearPC、QEMU、QEMU(kqemu模块)、QEMU(qvm86模块)、SimNow、Sun xVM、VirtualBox、User Mode Linux

Virtual Iron Virtual Iron 3.1、Virtual PC 2007、Virtual Server 2005 R2、Virtuozzo、VMware ESX Server、VMware ESXi、Server、VMware Fusion、VMware Server、VMware Workstation 6.0、VMware Player 2.0、Xen

 

12、分别阐述 POSIX、GNU、GPL 的理解?

POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003,而国际标准名称为ISO/IEC 9945。POSIX标准意在期望获得源代码级别的软件可移植性。

 GNU 项目创始于一九八四年,旨在开发一个类似 Unix ,且为 自由软件 的完整的操作系统: GNU 系统。

GNU 的内核尚未完成,所以 GNU 使用 Linux 作为其内核。GNU 和 Linux 以这样的方式组合成为 GNU/Linux 操作系统

GPL许可协议(GNU General Public License):只要软件中包含有其他GPL协议的产品或代码,那么该软件就必须也采用GPL许可协议且开源及免费。具有以下特点:

复制自由:允许将软件复制到任何人的电脑中,并且不限制复制的数量。

传播自由:允许以各种形式进行传播。

收费传播:允许在各种媒介上出售该软件,但必需提前让买家知道这个软件是可以免费获得的,并解释收费的理由(一般来讲都是能够为用户提供某种服务,以技术服务的形式来收费)。

修改自由:允许开发人员增加或删除软件的功能,但必须依然基于GPL许可协议授权。一句话,修改后必须以GPL授权开源发布。

13、Linux 发行版有哪些?各自的特点是什么?

RedHat注重性能和稳定性以及对硬件的支持。

Linux Mint在安装过程中你被允许从一个列表中选择桌面环境,并且你可以放心,一旦它安装完了之后,你还能播放音乐和视频文件,而无需任何额外的配置步骤,因为标准安装提供了多媒体解码器的开箱即用。

Debian主要用于服务器上,但现在它的桌面版本已经在功能和外观上得到了明显的改善。

Ubuntu安装映像包含Try Ubuntu功能,可以让你在硬盘真正安装之前尝试Ubuntu。

openSUSE既可作为一个滚动发布,又可当作是一个独立的定期发布版本

Fedora在领衔整合新的软件包版本和技术到发行版中

Mageia它的全安装DVD允许你在在多种桌面环境中选择,而不是强加一个给你。

Manjaro提供一个更舒适的安装和运行体验,预装了桌面环境,图形应用程序(包括软件中心)和用于播放音频和视频的多媒体解码器。

CentOS稳健性、稳定性、和100%二进制兼容性。

Arch Linux它是一个独立的开放源代码的发行版(这意味着它不基于任何其他的东西)。

Elementary OSElementary OS是基于Ubuntu的,所以它完全兼容代码仓库和软件包。

14、Linux 和windows 的区别?

windows平台:数量和质量的优势,不过大部分为收费软件;由微软官方提供重要支持和服务 
linux平台:大都为开源自由软件,用户可以修改定制和再发布,由于基本免费没有资金支持,部分软件质量和体验欠缺;有全球所有的Linux开发者和自由软件社区提供支持

·安全性

Windows平台:三天两头打补丁安装系统安全更新,还是会中病毒木马什么的,各位用户自己感受。 
Linux平台:要说linux没有安全问题,那当然是不可能的,不会中病毒什么的,也不可能,这一点仁者见仁智者见智,相对来说肯定比Windows平台要更加安全,使用linux你也不用装杀毒软件了。

15、Linux 文件类型有哪些?

普通文件(-)目录(d)字符设备(c)和块设备(b)套接口文件(s)符号链接(l)管道(p)

16、罗列 Linux 下文件操作的命令有哪些?(常见面试命令)

lscdmkdirrm-fbinsbindevetclibusrcp-rmvtarcvzftar xvzfreboot-o1,2,3)、-wall-wgccvim

17、如何配置 vim 编辑器?Linux 下还有哪些比较常用的文本编辑器?

首先进入命令行,按ai进入插入行进行编辑,编辑完成按esc键退出,按shift+:进入底行模式,wq+回车保存退出。

EmacsNotepad++TextMateSublime Text

 

18、如何压缩、解压文件?命令是什么?

解压:tar zxvf 文件名.tar.gz
压缩:tar zcvf 文件名.tar.gz DirName

19、gcc 编译器的优点有哪些?还知道哪些 C 的编译器?

GCC,跨体系结构很多Borland Turbo C 或称 Turbo C、Microsoft C 或称 MS C

 

20、什么是交叉编译器?交叉编译器的作用?为什么需要交叉编译?

在当前CPU平台下编译的程序可在其他CPU平台上运行。

在当前CPU平台下编译的程序可在其他CPU平台上运行。

不同的CPU,有不同的汇编不同的机器码。

21、C 语言中源文件到可执行文件经历哪几个步骤?每个步骤具体做哪些工作?

预处理:1、头文件展开。2、宏替换。3、条件编译。

编译:语法检查、语法分析。

汇编:把编译产生的.s文件转换成目标文件。

链接:

22#include <stdio.h>    #include “stdio.h”的区别?

搜索路径不同。#include <stdio.h> 在系统头文件目录下搜索,#include “stdio”先在当前文件目录下搜索,再到系统头文件目录下搜索。

 

23、分别阐述-I -w -Wall -O3  的作用?

-I:指定搜索路径

-w :关闭警告

-Wall:呈现全部警告

-O3 3级优化

24、什么是库文件?库文件的特点?

通常有静态库文件和动态库文件。编译后的库文件看不到源代码,可保密;同时不会因为不小心修改了函数而出问题,便于维护。

25、Linux 下库文件的分类有哪些?库文件的存放路径是什么?

静态库文件和动态库文件

库文件的存放路径:lib

26、静态库和动态库的区别?

静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。

动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。

静态库和动态库的最大区别,静态情况下,把库直接加载到程序中,而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在

27、如何制作和使用静态库和动态库?

gcc  -c  .c

ar rcs lib  .arc

gcc main .c  -l.

 

gcc -shared -FPIC -o

XX.so 源文件.c

gcc 源文件.c /XX.so -o

可执行文件名

28、GDB 的特点有哪些?

 

gdb (调试器)是Linux GNU计划的工具。

     (1)启动被调试程序;

     (2)让被调试程序运行;

     (3)查看变量值


29、分阐述 run break info break continue finish 用?

run:运行程序   break:停止程序  info break:查看断点信息    continue:继续(跳过的当前断点)    finish:让子函数运行完成

30、make 工程管理的作用?

提高编译程序的效率,一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪 些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操所系统的命令。

31、makefile 的语法是什么?(定义、执行顺序)

 

在各个子目录和当前目录中建立 mkdir Makefile,用vim对Makefile进行编写;

      三要素:目标,依赖,命令;执行命令需要依赖文件,会生成目标文件

                   格式:  目标:依赖

                          tab          命令 

       执行循序:由上而下执行;

32、企业级工程目录是如何创建?分别描述三个不同 makefile 的作用?

          总控 Makefile:将各个子目录下的 .o 文件链接生成可执行文件

    子目录 Makefile:将目录下的 .c 文件编译生成 .o 文件

    scripts 目录下的 Makefile:相当于C语言中的头文件定义了一些变量

 

2014-09-03 16:40:12 wangtracy123 阅读数 547
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

c8051f340的使用中离不了的一部分就是端口I/O初始化。

端口I/O初始化包括以下步骤:

1、用端口输入方式寄存器(PnMDIN)选择所有端口引脚的输入方式(模拟或数字)

2、用端口输出方式寄存器(PnMDOUT)选择所有端口引脚的输出方式(漏极开路或者是推完输出)。

3、用端口跳过寄存器(PnSKIP)选择应被开关跳过的那些引脚。

4、将引脚分配给要使用的外设

5、使能交叉开关(XBRE=1).

当XBR1寄存器中的WEAKPUD位为‘0’时,输出方式为漏极开路的那些引脚的弱上拉被使能。

注意:为使端口P0、P1、P2、P3工作在标准端口I/O输出方式,交叉开关必须被使能,当交叉开关被禁止时,端口输出驱动器被禁止端口4总是作为标准GPIO使用。

没有更多推荐了,返回首页