<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[玩转单片机]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[欢迎所有爱好电子和单片机的朋友。]]></description>
<link>http://hi.baidu.com/52elec</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[从单片机初学者迈向单片机工程师----按键处理]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/af83e4afe38482f1faed5073.html]]></link>
        <description><![CDATA[
		
		<p>&nbsp;&nbsp;&nbsp;  前些日子把自己以前下载的一些按键的资料好好看了下。发现万变不离其中。无非就是把以前延时消抖动改变为对按键进行计数，或者是状态的变化的判断。这样的好处不言而喻，释放了MCU，能够有更多时间去处理其它任务。而单片机初学者最容易犯的错误就是在这里。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  按键按下？----&gt; YES ----&gt; 延时20MS ----&gt; 按键按下？----&gt; YES ----&gt; 返回键值</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  |&nbsp;&nbsp;&nbsp;&nbsp;  N O&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;  NO</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  退出&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  退出</p>
<p>这是一个比较经典的处理模式，为什么这样说呢，因为大部分的单片机教材上面都是这样写的。以至于很多初学者以为按键处理就是这个模式。不得不说，现在的单片机教材优秀的太少，大部分都是抄来抄去。最终受害的还是我们学习者。可能要很久以后才会发现，原来自己走了这么长的时间的弯路。</p>
<p>下面贴一个很久以前在网上收集到的按键处理的资料。理解了其中的精髓就会一通百通。</p>
<p><br>
&nbsp;&nbsp;  状态机是一个有向图形，由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而&ldquo;运行&rdquo;。每个事件都在属于&ldquo;当前&rdquo;节点的转移函数的控制范围内，其中函数的范围是节点的一个子集。函数返回&ldquo;下一个&rdquo;（也许是同一个）节点。这些节点中至少有一个必须是终态。当到达终态，状态机停止。<br>
&nbsp;&nbsp;&nbsp;  这一段抽象的数学定义，或许会晕倒一片人，但是我们能不能换一个说法来更好的理解状态机呢，学习方法中，我最推崇&ldquo;类比&quot;, 因为天地一大宇宙，人身一小宇宙，天地间一切可类比。就像电流与水流，电学与力学一样。在此表弟我不才，也想对状态机类比一下。<br>
&nbsp;&nbsp;  其实在我看来，有限状态机就是一个人的悲喜剧，生命不息，状态不止。在父母面前，他是一个好的儿子，他所做的事就是孝敬父母,在妻子面前他是一个好丈夫，呵护着自己的老婆，支撑着这个家，在儿女面前，他是一个好爸爸淳淳教导着自己的子女，在老板面前，他是一个好职员，他所做的是为公司的明天而打拼. 如此环环不息，直至生命的终结，没有人是不死的，状态机也一样（在此不考虑无限状态机). 此类比中的&quot;好儿子&ldquo;,&quot;好丈夫&quot;,&quot;好爸爸&quot; 就是一个人的不同的自我，在扮演着不同的角色，演绎着不同的故事，可以称之为&ldquo;状态&rdquo;，而&ldquo;孝敬父母&rdquo;&ldquo;呵护老婆&rdquo;&ldquo;教导子女&rdquo;则是在不同状态下的行为。 以下是对以上类比的C伪码抽象.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  switch(人.状态)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case &quot;好儿子&quot;:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  孝敬父母;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  break;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case &quot;好丈夫&quot;:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  呵护老婆;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  break; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case &quot;好爸爸&quot;:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  教导子女;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  default:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
以上可能并不准确，因为没考虑其间的状态改变，但是其状态改变是显而易见的，比如到公司上班，就是好员工状态，回到家中，在妻子的面前，你就处于&ldquo;好丈夫&rdquo;状态在接儿女放学的路上，你就处在一个&ldquo;好爸爸&rdquo;的状态。<br>
  <br>
&nbsp;&nbsp;  接下来，就谈谈FSM（用英文并不是表弟我祟洋媚外，而是少打几个字)在嵌入式键盘模块的应用。并且用C++，及state模块实现之。键盘模块有哪些状态呢，表哥们应都清楚，无非就是，空闲(idle)，按下(press)，按住(hold)，释放(release)状态。每个状态下有不同的行为，也就是要DoSomething,于是用c++抽象一个类如下：<br>
为了简便，在此省略掉hold状态，假设系统仅是有idle,press,release三态<br>
class CKeyState&nbsp;&nbsp;  <br>
&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;  public:<br>
&nbsp;&nbsp;&nbsp;&nbsp;  char m_StFlag;  //用于键盘模块中的状态转换，state模式中不是这样<br>
&nbsp;&nbsp;&nbsp;&nbsp;  CKeyState()<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_StFlag=0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;&nbsp;  void virtual DoSth(void)=0;  //不同状态下所做的事情，纯虚函数。<br>
&nbsp;&nbsp;&nbsp;&nbsp;  void virtual delay(void)&nbsp;&nbsp;&nbsp;&nbsp;  //延时函数，虚函数，不同状态可以有不同的延时函数，故声明为虚函数<br>
&nbsp;&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  for(int i=0;i&lt;100;i++)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  for(int j=0;j&lt;255;j++);<br>
&nbsp;&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;  };</p>
<p>class CIdleSt : public CKeyState  //空闲状态<br>
{<br>
  void virtual DoSth(void)<br>
  {<br>
&nbsp;&nbsp;&nbsp;  if(!KEY)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //有键按下<br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delay();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //去抖<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if(!KEY)m_StFlag=1;&nbsp;&nbsp;&nbsp;  //仍然有键按下，则去press态<br>
&nbsp;&nbsp;&nbsp;  }<br>
  }<br>
};</p>
<p>class CPressSt : public CKeyState  //按下状态<br>
{<br>
  void virtual DoSth(void)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
  {<br>
&nbsp;&nbsp;&nbsp;  LED=1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //具体的动作，此处为点亮一个LED<br>
&nbsp;&nbsp;&nbsp;  if(KEY)m_StFlag=1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //按键释放则去Relese态<br>
  }<br>
};</p>
<p>class CReleaseSt : public CKeyState<br>
{<br>
  void virtual DoSth(void)<br>
  {<br>
&nbsp;&nbsp;&nbsp;  delay();&nbsp;&nbsp;&nbsp;&nbsp;  //释放时去抖动<br>
&nbsp;&nbsp;&nbsp;  if(KEY)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_StFlag=0;  //释放则回到IDLE态<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_StFlag=0;  //是抖动，则仍在press态<br>
&nbsp;&nbsp;&nbsp;  } <br>
  }<br>
};</p>
<p>以上就是对状态的简单抽象，以下是键盘模块的类的定义，<br>
class CKeyModule<br>
{<br>
public:<br>
  CKeyState *st;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //键盘模块当然包含一个状态<br>
  CKeyModule()<br>
  {<br>
&nbsp;&nbsp;&nbsp;  st=new CIdleSt();  //初始化为idle状态<br>
  }</p>
<p>  void UpdateState(void);  //状态的更新和转换<br>
};</p>
<p>void CKeyModule:: UpdateState()<br>
{<br>
  char tmp=st-&gt;m_StFlag;&nbsp;&nbsp;&nbsp;  //根据m_StFlag的值来转换状态<br>
  switch(tmp)<br>
  {<br>
  case 0:<br>
&nbsp;&nbsp;&nbsp;  st = new CIdleSt();<br>
&nbsp;&nbsp;&nbsp;  break;<br>
  case 1:<br>
&nbsp;&nbsp;&nbsp;  st=new CPressSt();<br>
&nbsp;&nbsp;&nbsp;  break;<br>
  case 2:<br>
&nbsp;&nbsp;&nbsp;  st=new CReleaseSt();<br>
&nbsp;&nbsp;&nbsp;  break;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br>
  default:<br>
&nbsp;&nbsp;&nbsp;  st=new CIdleSt();<br>
  }<br>
}</p>
<p>于是乎在我们的程序中则可应用如下：<br>
#include&lt;ioAT89S52.h&gt;</p>
<p>#define KEY P0_bit.P0_0<br>
#define LED P0_bit.P0_1<br>
。。。</p>
<p>CKeyModule pSysKey;  //定义一个键盘模块对象</p>
<p>int main(void){<br>
  KEY=1;<br>
  LED=0;</p>
<p>  for(;;){<br>
  pSysKey.st-&gt;DoSth();&nbsp;&nbsp;&nbsp;  //根据不同的状态，做不同的事,此处正是虚函数的精要<br>
  pSysKey.UpdateState();  //更新状态<br>
  }<br>
}</p>
<p>OK，enjoy it 不要觉得长，慢慢学会看别人的程序也是一种能力和进步。</p> <a href="http://hi.baidu.com/52elec/blog/item/af83e4afe38482f1faed5073.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%A5%C6%AC%BB%FA%D1%A7%CF%B0">单片机学习</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/af83e4afe38482f1faed5073.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-24  11:25</pubDate>
        <category><![CDATA[单片机学习]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/af83e4afe38482f1faed5073.html</guid>
</item>

<item>
        <title><![CDATA[如何从单片机初学者迈向单片机工程师]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/91b0e260c02899d58cb10d69.html]]></link>
        <description><![CDATA[
		
		<p>&nbsp;&nbsp;&nbsp;  屈指算来，学习单片机也快两年了。其中酸甜苦辣个中滋味只有自己才能体会。现在也算是取得了一点点小小进步。看着越来越多的初学者走在自己曾经走过的路上，百感交集。但是好像很多人在学了一点之后就很茫然了，就不知道该如何走下去了。难道单片机就是1602液晶，就是几个按键，几个数码管，AD，DA这些东西吗？不是，远远不是。想想你身边的各种各样的电子产品吧，看看他们是如何工作的。再想想如果让你去设计这个产品完成相应的功能，你会如何处理呢？所以，想从单片机初学者迈向单片机工程师的第一步就是要有工程师的头脑。什么事情都尽可能的以实际工作中可能遇到的情况去考虑。不要以为这很难，想想你大学毕业了，不也是要马上去面对实际的工作吗，从现在开始努力，你会发现，毕业以后你会比同学远远超出一大截。</p>
<p>&nbsp;&nbsp;&nbsp;  一直都没有更新博客了，我在考虑是否有必要写一些关于单片机应用方面的文章，希望能够给更多初学者一点帮助。看情况吧。</p> <a href="http://hi.baidu.com/52elec/blog/item/91b0e260c02899d58cb10d69.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%A5%C6%AC%BB%FA%D1%A7%CF%B0">单片机学习</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/91b0e260c02899d58cb10d69.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-23  16:15</pubDate>
        <category><![CDATA[单片机学习]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/91b0e260c02899d58cb10d69.html</guid>
</item>

<item>
        <title><![CDATA[模块化的EEPROM的循环利用管理程序(转)]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/a6550d1c2a35248187d6b6a5.html]]></link>
        <description><![CDATA[
		
		<table cellspacing="0" cellpadding="0" summary="pid243158">
    <tbody>
        <tr>
            <td class="postauthor"> </td>
            <td class="postcontent">
            <div class="cool"> </div>
            <div class="defaultpost">
            <div class="postmessage firstpost">
            <div >
            <div class="threadtags"> </div>
            </div>
            <div class="t_msgfontfix">
            <table cellspacing="0" cellpadding="0">
                <tbody>
                    <tr>
                        <td class="t_msgfont" >重复循环利用整个EEPROM区域进行写，巧妙建立默认的索引。外部EEPROM操作<span class="t_tag" href="tag.php?name=%E6%8E%A5%E5%8F%A3">接口</span>可实现<span class="t_tag" href="tag.php?name=%E6%A8%A1%E5%9D%97">模块</span>化，可单独建库。完善的写保护机制。<br>
                        <br>
                        //--------------------------------------------------------<br>
                        //EEPROM方式的<span class="t_tag" href="tag.php?name=%E6%95%B0%E6%8D%AE">数据</span>管理<br>
                        //特征字：<br>
                        //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0xff 空记录<br>
                        //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0xf0 写锁标志<br>
                        //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0xf3 有效记录<br>
                        //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x0&nbsp;&nbsp; 坏记录<br>
                        //--------------------------------------------------------<br>
                        #include &quot;....SystemCom.h&quot;<br>
                        #include &quot;....SystemMemory.h&quot;<br>
                        <br>
                        #define FLAG_EMPTYRECORD&nbsp;&nbsp;&nbsp;&nbsp; 0xff&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //空记录<br>
                        #define FLAG_LOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0xf0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //写锁标志<br>
                        #define FLAG_VALIDRECORD&nbsp;&nbsp;&nbsp;&nbsp; 0xf3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //有效记录<br>
                        #define FLAG_BADRECORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //坏记录区<br>
                        <br>
                        struct EDataBase{<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 *pRecordBuffer;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //记录缓冲区开始指针<br>
                        };<br>
                        struct EDataBase sEDataBase;<br>
                        <br>
                        struct InEDataBase{<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 mRecordByteSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //记录大小,比记录缓冲区大1个字节。（特征字节）<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; bool bWriteRequ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //写请求<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 *pWriteBuffer;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //写EEPROM的数据缓冲区<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; bool bWriteBusy;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 mWriteTask;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //写任务号<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U16 mEepromStartLocation;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在Eeprom存储起始<span class="t_tag" href="tag.php?name=%E5%9C%B0%E5%9D%80">地址</span><br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U16 mEepromEndLocation;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在Eeprom存储结束地址<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U16 mCurrentRecordLocation;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //当前数据存储所在位置<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U16 mTemp;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 (*pfEeprom)( U8 mCmd, U16 mId, U8 mData );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EEPROM操作函数指针<br>
                        };<br>
                        struct InEDataBase sInEDataBase;<br>
                        #define this sInEDataBase<br>
                        <br>
                        enum EepromCmd{<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; eReadU8,<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; eWriteU8,<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; eReadBusy,<br>
                        };<br>
                        <br>
                        #define Eeprom_ReadU8(mId)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*this.pfEeprom)(eReadU8, mId, NULL)<br>
                        #define Eeprom_WriteU8(mId,mData)&nbsp;&nbsp;&nbsp; do{ (*this.pfEeprom)(eWriteU8, mId, mData);}while(0)<br>
                        #define Eeprom_ReadBusy()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*this.pfEeprom)(eReadBusy, NULL, NULL)<br>
                        #define READRECORDFLAG(mId)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Eeprom_ReadU8( InEDataBase_FlagLocation(mId) )<br>
                        #define WRITERECORDFLAG(mId, mData) Eeprom_WriteU8( InEDataBase_FlagLocation(mId), mData )<br>
                        <br>
                        <br>
                        //--------------------------------------------------------<br>
                        //得到特征字位置<br>
                        //入口：记录的起始位置<br>
                        //--------------------------------------------------------<br>
                        U16 InEDataBase_FlagLocation( U16 mRecordLocation )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; return mRecordLocation + this.mRecordByteSize - 1;<br>
                        }<br>
                        <br>
                        //--------------------------------------------------------<br>
                        //记录号+1<br>
                        //返回+1后的记录号<br>
                        //--------------------------------------------------------<br>
                        U16 InEDataBase_RecordIdInc( U16 mId )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; mId += this.mRecordByteSize;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; if( mId &gt;= this.mEepromEndLocation ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mId = this.mEepromStartLocation;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; return mId;<br>
                        }<br>
                        <br>
                        <br>
                        //--------------------------------------------------------<br>
                        //记录号-1<br>
                        //返回-1后的记录号<br>
                        //--------------------------------------------------------<br>
                        U16 InEDataBase_RecordIdDec( U16 mId )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; if( mId &lt; (U16)(this.mEepromStartLocation + this.mRecordByteSize) )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mId = this.mEepromEndLocation - this.mRecordByteSize;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; else {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mId -= this.mRecordByteSize;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; return mId;<br>
                        }<br>
                        <br>
                        //--------------------------------------------------------<br>
                        //读出数据到缓冲<br>
                        //--------------------------------------------------------<br>
                        void InEDataBase_ReadBuffer( void )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 i = this.mRecordByteSize;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U16 mLocation = this.mCurrentRecordLocation;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 *pRecordBuffer = sEDataBase.pRecordBuffer;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; while( --i ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pRecordBuffer++ = Eeprom_ReadU8( mLocation++ );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        }<br>
                        <br>
                        //--------------------------------------------------------<br>
                        //初始化<br>
                        //入口：记录字节个数, Eeprom起始地址，Eeprom大小（字节）, Eeprom函数操作指针<br>
                        //--------------------------------------------------------<br>
                        void EDataBase_Init( U8 mRecordByteSize, U16 mEepromStartLocation, U16 mEepromSize, U8 (*pfEeprom)( U8 mCmd, U16 mId, U8 mData ) )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U16 i,j;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; U8 k;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; Memory_Memset( (U8 *)&amp;this, 0, sizeof(struct InEDataBase) );<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; sEDataBase.pRecordBuffer = Memory_Malloc( mRecordByteSize );<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; mRecordByteSize++;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.pWriteBuffer = Memory_Malloc( mRecordByteSize );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.mRecordByteSize = mRecordByteSize;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.pfEeprom = pfEeprom;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.mEepromStartLocation = mEepromStartLocation;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.mEepromEndLocation = mEepromStartLocation + mEepromSize - (mEepromSize % mRecordByteSize);<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; //重建索引<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; i = this.mEepromStartLocation;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; //必定有个空记录<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; while( i &lt; this.mEepromEndLocation )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = READRECORDFLAG(i);<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ( k == FLAG_LOCK ) || ( k == FLAG_EMPTYRECORD ) )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //找到空记录,倒推最后一个记录位置<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j = i;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do{<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = InEDataBase_RecordIdDec( i );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = READRECORDFLAG(i);<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( k == FLAG_VALIDRECORD ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //找到最近的有效数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto l_LocationFirst;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while( i!= j );<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //没有任何有效数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = this.mEepromStartLocation;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto l_LocationFirst;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //继续到下个记录<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = InEDataBase_RecordIdInc( i );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; //无任何数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; i = this.mEepromStartLocation;<br>
                        <br>
                        l_LocationFirst:<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.mCurrentRecordLocation = i;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp; //读出数据到缓冲<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; InEDataBase_ReadBuffer();<br>
                        }<br>
                        <br>
                        //--------------------------------------------------------<br>
                        //写数据存储进EEPROM<br>
                        //--------------------------------------------------------<br>
                        void EDataBase_FlushBuffer( void )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; this.bWriteRequ = true;<br>
                        }<br>
                        <br>
                        //--------------------------------------------------------<br>
                        //循环<br>
                        //--------------------------------------------------------<br>
                        void EDataBase_Loop( void )<br>
                        {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; if( this.bWriteBusy &amp;&amp; ( Eeprom_ReadBusy() == false ) ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //检查是否写完<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch( this.mWriteTask ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0: //擦除新记录区,首先找到有效空块<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mCurrentRecordLocation = InEDataBase_RecordIdInc( this.mCurrentRecordLocation );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( READRECORDFLAG( this.mCurrentRecordLocation ) == FLAG_BADRECORD )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //是处于坏块上，退出，下次进入时到下个记录位置<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mTemp = this.mCurrentRecordLocation;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 1;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1: //擦除当前有效空块后的空块,保证当前有效空块写入数据后至少有一个有效空块.（初始建立索引需要）<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mTemp = InEDataBase_RecordIdInc( this.mTemp );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( READRECORDFLAG( this.mTemp ) == FLAG_BADRECORD )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //是处于坏块上，退出，下次进入时到下个记录位置<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //写空区标志<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mTemp, FLAG_EMPTYRECORD );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 2;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2: //检查是否空区建立<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( READRECORDFLAG( this.mTemp ) != FLAG_EMPTYRECORD )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //失败<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mTemp, FLAG_BADRECORD );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 1;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //开始写数据.首先锁标志<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mCurrentRecordLocation, FLAG_LOCK );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 3;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 3:<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( READRECORDFLAG( this.mCurrentRecordLocation ) != FLAG_LOCK )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //失败<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mCurrentRecordLocation, FLAG_BADRECORD );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 0;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //开始写数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mTemp = 0;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 4;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 4: //写全部数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Eeprom_WriteU8( this.mTemp + this.mCurrentRecordLocation, this.pWriteBuffer[ this.mTemp ] );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ++this.mTemp == (this.mRecordByteSize - 1) ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //写完数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 5;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 5: //校验数据<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mTemp = 0;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while( this.mTemp != (this.mRecordByteSize - 1) )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( this.pWriteBuffer[ this.mTemp ] != Eeprom_ReadU8( this.mTemp + this.mCurrentRecordLocation ) )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //失败<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mTemp, FLAG_BADRECORD );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 0;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mTemp++;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 6;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 6: //写完成标志<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mCurrentRecordLocation, FLAG_VALIDRECORD );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 7;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 7: //校验写完成标志<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( READRECORDFLAG( this.mCurrentRecordLocation ) != FLAG_VALIDRECORD )<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //标志错误,失败<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WRITERECORDFLAG( this.mTemp, FLAG_BADRECORD );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 0;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //完成<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.bWriteBusy = false;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; else {<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //空闲下检查是否有写请求<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( this.bWriteRequ == true ){<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //开始写<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mWriteTask = 0;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.bWriteRequ = false;<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.bWriteBusy = true;<br>
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memory_MemCopy( this.pWriteBuffer, sEDataBase.pRecordBuffer, this.mRecordByteSize - 1 );<br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        &nbsp;&nbsp;&nbsp;&nbsp; }<br>
                        }</td>
                    </tr>
                </tbody>
            </table>
            </div>
            </div>
            </div>
            </td>
        </tr>
    </tbody>
</table> <a href="http://hi.baidu.com/52elec/blog/item/a6550d1c2a35248187d6b6a5.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%A5%C6%AC%BB%FA%D1%A7%CF%B0">单片机学习</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/a6550d1c2a35248187d6b6a5.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-31  15:54</pubDate>
        <category><![CDATA[单片机学习]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/a6550d1c2a35248187d6b6a5.html</guid>
</item>

<item>
        <title><![CDATA[像写Windows程序那样写单片机程序之基础配置(转)]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/21758fadc588f2034b36d697.html]]></link>
        <description><![CDATA[
		
		<p>为什么非得要&ldquo;像Windows程序&rdquo;那样，而不是Linux或是其他程序那样？原因很简单，因为本人不会~_~。其实，重要的不是像哪种平台下的程序，而是程序的结构方式、屏蔽底层硬件实现等与平台无关的东西。</p>
<p>本系列文章探讨的主题都是在Keil uVision3集成编译环境下完成的，针对的是51系列单片机。</p>
<p>下面就介绍一下在我的单片机程序里必须要包含的一个头文件----&quot;const.h&quot;，完整内容如下：</p>
<p>#ifndef _CONST_H_</p>
<p>#define _CONST_H_</p>
<p>#include &lt;intrins.h&gt;</p>
<p><br>
#define TRUE 1</p>
<p>#define FALSE 0</p>
<p><br>
typedef unsigned char BYTE;</p>
<p>typedef unsigned int WORD;</p>
<p>typedef unsigned long DWORD;</p>
<p>typedef float FLOAT; </p>
<p>typedef char CHAR;</p>
<p>typedef unsigned char UCHAR;</p>
<p>typedef int INT;</p>
<p>typedef unsigned int UINT;</p>
<p>typedef unsigned long ULONG;</p>
<p>typedef UINT WPARAM;</p>
<p>typedef ULONG LPARAM;</p>
<p>typedef ULONG LRESULT;</p>
<p>typedef void VOID;</p>
<p>typedef const CONST;</p>
<p>typedef void *PVOID;</p>
<p>typedef bit BOOL;</p>
<p> </p>
<p>#define MAKEWORD(lo, hi)&nbsp;&nbsp;  ((WORD)(((BYTE)(lo)) | ((WORD)((BYTE)(hi))) &lt;&lt; 8))</p>
<p>#define MAKEDWORD(lo, hi)  ((DWORD)(((WORD)(lo)) | ((DWORD)((WORD)(hi))) &lt;&lt; 16))</p>
<p>#define LOWORD(dw)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((WORD)(dw)</p>
<p>#define HIWORD(dw)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((WORD)(((DWORD)(dw) &gt;&gt; 16) &amp; 0xFFFF))</p>
<p>#define LOBYTE(w)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((BYTE)(w))</p>
<p>#define HIBYTE(w)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((BYTE)(((WORD)(w) &gt;&gt; 8) &amp; 0xFF))</p>
<p>#define MAX(a, b)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (((a) &gt; (b)) ? (a) : (b))</p>
<p>#define MIN(a, b)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (((a) &lt; (b)) ? (a) : (b))</p>
<p> </p>
<p>#define SET_STATE_FLAG(state, mask)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((state) |= (mask))</p>
<p>#define RESET_STATE_FLAG(state, mask)&nbsp;&nbsp;&nbsp;  ((state) &amp;= ~(mask))</p>
<p>#define TEST_STATE_FLAG(state, mask)&nbsp;&nbsp;&nbsp;&nbsp;  ((state) &amp; (mask))</p>
<p> </p>
<p>//偏移量从0开始</p>
<p>#define TEST_BIT(b, offset)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (1 &amp; ((b) &gt;&gt; (offset)))</p>
<p>#define SET_BIT(b, offset)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((b) |= (1 &lt;&lt; (offset)))</p>
<p>#define RESET_BIT(b, offset)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ((b) &amp;= (~(1 &lt;&lt; (offset))))</p>
<p><br>
//将BCD码变为十进制，如将0x23变为23</p>
<p>//注意:高四位和低四位均不能大于9</p>
<p>#define BCD_TO_DECIMAL(bcd) ((BYTE)((((BYTE)(bcd)) &gt;&gt; 4) * 10 + (((BYTE)(bcd)) &amp; 0x0f)))</p>
<p>#define DECIMAL_TO_BCD(decimal) ((BYTE)(((((BYTE)(decimal)) / 10) &lt;&lt; 4) | ((BYTE)(decimal)) % 10))</p>
<p><br>
#define NOP() _nop_()</p>
<p>#define BYTE_ROTATE_LEFT(b, n) _crol_(b, n)</p>
<p>#define BYTE_ROTATE_RIGHT(b, n) _cror_(b, n)</p>
<p>#define WORD_ROTATE_LEFT(w, n) _irol_(w, n)</p>
<p>#define WORD_ROTATE_RIGHT(w, n) _iror_(w, n)</p>
<p>#define DWORD_ROTATE_LEFT(dw, n) _lrol_(dw, n)</p>
<p>#define DWORD_ROTATE_RIGHT(dw, n) _lror_(dw, n)</p>
<p><br>
#define ENABLE_ALL_INTERRUPTS() (EA = 1)</p>
<p>#define DISABLE_ALL_INTERRUPTS() (EA = 0)</p>
<p> </p>
<p>#endif</p>
<p> </p>
<p>其实，里面的大部分内容都是从VC的头文件里拷贝过来的没什么创新，而且从命名也比较好判断出实现的功能，也就不一一介绍了。下面说一下几个常用的：</p>
<p>1、LOBYTE( )和HIBYTE( )。从名字就可以看出，取一个字长的低字节和高字节。这两个宏在定时器的初值装载中经常要用到。在网上或书上几乎所有的程序都是这样：</p>
<p>TH0 = (65536- X) / 256;</p>
<p>TL0 = (65536 - X) % 256;</p>
<p>其实这样赋值是非常不直观的，高字节为什么要除以256？低字节为什么要对256取余？如果换成如下的写法是不是很明了呢？</p>
<p>TH0 = HIBYTE(65536- X);</p>
<p>TL0 = LOBYTE(65536 - X);</p>
<p>2、TEST_BIT( )、SET_BIT( )和RESET_BIT( )。单片机的资源比较紧张，经常要用到以&ldquo;位&rdquo;为单位。这三个宏就是为了方便位操作的。</p>
<p>3、BCD_TO_DECIMAL( )和DECIMAL_TO_BCD( )。用过ds1302的朋友都知道，从中度取的都是BCD格式的信息，经常需要与十进制之间进行转换。</p>
<p>当然，这个头文件只是起到一个抛砖引玉的作用，随时都加入需要的功能。这样做的好处是把经常用到的功能提炼出来，提高了代码的复用率。更重要的是，今后所有自己的库文件的编写都用到了此头文件中的内容。就像所有Windows程序都需要包含windows.h头文件一样。</p>
<p> </p>
<p>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/jiqiang01234/archive/2009/06/08/4250792.aspx">http://blog.csdn.net/jiqiang01234/archive/2009/06/08/4250792.aspx</a></p> <a href="http://hi.baidu.com/52elec/blog/item/21758fadc588f2034b36d697.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%C4%AC%C8%CF%B7%D6%C0%E0">默认分类</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/21758fadc588f2034b36d697.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-31  11:23</pubDate>
        <category><![CDATA[默认分类]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/21758fadc588f2034b36d697.html</guid>
</item>

<item>
        <title><![CDATA[通信用光耦]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/145a08fdc672b71c09244dc4.html]]></link>
        <description><![CDATA[
		
		100K bit/S:<br>
6N138、6N139、PS8703<br>
<br>
1M bit/S:<br>
6N135、6N136、CNW135、CNW136、PS8601、PS8602、PS8701、PS9613、PS9713、CNW4502、HCPL-2503、HCPL-4502、HCPL-2530（双路）、HCPL-2531（双路）<br>
<br>
10M bit/S:<br>
6N137、PS9614、PS9714、PS9611、PS9715、HCPL-2601、HCPL-2611、HCPL-2630（双路）、HCPL－2631（双路）<br>
<br>
另外，台湾COSMO公司的KP7010在RL选值为300欧左右时，我根据其数据手册所载数值计算，速率可达100Kbit/S，且为6脚封装，比同级的6N138、6N139小巧，价格也较低。 <br> <a href="http://hi.baidu.com/52elec/blog/item/145a08fdc672b71c09244dc4.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%E7%D7%D3">电子</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/145a08fdc672b71c09244dc4.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-20  17:01</pubDate>
        <category><![CDATA[电子]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/145a08fdc672b71c09244dc4.html</guid>
</item>

<item>
        <title><![CDATA[传感器相关知识]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/fc8104a145f22e814610640b.html]]></link>
        <description><![CDATA[
		
		<div class="cnt"><font face="宋体" size="1">一、传感器的定义 <br>
国家标准GB7665-87对传感器下的定义是：&ldquo;能感受规定的被测量并按照一定的规律转换成可用信号的器件或装置，通常由敏感元件和转换元件组成&rdquo;。传感器是一种检测装置，能感受到被测量的信息，并能将检测感受到的信息，按一定规律变换成为电信号或其他所需形式的信息输出，以满足信息的传输、处理、存储、显示、记录和控制等要求。它是实现自动检测和自动控制的首要环节。 <br>
<br>
二、传感器技术<br>
传感器的标定技术，即通过实验的方法以确定传感器的各种特性指标；抗干扰技<br>
术，即提高传感器的信噪比，以减少测量误差等；接口技术，即是与<br>
微型计算机组成的传感系统。这三者被称为传感器的&ldquo;软件&rdquo;技术。<br>
<br>
三、传感器的分类<br>
目前对传感器尚无一个统一的分类方法，但比较常用的有如下三种： <br>
　　１、按传感器的物理量分类，可分为位移、力、速度、温度、流量、气体成份等传感器 <br>
　　２、按传感器工作原理分类，可分为电阻、电容、电感、电压、霍尔、光电、光栅、热电偶等传感器。 <br>
　　３、按传感器输出信号的性质分类，可分为：输出为开关量（&ldquo;１&rdquo;和&quot;０&rdquo;或&ldquo;开&rdquo;和&ldquo;关&rdquo;）的开关型传感器；输出为模拟型传感器；输出为脉冲或代码的数字型传感器。<br>
<br>
四、传感器的静态特性<br>
传感器的静态特性是指对静态的输入信号，传感器的输出量与输入量之间所具有相互关系。因为这时输入量和输出量都和时间无关，所以它们之间的关系，即传感器的静态特性可用一个不含时间变量的代数方程，或以输入量作横坐标，把与其对应的输出量作纵坐标而画出的特性曲线来描述。表征传感器静态特性的主要参数有：线性度、灵敏度、分辨力和迟滞等<br>
<br>
五、传感器的动态特性<br>
&nbsp;&nbsp;  　所谓动态特性，是指传感器在输入变化时，它的输出的特性。在实际工作中，传感器的动态特性常用它对某些标准输入信号的响应来表示。这是因为传感器对标准输入信号的响应容易用实验方法求得，并且它对标准输入信号的响应与它对任意输入信号的响应之间存在一定的关系，往往知道了前者就能推定后者。最常用的标准输入信号有阶跃信号和正弦信号两种，所以传感器的动态特性也常用阶跃响应和频率响应来表示。 <br>
<br>
很多传感器要在动态条件下检测，被测量可能以各种形式随时间变化。只要输入量是时间的函数，则其输出量也将是时间的函数，其间关系要用动特性来说明。设计传感器时要根据其动态性能要求与使用条件选择合理的方案和确定合适的参数；使用传感器时要根据其动态特性与使用条件确定合适的使用方法，同时对给定条件下的传感器动态误差作出估计。总之，动特性是传感器性能的一个重要方面，对其进行研究与分析十分必要。总的来说，传感器的动特性取决于传感器本身，另一方面也与被测量的形式有关。 <br>
<br>
（1）规律性的：1）周期性的：正弦周期输入、复杂周期输入；2）非周期性的：阶跃输入、线性输入、其他瞬变输入 <br>
（2）随机性的：1）平稳的：多态历经过程、非多态历经过程；2）非平稳的随机过程。 <br>
<br>
在研究动态特性时，通常只能根据&ldquo;规律性&rdquo;的输入来考虑传感器的响应。复杂周期输入信号可以分解为各种谐波，所以可用正弦周期输入信号来代替。其它瞬变输入不及阶跃输入来得严峻，可用阶跃输入代表。因此，&ldquo;标准&rdquo;输入只有三种；正弦周期输入、阶跃输入和线性输入。而经常使用的是前两种。 <br>
<br>
六、传感器的线性度<br>
&nbsp;&nbsp;  　通常情况下，传感器的实际静态特性输出是条曲线而非直线。在实际工作中，为使仪表具有均匀刻度的读数，常用一条拟合直线近似地代表实际的特性曲线、线性度（非线性误差）就是这个近似程度的一个性能指标。 <br>
　　拟合直线的选取有多种方法。如将零输入和满量程输出点相连的理论直线作为拟合直线；或将与特性曲线上各点偏差的平方和为最小的理论直线作为拟合直线，此拟合直线称为最小二乘法拟合直线。 <br>
<br>
七、传感器的灵敏度<br>
　　灵敏度是指传感器在稳态工作情况下输出量变化△y对输入量变化△x的比值。 <br>
<br>
　　它是输出一输入特性曲线的斜率。如果传感器的输出和输入之间显线性关系，则灵敏度S是一个常数。否则，它将随输入量的变化而变化。 <br>
　　灵敏度的量纲是输出、输入量的量纲之比。例如，某位移传感器，在位移变化1mm时，输出电压变化为200mV，则其灵敏度应表示为200mV/mm。 <br>
　　当传感器的输出、输入量的量纲相同时，灵敏度可理解为放大倍数。 <br>
　　提高灵敏度，可得到较高的测量精度。但灵敏度愈高，测量范围愈窄，稳定性也往往愈差。 <br>
<br>
八、传感器的分辨力<br>
分辨力是指传感器可能感受到的被测量的最小变化的能力。也就是说，如果输入量从某一非零值缓慢地变化。当输入变化值未超过某一数值时，传感器的输出不会发生变化，即传感器对此输入量的变化是分辨不出来的。只有当输入量的变化超过分辨力时，其输出才会发生变化。 <br>
　　通常传感器在满量程范围内各点的分辨力并不相同，因此常用满量程中能使输出量产生阶跃变化的输入量中的最大变化值作为衡量分辨力的指标。上述指标若用满量程的百分比表示，则称为分辨率。 <br>
<br>
九、传感器的迟滞特性<br>
　　迟滞特性表征传感器在正向（输入量增大）和反向（输入量减小）行程间输出-一输入特性曲线不一致的程度，通常用这两条曲线之间的最大差值△MAX与满量程输出F·S的百分比表示。 <br>
　　迟滞可由传感器内部元件存在能量的吸收造成。<br>
</font><strong><font face="宋体" size="1">各种传感器相关知识<br>
<br>
</font></strong><font size="1"><font face="宋体">一、温度传感器<br>
&nbsp;&nbsp;  温度是一个基本的物理量，自然界中的一切过程无不与温度密切相关。温度传感器是最早开发，应用最广的一类传感器。根据美国仪器学会的调查，1990年，温度传感器的市场份额大大超过了其他的传感器。从17世纪初伽利略发明温度计开始，人们开始利用温度进行测量。真正把温度变成电信号的传感器是1821年由德国物理学家赛贝发明的，这就是后来的热电偶传感器。五十年以后，另一位德国人西门子发明了铂电阻温度计。在半导体技术的支持下，本世纪相继开发了半导体热电偶传感器、PN结温度传感器和集成温度传感器。与之相应，根据波与物质的相互作用规律，相继开发了声学温度传感器、红外传感器和微波传感器。 <br>
<br>
我们现在主要介绍常用的热电偶温度传感器。比如两种不同材质的导体，如在某点互相连接在一起，对这个连接点加热，在它们不加热的部位就会出现电位差。这个电位差的数值与不加热部位测量点的温度有关，和这两种导体的材质有关。这种现象可以在很宽的温度范围内出现，如果精确测量这个电位差，再测出不加热部位的环境温度，就可以准确知道加热点的温度。由于它必须有两种不同材质的导体，所以称之为&ldquo;热电偶&rdquo;。不同材质作出的热电偶使用于不同的温度范围，它们的灵敏度也各不相同。热电偶的灵敏度是指加热点温度变化1 摄氏度时，输出电位差的变化量。对于大多数金属材料支撑的热电偶而言，这个数值大约在5 到40微伏每摄氏度之间。 <br>
<br>
由于构成热电偶的金属材料可以耐受很高的温度，例如钨铼热电偶能够工作在2000摄氏度以上的高温，常常用来检测高温环境的热物理参数，还有的材料能够在低温下工作，例如金铁热电偶能够在液氮的温度附近工作。可见热电偶传感器能够在很广泛的温度范围内工作。 <br>
<br>
热电偶传感器有自己的优点和缺陷，它灵敏度比较低，容易受到环境干扰信号的影响，也容易受到前置放大器温度漂移的影响，因此不适合测量微小的温度变化。由于热电偶温度传感器的灵敏度与材料的粗细无关，用非常细的材料也能够做成温度传感器。也由于制作热电偶的金属材料具有很好的延展性，这种细微的测温元件有极高的响应速度，可以测量快速变化的过程，如燃烧和爆炸过程等。对一般的工业应用来说，为了保护感温元件避免受到腐蚀和磨损，总是装在厚厚的护套里面，外观就显得笨大，对于温度场的反应也就迟缓得多。使用热电偶的时候，必须消除环境温度的波动对测量带来的影响。有的把它的自由端放在不变的温度场中，有的使用冷端补偿器抵消这种影响。当测量点远离仪表时，还需要使用热点势率和热电偶相近的导线来传输信号，这种导线称为补偿导线。 <br>
<br>
温度传感器是五花八门的各种传感器中最为常用的一种，现代的温度传感器外形非常得小，这样更加让它广泛应用在生产实践的各个领域中，也为我们的生活提供了无数的便利和功能。<br>
<br>
二、热电阻传感器<br>
热电阻传感器主要是利用电阻值随温度变化而变化这一特性来测量温度及与温度有关的参数。在温度检测精度要求比较高的场合，这种传感器比较适用。目前较为广泛的热电阻材料为铂、铜、镍等，它们具有电阻温度系数大、线性好、性能稳定、使用温度范围宽、加工容易等特点。用于测量-200℃～+500℃范围内的温度 <br>
<br>
三、压阻式传感器<br>
压阻式传感器是根据半导体材料的压阻效应在半导体材料的基片上经扩散电阻而制成的器件。其基片可直接作为测量传感元件，扩散电阻在基片内接成电桥形式。当基片受到外力作用而产生形变时，各电阻值将发生变化，电桥就会产生相应的不平衡输出。 <br>
<br>
四、电阻式传感器<br>
　电阻式传感器是将被测量，如位移、形变、力、加速度、湿度、温度等这些物理量转换式成电阻值这样的一种器件。主要有电阻应变式、压阻式、热电阻、热敏、气敏、湿敏等电阻式传感器件。 <br>
<br>
五、电阻应变式传感器<br>
传感器中的电阻应变片具有金属的应变效应，即在外力作用下产生机械形变，从而使电阻值随之发生相应的变化。电阻应变片主要有金属和半导体两类，金属应变片有金属丝式、箔式、薄膜式之分。半导体应变片具有灵敏度高（通常是丝式、箔式的几十倍）、横向效应小等优点。</font><br>
</font><strong><font face="宋体" size="1">传感器选用原则<br>
<br>
</font></strong><font face="宋体" size="1">现代传感器在原理与结构上千差万别，如何根据具体的测量目的、测量对象以及测量<br>
　　环境合理地选用传感器，是在进行某个量的测量时首先要解决的问题。当传感器确定之后，与之相配套的测量方法和测量设备也就可以确定了。测量结果的成败，在很大程度上取决于传感器的选用是否合理。<br>
　　1、根据测量对象与测量环境确定传感器的类型<br>
　　要进行&mdash;个具体的测量工作，首先要考虑采用何种原理的传感器，这需要分析多方面的因素之后才能确定。因为，即使是测量同一物理量，也有多种原理的传感器可供选用，哪一种原理的传感器更为合适，则需要根据被测量的特点和传感器的使用条件考虑以下一些具体问题：量程的大小；被测位置对传感器体积的要求；测量方式为接触式还是非接触式；信号的引出方法，有线或是非接触测量；传感器的来源，国产还是进口，价格能否承受，还是自行研制。<br>
　　在考虑上述问题之后就能确定选用何种类型的传感器，然后再考虑传感器的具体性能指标。<br>
　　2、灵敏度的选择<br>
　　通常，在传感器的线性范围内，希望传感器的灵敏度越高越好。因为只有灵敏度高时，与被测量变化对应的输出信号的值才比较大，有利于信号处理。但要注意的是，传感器的灵敏度高，与被测量无关的外界噪声也容易混入，也会被放大系统放大，影响测量精度。因此，要求传感器本身应具有较高的信噪比，尽员减少从外界引入的厂扰信号。<br>
<br>
　　传感器的灵敏度是有方向性的。当被测量是单向量，而且对其方向性要求较高，则应选择其它方向灵敏度小的传感器；如果被测量是多维向量，则要求传感器的交叉灵敏度越小越好。<br>
<br>
　　3、频率响应特性<br>
<br>
　　传感器的频率响应特性决定了被测量的频率范围，必须在允许频率范围内保持不失真的测量条件，实际上传感器的响应总有&mdash;定延迟，希望延迟时间越短越好。<br>
<br>
　　传感器的频率响应高，可测的信号频率范围就宽，而由于受到结构特性的影响，机械系统的惯性较大，因有频率低的传感器可测信号的频率较低。<br>
<br>
　　在动态测量中，应根据信号的特点(稳态、瞬态、随机等)响应特性，以免产生过火的误差。<br>
<br>
　　4、线性范围<br>
<br>
　　传感器的线形范围是指输出与输入成正比的范围。以理论上讲，在此范围内，灵敏度保持定值。传感器的线性范围越宽，则其量程越大，并且能保证一定的测量精度。在选择传感器时，当传感器的种类确定以后首先要看其量程是否满足要求。<br>
<br>
　　但实际上，任何传感器都不能保证绝对的线性，其线性度也是相对的。当所要求测量精度比较低时，在一定的范围内，可将非线性误差较小的传感器近似看作线性的，这会给测量带来极大的方便。<br>
<br>
　　5、稳定性<br>
<br>
　　传感器使用一段时间后，其性能保持不变化的能力称为稳定性。影响传感器长期稳定性的因素除传感器本身结构外，主要是传感器的使用环境。因此，要使传感器具有良好的稳定性，传感器必须要有较强的环境适应能力。<br>
<br>
　　在选择传感器之前，应对其使用环境进行调查，并根据具体的使用环境选择合适的传感器，或采取适当的措施，减小环境的影响。<br>
　　传感器的稳定性有定量指标，在超过使用期后，在使用前应重新进行标定，以确定传感器的性能是否发生变化。<br>
　　在某些要求传感器能长期使用而又不能轻易更换或标定的场合，所选用的传感器稳定性要求更严格，要能够经受住长时间的考验。<br>
　　6、精度<br>
<br>
　　精度是传感器的一个重要的性能指标，它是关系到整个测量系统测量精度的一个重要环节。传感器的精度越高，其价格越昂贵，因此，传感器的精度只要满足整个测量系统的精度要求就可以，不必选得过高。这样就可以在满足同一测量目的的诸多传感器中选择比较便宜和简单的传感器。<br>
<br>
　　如果测量目的是定性分析的，选用重复精度高的传感器即可，不宜选用绝对量值精度高的；如果是为了定量分析，必须获得精确的测量值，就需选用精度等级能满足要求的传感器。<br>
<br>
　　对某些特殊使用场合，无法选到合适的传感器，则需自行设计制造传感器。自制传感器的性能应满足使用要求。</font></div> <a href="http://hi.baidu.com/52elec/blog/item/fc8104a145f22e814610640b.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%E7%D7%D3">电子</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/fc8104a145f22e814610640b.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-17  08:54</pubDate>
        <category><![CDATA[电子]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/fc8104a145f22e814610640b.html</guid>
</item>

<item>
        <title><![CDATA[关于时钟线/数据线/地址线上串联电阻其作用的资料整理]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/e4bccecfbe33c537f9dc61e4.html]]></link>
        <description><![CDATA[
		
		<p style="text-indent: 2em">关于时钟线/数据线/地址线上串联电阻其作用的资料整理(转)</p>
<p style="text-indent: 2em">1、概括：</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  高速信号线中才考虑使用这样的电阻。在低频情况下，一般是直接连接。&nbsp;&nbsp;</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  这个电阻有两个作用，第一是阻抗匹配。因为信号源的阻抗很低，跟信号线之间阻抗不匹配（关于阻抗匹配，请看详述），串上一个电阻后，可改善匹配情况，以减少反射，避免振荡等。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  第二是可以减少信号边沿的陡峭程度，从而减少高频噪声以及过冲等。因为串联的电阻，跟信号线的分布电容以及负载的输入&nbsp;&nbsp;&nbsp;  电容等形成一个RC 电路，这样就会降低信号边沿的陡峭程度。大家知道，如果一个信号的边沿非常陡峭，含有大量的高频成分，将会辐射干扰，另外，也容易产生过冲。</p>
<p style="text-indent: 2em">2、 详述（阻抗匹配）</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  阻抗匹配是指信号源或者传输线跟负载之间的一种合适的搭配方式。阻抗匹配分为低频和高频两种情况讨论。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  我们先从直流电压源驱动一个负载入手。由于实际的电压源，总是有内阻的（请参看输出阻抗一问），我们可以把一个实际电压源，等效成一个理想的电压源跟一个电阻r串联的模型。假设负载电阻为R，电源电动势为U，内阻为r，那么我们可以计算出流过电阻R的电流为：I=U/(R+r)，可以看出，负载电阻R越小，则输出电流越大。负载R上的电压为：Uo=IR=U/[1+(r/R)]，可以看出，负载电阻R越大，则输出电压Uo越高。再来计算一下电阻R消耗的功率为：</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  P=I2×R=[U/(R+r)]2×R=U2×R/(R2+2×R×r+r2)</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  =U2×R/[(R-r)2+4×R×r]</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  =U2/{[(R-r)2/R]+4×r}</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  对于一个给定的信号源，其内阻r是固定的，而负载电阻R则是由我们来选择的。注意式中[(R-r)2/R]，当R=r时，[(R-r)2/R]可取得最小值0，这时负载电阻R上可获得最大输出功率Pmax=U2/(4×r)。即，当负载电阻跟信号源内阻相等时，负载可获得最大输出功率，这就是我们常说的阻抗匹配之一。对于纯电阻电路，此结论同样适用于低频电路及高频电路。当交流电路中含有容性或感性阻抗时，结论有所改变，就是需要信号源与负载阻抗的的实部相等，虚部互为相反数，这叫做共扼匹配。在低频电路中，我们一般不考虑传输线的匹配问题，只考虑信号源跟负载之间的情况，因为低频信号的波长相对于传输线来说很长，传输线可以看成是&ldquo;短线&rdquo;，反射可以不考虑（可以这么理解：因为线短，即使反射回来，跟原信号还是一样的）。从以上分析我们可以得出结论：如果我们需要输出电流大，则选择小的负载R；如果我们需要输出电压大，则选择大的负载R；如果我们需要输出功率最大，则选择跟信号源内阻匹配的电阻R。有时阻抗不匹配还有另外一层意思，例如一些仪器输出端是在特定的负载条件下设计的，如果负载条件改变了，则可能达不到原来的性能，这时我们也会叫做阻抗失配。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  在高频电路中，我们还必须考虑反射的问题。当信号的频率很高时，则信号的波长就很短，当波长短得跟传输线长度可以比拟时，反射信号叠加在原信号上将会改变原信号的形状。如果传输线的特征阻抗跟负载阻抗不相等（即不匹配）时，在负载端就会产生反射。为什么阻抗不匹配时会产生反射以及特征阻抗的求解方法，牵涉到二阶偏微分方程的求解，在这里我们不细说了，有兴趣的可参看电磁场与微波方面书籍中的传输线理论。传输线的特征阻抗（也叫做特性阻抗）是由传输线的结构以及材料决定的，而与传输线的长度，以及信号的幅度、频率等均无关。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  例如，常用的闭路电视同轴电缆特性阻抗为75Ω，而一些射频设备上则常用特征阻抗为50Ω的同轴电缆。另外还有一种常见的传输线是特性阻抗为300Ω的扁平平行线，这在农村使用的电视天线架上比较常见，用来做八木天线的馈线。因为电视机的射频输入端输入阻抗为75Ω，所以300Ω的馈线将与其不能匹配。实际中是如何解决这个问题的呢？不知道大家有没有留意到，电视机的附件中，有一个300Ω到75Ω的阻抗转换器（一个塑料封装的，一端有一个圆形的插头的那个东东，大概有两个大拇指那么大）。它里面其实就是一个传输线变压器，将300Ω的阻抗，变换成75Ω的，这样就可以匹配起来了。这里需要强调一点的是，特性阻抗跟我们通常理解的电阻不是一个概念，它与传输线的长度无关，也不能通过使用欧姆表来测量。为了不产生反射，负载阻抗跟传输线的特征阻抗应该相等，这就是传输线的阻抗匹配。如果阻抗不匹配会有什么不良后果呢？如果不匹配，则会形成反射，能量传递不过去，降低效率；会在传输线上形成驻波（简单的理解，就是有些地方信号强，有些地方信号弱），导致传输线的有效功率容量降低；功率发射不出去，甚至会损坏发射设备。如果是电路板上的高速信号线与负载阻抗不匹配时，会产生震荡，辐射干扰等。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  当阻抗不匹配时，有哪些办法让它匹配呢？第一，可以考虑使用变压器来做阻抗转换，就像上面所说的电视机中的那个例子那样。第二，可以考虑使用串联/并联电容或电感的办法，这在调试射频电路时常使用。第三，可以考虑使用串联/并联电阻的办法。一些驱动器的阻抗比较低，可以串联一个合适的电阻来跟传输线匹配，例如高速信号线，有时会串联一个几十欧的电阻。而一些接收器的输入阻抗则比较高，可以使用并联电阻的方法，来跟传输线匹配，例如，485总线接收器，常在数据线终端并联120欧的匹配电阻。</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  为了帮助大家理解阻抗不匹配时的反射问题，我来举两个例子：假设你在练习拳击&mdash;&mdash;打沙包。如果是一个重量合适的、硬度合适的沙包，你打上去会感觉很舒服。但是，如果哪一天我把沙包做了手脚，例如，里面换成了铁沙，你还是用以前的力打上去，你的手可能就会受不了了&mdash;&mdash;这就是负载过重的情况，会产生很大的反弹力。相反，如果我把里面换成了很轻很轻的东西，你一出拳，则可能会扑空，手也可能会受不了&mdash;&mdash;这就是负载过轻的情况。另一个例子，不知道大家有没有过这样的经历：就是看不清楼梯时上/下楼梯，当你以为还有楼梯时，就会出现&ldquo;负载不匹配&rdquo;这样的感觉了。当然，也许这样的例子不太恰当，但我们可以拿它来理解负载不匹配时的反射情况。</p> <a href="http://hi.baidu.com/52elec/blog/item/e4bccecfbe33c537f9dc61e4.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%E7%D7%D3">电子</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/e4bccecfbe33c537f9dc61e4.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-16  14:35</pubDate>
        <category><![CDATA[电子]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/e4bccecfbe33c537f9dc61e4.html</guid>
</item>

<item>
        <title><![CDATA[单片机设计与KeilC编程总结(转)]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/ca902eef13c5e2e5ce1b3eeb.html]]></link>
        <description><![CDATA[
		
		1基本原则  <br>
<br>
质量是关键。没有人会对很差的工作感到满足。当完成高质量的工作时，你会为此而感到骄傲。不管你是否知道，你都会因为你的高质量工作而得到信誉。因此，要想为自己所做的事感到骄傲，就需要建立个人标准，并为达到这一标准而努力奋斗。在达到这些标准时，再提高标准并继续努力。挑战自己去完成更优良的工作，你将会为自己的成就而感到惊讶。  <br>
<br>
1.1 了解单片机的能力  <br>
【规则1】设计满足要求的最精简的系统。  <br>
<br>
正确估计单片机的能力，知道单片机能做什么，最大程度的挖掘单片机的潜力对一个单片机系统设计者来说是至关重要的。我们应该有这样一个认识，即单片机的处理能力是非常强大的。早期的PC 机，其CPU（8086）处理能力和8051 相当，却能处理相当复杂的任务。单片机的能力的关键就在软件设计者编写的软件上。只有充分地了解到单片机的能力，才不会做出&ldquo;冗余&rdquo;的系统设计。而采用许多的外围芯片来实现单片机能实现的功能。这样做,即增加了系统成本，也可能会降低了系统的可靠性。  <br>
<br>
1.2 系统可靠性至关重要  <br>
【规则2】使用看门狗。  <br>
<br>
看门狗电路通常是一块在有规律的时间间隔中进行更新的硬件。更新一般由单片机来完成，如果在一定间隔内没能更新看门狗，那看门狗将产生复位信号，重新复位单片机。更新看门狗的具体形式多是给看门狗芯片相关引脚提供一个电平上升沿或读写它的某个寄存器。使用看门狗电路将在单片机发生故障进行死机状态时，重新复位单片机。当前有多种看门狗的芯片，如MAXIM 公司的MAX802，MAX813等。而且，有好多种单片机中本身就集成有看门狗。一个外部的看门狗是最好的，因为它不依赖于单片机。如果可能的话，看门狗更新程序不应该放在中断或是子程序中，原则上应该放在主程序中。我曾经见过一个工程师，他所调试的程序在运行时偶而会引起看门狗的复位动作，于是他干脆在每10ms 就中断一次的时钟中断程序中清看门狗。我相信他也知道使看门狗失去作用，可他却没有不是去查明引起这个现象的真正原因。因此，我想提醒大家：不论什么理由，绝对不要忽略系统故障的真正原因。高质量的产品来自于高素质的工程师，高质量的产品造就高素质的工程师。  <br>
<br>
【规则3】确定系统的复位信号可靠。  <br>
<br>
这是一个很容易忽略的问题。当你在设计单片机系统时，你脑中有这个概念吗？什么样的复位信号才是可靠的吗？你用示波器查看过你设计的产品的复位信号吗？不稳定的复位信号可能会产生什么样的后果？你有没有发现过你所设计的单片机系统，每次重新上电启动后，数据变得乱七八糟，并且每一次现象并不相同，找不出规律，或者有时候干脆不运行，或者有时候进入一种死机状态，有时候又一点事都没有正常运行？在这种情况下，你应该查一下你的系统的复位信号。一般在单片机的数据手册（Datasheet）中都会提到该单片机需要的复位信号的要求。一般复位信号的宽度应为。复位电平的宽度和幅度都应满足芯片的要求，并且要求保持稳定。还有特别重要的一点就是复位电平应与电源上电在同一时刻发生，即芯片一上电，复位信号就已产生。不然，由于没有经过复位，单片机中的寄存器的值为随机值，上电时就会按PC 寄存器中的随机内容开始运行程序，这样很容易进行误操作或进入死机状态。  <br>
<br>
【规则4】确定系统的初始化有效。  <br>
<br>
系统程序开始应延时一段时间。这是很多单片机程序设计中的常用方法，为什么呢？因为系统中的芯片以及器件从上电开始到正常工作的状态往往有一段时间，程序开始时延时一段时间，是让系统中所有器件到达正常工作状态。究竟延时多少才算合适？这取决于系统的各芯片中到达正常工作状态的时间，通常以最慢的为准。一般来说，延时20-100 毫秒已经足够。对于系统中使用嵌入式MODEM 等&ldquo;慢热&rdquo;型的器件来说，则应更长。当然，这都需要在系统实际运行中进行调整。  <br>
<br>
【规则5】上电时对系统进行检测。  <br>
<br>
上电时对系统中进行检测是单片机程序中的一个良好设计。在硬件设计时也应该细细考虑将各个使用到的芯片、接口设计成容易使用软件进行测试的模式。很多有经验的单片机设计者都会在系统上电时（特别是第一次上电时）进行全面的检测，或者更进一步，将系统的运行状态中分为测试模式和正常运行模式，通过加入测试模式对系统进行详细的检测，使得系统的批量检测更为方便容易。另外要注意的是，一个简单明了的故障显示界面也是颇要费得心思的。比如：系统的外部RAM（数据存储器）是单片机系统中常用的器件。外部RAM 如果存在问题，程序通常都会成为一匹脱缰的野马。因此，程序在启动时（至少在第一次上电启动时）一定要对外部RAM 进行检测。检测内容包括： <br>
1）检测RAM 中的单元。这主要通过写入和读出的数据保持一致。  <br>
2）检测单片机与RAM 之间的地址数据总线。总线即没有互相短路，也没有连接到&ldquo;地&rdquo;上。另外，很多芯片，都提供了测试的方法。如串行通信芯片UART，都带环路测试的功能。  <br>
<br>
【规则6】按EMC 测试要求设计硬件。  <br>
EMC 测试要求已经成为产品的必需。有很多的文章关于这方面的。  <br>
<br>
1.3 软件编程和调试  <br>
【规则7】尽可能使用Small 模式编译  <br>
<br>
对比起Large 模式和Compact 模式，Small 模式能生成更为紧凑的代码。在Small模式下，C51 编译器将没有使用关键词，如idata、pdata、xdata 特殊声明的变量通通放在data 单元中。在编程中，对于在的数据区，可以指定放在外部存储器中。  <br>
<br>
【规则8】在仿真前做好充分的准备  <br>
单片机硬件仿真器给单片机开发者带来了极大的方便，同时也很容易造成人的依赖性。很多时候，没有仿真器却能促使工程师写出更高质量的程序。也许在硬件仿真调试之前，下面准备工作将会对你有用：  <br>
1）程序编完后，对代码仔细逐行检查。检查代码的错误，建立自己的代码检查表，对经常易错的地方进行检查。检查代码是否符合编程规范。  <br>
2）对各个子程序进行测试。测试的方法：用程序测试程序，编制一个调用该子程序的代码，建立要测试子程序的入口条件，再看看它是否按预期输出结果。  <br>
3）如果代码有修改，再次对代码进行检查。  <br>
4）有可能的话，进行软件仿真&mdash;&mdash;Keil C 的软件仿真功能十分强大。软件仿真可以防止因硬件的错误，如器件损坏、线路断路或短路，而引起调试的错误。  <br>
5）开始硬件仿真。  <br>
<br>
【规则9】使用库函数  <br>
重用代码，尤其是是标准库的代码，而不是手工编写你自己的代码。这样更快、更容易也更安全。KeilC 中提供了多个库函数，这些库函数的用法在KeilC 的帮助文件中有详细的描述。  <br>
<br>
【规则10】使用const。  <br>
<br>
这一点在很多经典的关于C 和C++的书籍中是必谈的要点。在《Exceptional C++》一书中，对这点有很精彩的描述，现摘录如下：&ldquo;没有正确的安全意识的枪手在世界上是不可能活的很长的。const 观念不正确的程序员也是一样和没有时间戴紧帽子的正确，没有时间检查带电电线的电工一样不会活的很长。&rdquo;在C 语言中，const 修饰符表示告诉编译器此函数将不会改变被修饰的变量的指向的任何值（除了强制类型转换）。当把指针作为参数传递时，总是合适地使用const，不仅可以防止你无意中错误的赋值，而且还可以防止在作为参数将指针传递给函数时可能会修改了本不想改变的指针所指向的对象的值。如：  <br>
const int num= 7;  <br>
num = 9; //有/可能得到编译器的警告。  <br>
const char *ptr，则表示该指针所指向的内容不会被改变，如果在程序中被发生对其赋值的操作，编译时将出错误提示。如：  <br>
const char *ptr = &ldquo;hello&rdquo;;  <br>
*ptr = 'H';//错误，所指内容不可改变也可将const 放在星号后面来声明指针本身不可改变。如:  <br>
char* const ptr;  <br>
ptr++; //错误，指针本身不可改变  <br>
也可同时禁止改变指针和它所引用的内容，其形式如下： const char* const ptr;  <br>
<br>
【规则11】使用static  <br>
<br>
static 是一个能够减少命名冲突的有用工具。将只在一个模块文件中的变量和函数使用static 修饰，将不会和其他模块可能具有相同名称的函数和变量在模块连接时不会产生名称冲突。一般来说，只要不是提供给其它模块使用的函数，和非全局变量，均应使用static 修饰。将子程序中的变量使用static 修饰时，表示这个变量在程序开始时分配内存，在程序结束时释放，它们在程序执行期间保持它们的值。如：  <br>
void func1(void)  <br>
{  <br>
static int time = 0;  <br>
time++  <br>
}  <br>
void func2(void)  <br>
{  <br>
static int time = 0;  <br>
time++;  <br>
}  <br>
两个子程序中的time 变量使用static 修饰，所以它们是静态变量，每调用一次time将进行加1，并保持这个值。它们的功能与下面程序相似：  <br>
int time1 = 0;  <br>
int time2 = 0;  <br>
void func1(void)  <br>
{  <br>
time1++  <br>
}  <br>
void func2(void)  <br>
{  <br>
time2++;  <br>
}  <br>
我们可以看出，使用static 修饰后，模块中的全局变量减少，使得程序的更为简单。  <br>
<br>
【规则12】不要忽视编译器的警告。  <br>
编译器的给出的警告都是有的放矢，在没有查清引起警告的真正原因之前，不要忽视它。  <br>
<br>
【规则13】注意溢出问题，写安全的代码。  <br>
<br>
1.4 KeilC 编程  <br>
【规则14】深入了解你所用的工具。  <br>
仔细查看KeilC 附带的帮助文件，你能找到你期待已久的东西。KeilC 是当前最好用的单片机开发软件。要充分利用该软件的功能，就必须对它深入的进行了解。  <br>
<br>
【规则15】不要使用语言的冷僻特性，并且记住，耍小聪明会贻害无穷。最重要的是编写你理解的代码，理解你编写的代码，你就可能会做得很好。  <br>
<br>
2 推荐书目  <br>
要成为一个优秀的单片机系统产品设计工程师，兴趣、热情、责任心至关重要。  <br>
2.1 单片机技术学习  <br>
《微机原理及应用(从16 位到32 位) 》戴梅萼等著清华大学出版社。学校教材，也是当年我学习单片机的启蒙书。  <br>
2.2 C51 编程学习  <br>
《单片机高级语言C51 Windows 环境编程与应用》作者:徐爱钧彭秀华电子工业出版社。这本书几乎覆盖了C51 编程的方方面面，最新版本对当前使用最广的keilC 也有很详细的讲述。对于刚学C51 编程的同志，本书是上上之选，强力推荐。比起现今书市上的所谓什么&ldquo;C51 编程圣经&rdquo;之类的书强得多。  <br>
2.3 C 语言编程必读  <br>
《C 陷阱与缺陷》Andrew Koenig 著  <br>
《C 专家编程》Peter Van Der Linden 著  <br>
C 语言开发技术经典之作，C 程序员必读之书，数十年来经久不衰。如果你想对C语言全面的掌握，真正了解C 语言的精髓，这两本书是必读之作。由人民邮电出版社出版的中文译本也还不错。  <br>
2.4 程序设计技术方面  <br>
《数据结构》, 严蔚敏, 清华大学出版社。清华大学出版社的教材质量稳定，中规中矩，价格相对来说也便宜一点。  <br>
《程序设计实践》Brian W. Kernighan, Rob Pike 著；《代码大全》（网上有下载）。这两本是能让你看后，感觉有大突破的那种书籍，千万别吝惜银子。  <br>
<br>
3 后记  <br>
<br>
从事单片机开发工作已经有差不多三年时间了，自己感觉积累了一些经验和体会。这篇文章就算是一个总结吧。本来想写的更为详细一些，加入C51 中指针及uvision 软件仿真的一些使用体会，以及自己的一些开发实践，但一想，keil c 中的说明书已经够详细了，而我的开发产品所有权又不属于我本人，因此，并没有深入下去。由于本人水平有限，这次也是抱着与各位交流学习的目的，非常欢迎各位与我联系交流，共同探讨。  <br> <a href="http://hi.baidu.com/52elec/blog/item/ca902eef13c5e2e5ce1b3eeb.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%A5%C6%AC%BB%FA%D1%A7%CF%B0">单片机学习</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/ca902eef13c5e2e5ce1b3eeb.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-07  22:55</pubDate>
        <category><![CDATA[单片机学习]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/ca902eef13c5e2e5ce1b3eeb.html</guid>
</item>

<item>
        <title><![CDATA[单片机设计与KeilC编程总结(转)]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/40a3f14a34a7032909f7efeb.html]]></link>
        <description><![CDATA[
		
		1基本原则  <br>
<br>
质量是关键。没有人会对很差的工作感到满足。当完成高质量的工作时，你会为此而感到骄傲。不管你是否知道，你都会因为你的高质量工作而得到信誉。因此，要想为自己所做的事感到骄傲，就需要建立个人标准，并为达到这一标准而努力奋斗。在达到这些标准时，再提高标准并继续努力。挑战自己去完成更优良的工作，你将会为自己的成就而感到惊讶。  <br>
<br>
1.1 了解单片机的能力  <br>
【规则1】设计满足要求的最精简的系统。  <br>
<br>
正确估计单片机的能力，知道单片机能做什么，最大程度的挖掘单片机的潜力对一个单片机系统设计者来说是至关重要的。我们应该有这样一个认识，即单片机的处理能力是非常强大的。早期的PC 机，其CPU（8086）处理能力和8051 相当，却能处理相当复杂的任务。单片机的能力的关键就在软件设计者编写的软件上。只有充分地了解到单片机的能力，才不会做出&ldquo;冗余&rdquo;的系统设计。而采用许多的外围芯片来实现单片机能实现的功能。这样做,即增加了系统成本，也可能会降低了系统的可靠性。  <br>
<br>
1.2 系统可靠性至关重要  <br>
【规则2】使用看门狗。  <br>
<br>
看门狗电路通常是一块在有规律的时间间隔中进行更新的硬件。更新一般由单片机来完成，如果在一定间隔内没能更新看门狗，那看门狗将产生复位信号，重新复位单片机。更新看门狗的具体形式多是给看门狗芯片相关引脚提供一个电平上升沿或读写它的某个寄存器。使用看门狗电路将在单片机发生故障进行死机状态时，重新复位单片机。当前有多种看门狗的芯片，如MAXIM 公司的MAX802，MAX813等。而且，有好多种单片机中本身就集成有看门狗。一个外部的看门狗是最好的，因为它不依赖于单片机。如果可能的话，看门狗更新程序不应该放在中断或是子程序中，原则上应该放在主程序中。我曾经见过一个工程师，他所调试的程序在运行时偶而会引起看门狗的复位动作，于是他干脆在每10ms 就中断一次的时钟中断程序中清看门狗。我相信他也知道使看门狗失去作用，可他却没有不是去查明引起这个现象的真正原因。因此，我想提醒大家：不论什么理由，绝对不要忽略系统故障的真正原因。高质量的产品来自于高素质的工程师，高质量的产品造就高素质的工程师。  <br>
<br>
【规则3】确定系统的复位信号可靠。  <br>
<br>
这是一个很容易忽略的问题。当你在设计单片机系统时，你脑中有这个概念吗？什么样的复位信号才是可靠的吗？你用示波器查看过你设计的产品的复位信号吗？不稳定的复位信号可能会产生什么样的后果？你有没有发现过你所设计的单片机系统，每次重新上电启动后，数据变得乱七八糟，并且每一次现象并不相同，找不出规律，或者有时候干脆不运行，或者有时候进入一种死机状态，有时候又一点事都没有正常运行？在这种情况下，你应该查一下你的系统的复位信号。一般在单片机的数据手册（Datasheet）中都会提到该单片机需要的复位信号的要求。一般复位信号的宽度应为。复位电平的宽度和幅度都应满足芯片的要求，并且要求保持稳定。还有特别重要的一点就是复位电平应与电源上电在同一时刻发生，即芯片一上电，复位信号就已产生。不然，由于没有经过复位，单片机中的寄存器的值为随机值，上电时就会按PC 寄存器中的随机内容开始运行程序，这样很容易进行误操作或进入死机状态。  <br>
<br>
【规则4】确定系统的初始化有效。  <br>
<br>
系统程序开始应延时一段时间。这是很多单片机程序设计中的常用方法，为什么呢？因为系统中的芯片以及器件从上电开始到正常工作的状态往往有一段时间，程序开始时延时一段时间，是让系统中所有器件到达正常工作状态。究竟延时多少才算合适？这取决于系统的各芯片中到达正常工作状态的时间，通常以最慢的为准。一般来说，延时20-100 毫秒已经足够。对于系统中使用嵌入式MODEM 等&ldquo;慢热&rdquo;型的器件来说，则应更长。当然，这都需要在系统实际运行中进行调整。  <br>
<br>
【规则5】上电时对系统进行检测。  <br>
<br>
上电时对系统中进行检测是单片机程序中的一个良好设计。在硬件设计时也应该细细考虑将各个使用到的芯片、接口设计成容易使用软件进行测试的模式。很多有经验的单片机设计者都会在系统上电时（特别是第一次上电时）进行全面的检测，或者更进一步，将系统的运行状态中分为测试模式和正常运行模式，通过加入测试模式对系统进行详细的检测，使得系统的批量检测更为方便容易。另外要注意的是，一个简单明了的故障显示界面也是颇要费得心思的。比如：系统的外部RAM（数据存储器）是单片机系统中常用的器件。外部RAM 如果存在问题，程序通常都会成为一匹脱缰的野马。因此，程序在启动时（至少在第一次上电启动时）一定要对外部RAM 进行检测。检测内容包括： <br>
1）检测RAM 中的单元。这主要通过写入和读出的数据保持一致。  <br>
2）检测单片机与RAM 之间的地址数据总线。总线即没有互相短路，也没有连接到&ldquo;地&rdquo;上。另外，很多芯片，都提供了测试的方法。如串行通信芯片UART，都带环路测试的功能。  <br>
<br>
【规则6】按EMC 测试要求设计硬件。  <br>
EMC 测试要求已经成为产品的必需。有很多的文章关于这方面的。  <br>
<br>
1.3 软件编程和调试  <br>
【规则7】尽可能使用Small 模式编译  <br>
<br>
对比起Large 模式和Compact 模式，Small 模式能生成更为紧凑的代码。在Small模式下，C51 编译器将没有使用关键词，如idata、pdata、xdata 特殊声明的变量通通放在data 单元中。在编程中，对于在的数据区，可以指定放在外部存储器中。  <br>
<br>
【规则8】在仿真前做好充分的准备  <br>
单片机硬件仿真器给单片机开发者带来了极大的方便，同时也很容易造成人的依赖性。很多时候，没有仿真器却能促使工程师写出更高质量的程序。也许在硬件仿真调试之前，下面准备工作将会对你有用：  <br>
1）程序编完后，对代码仔细逐行检查。检查代码的错误，建立自己的代码检查表，对经常易错的地方进行检查。检查代码是否符合编程规范。  <br>
2）对各个子程序进行测试。测试的方法：用程序测试程序，编制一个调用该子程序的代码，建立要测试子程序的入口条件，再看看它是否按预期输出结果。  <br>
3）如果代码有修改，再次对代码进行检查。  <br>
4）有可能的话，进行软件仿真&mdash;&mdash;Keil C 的软件仿真功能十分强大。软件仿真可以防止因硬件的错误，如器件损坏、线路断路或短路，而引起调试的错误。  <br>
5）开始硬件仿真。  <br>
<br>
【规则9】使用库函数  <br>
重用代码，尤其是是标准库的代码，而不是手工编写你自己的代码。这样更快、更容易也更安全。KeilC 中提供了多个库函数，这些库函数的用法在KeilC 的帮助文件中有详细的描述。  <br>
<br>
【规则10】使用const。  <br>
<br>
这一点在很多经典的关于C 和C++的书籍中是必谈的要点。在《Exceptional C++》一书中，对这点有很精彩的描述，现摘录如下：&ldquo;没有正确的安全意识的枪手在世界上是不可能活的很长的。const 观念不正确的程序员也是一样和没有时间戴紧帽子的正确，没有时间检查带电电线的电工一样不会活的很长。&rdquo;在C 语言中，const 修饰符表示告诉编译器此函数将不会改变被修饰的变量的指向的任何值（除了强制类型转换）。当把指针作为参数传递时，总是合适地使用const，不仅可以防止你无意中错误的赋值，而且还可以防止在作为参数将指针传递给函数时可能会修改了本不想改变的指针所指向的对象的值。如：  <br>
const int num= 7;  <br>
num = 9; //有/可能得到编译器的警告。  <br>
const char *ptr，则表示该指针所指向的内容不会被改变，如果在程序中被发生对其赋值的操作，编译时将出错误提示。如：  <br>
const char *ptr = &ldquo;hello&rdquo;;  <br>
*ptr = 'H';//错误，所指内容不可改变也可将const 放在星号后面来声明指针本身不可改变。如:  <br>
char* const ptr;  <br>
ptr++; //错误，指针本身不可改变  <br>
也可同时禁止改变指针和它所引用的内容，其形式如下： const char* const ptr;  <br>
<br>
【规则11】使用static  <br>
<br>
static 是一个能够减少命名冲突的有用工具。将只在一个模块文件中的变量和函数使用static 修饰，将不会和其他模块可能具有相同名称的函数和变量在模块连接时不会产生名称冲突。一般来说，只要不是提供给其它模块使用的函数，和非全局变量，均应使用static 修饰。将子程序中的变量使用static 修饰时，表示这个变量在程序开始时分配内存，在程序结束时释放，它们在程序执行期间保持它们的值。如：  <br>
void func1(void)  <br>
{  <br>
static int time = 0;  <br>
time++  <br>
}  <br>
void func2(void)  <br>
{  <br>
static int time = 0;  <br>
time++;  <br>
}  <br>
两个子程序中的time 变量使用static 修饰，所以它们是静态变量，每调用一次time将进行加1，并保持这个值。它们的功能与下面程序相似：  <br>
int time1 = 0;  <br>
int time2 = 0;  <br>
void func1(void)  <br>
{  <br>
time1++  <br>
}  <br>
void func2(void)  <br>
{  <br>
time2++;  <br>
}  <br>
我们可以看出，使用static 修饰后，模块中的全局变量减少，使得程序的更为简单。  <br>
<br>
【规则12】不要忽视编译器的警告。  <br>
编译器的给出的警告都是有的放矢，在没有查清引起警告的真正原因之前，不要忽视它。  <br>
<br>
【规则13】注意溢出问题，写安全的代码。  <br>
<br>
1.4 KeilC 编程  <br>
【规则14】深入了解你所用的工具。  <br>
仔细查看KeilC 附带的帮助文件，你能找到你期待已久的东西。KeilC 是当前最好用的单片机开发软件。要充分利用该软件的功能，就必须对它深入的进行了解。  <br>
<br>
【规则15】不要使用语言的冷僻特性，并且记住，耍小聪明会贻害无穷。最重要的是编写你理解的代码，理解你编写的代码，你就可能会做得很好。  <br>
<br>
2 推荐书目  <br>
要成为一个优秀的单片机系统产品设计工程师，兴趣、热情、责任心至关重要。  <br>
2.1 单片机技术学习  <br>
《微机原理及应用(从16 位到32 位) 》戴梅萼等著清华大学出版社。学校教材，也是当年我学习单片机的启蒙书。  <br>
2.2 C51 编程学习  <br>
《单片机高级语言C51 Windows 环境编程与应用》作者:徐爱钧彭秀华电子工业出版社。这本书几乎覆盖了C51 编程的方方面面，最新版本对当前使用最广的keilC 也有很详细的讲述。对于刚学C51 编程的同志，本书是上上之选，强力推荐。比起现今书市上的所谓什么&ldquo;C51 编程圣经&rdquo;之类的书强得多。  <br>
2.3 C 语言编程必读  <br>
《C 陷阱与缺陷》Andrew Koenig 著  <br>
《C 专家编程》Peter Van Der Linden 著  <br>
C 语言开发技术经典之作，C 程序员必读之书，数十年来经久不衰。如果你想对C语言全面的掌握，真正了解C 语言的精髓，这两本书是必读之作。由人民邮电出版社出版的中文译本也还不错。  <br>
2.4 程序设计技术方面  <br>
《数据结构》, 严蔚敏, 清华大学出版社。清华大学出版社的教材质量稳定，中规中矩，价格相对来说也便宜一点。  <br>
《程序设计实践》Brian W. Kernighan, Rob Pike 著；《代码大全》（网上有下载）。这两本是能让你看后，感觉有大突破的那种书籍，千万别吝惜银子。  <br>
<br>
3 后记  <br>
<br>
从事单片机开发工作已经有差不多三年时间了，自己感觉积累了一些经验和体会。这篇文章就算是一个总结吧。本来想写的更为详细一些，加入C51 中指针及uvision 软件仿真的一些使用体会，以及自己的一些开发实践，但一想，keil c 中的说明书已经够详细了，而我的开发产品所有权又不属于我本人，因此，并没有深入下去。由于本人水平有限，这次也是抱着与各位交流学习的目的，非常欢迎各位与我联系交流，共同探讨。  <br> <a href="http://hi.baidu.com/52elec/blog/item/40a3f14a34a7032909f7efeb.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/%B5%A5%C6%AC%BB%FA%D1%A7%CF%B0">单片机学习</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/40a3f14a34a7032909f7efeb.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-07  22:55</pubDate>
        <category><![CDATA[单片机学习]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/40a3f14a34a7032909f7efeb.html</guid>
</item>

<item>
        <title><![CDATA[向大家推荐一个我学习WINDOWS编程的网站]]></title>
        <link><![CDATA[http://hi.baidu.com/52elec/blog/item/3654136e5a2c3ed380cb4a17.html]]></link>
        <description><![CDATA[
		
		<p>&nbsp;&nbsp;&nbsp;  一直都在学习windows编程。期间在网上也找了不少资料，发现一个网站做的很不错。</p>
<p>&nbsp;&nbsp;  在CSDN上面也有那个网站老大，就是杨老师，在CSDN的学生大本营中大家可以找的到。</p>
<p>&nbsp;&nbsp;  杨老师的网站中的&ldquo;C语言也能干大事&rdquo;系列教程视频确实很不错，通过它，我终于找到了学习windows程序设计的门路。</p>
<p>&nbsp;&nbsp;&nbsp;  为了给更多迷茫的学生或者爱好windows程序设计的爱好者们更多的帮助，下面把杨老师论坛的连接贴出来。大家不妨去看一下。保证你会收获很多。</p>
<p>&nbsp;&nbsp;  在此，对杨老师推出的视频教程表示感谢。</p>
<p>下面是杨老师的网站链接。</p>
<p><a href="http://www.rupeng.com/forum/jian-616.html">http://www.rupeng.com/forum/jian-616.html</a></p>
<p> </p>
<p>为了防止大家说那是什么病毒或者木马之类的连接，我贴一个截图上来。大家可以道杨老师的网站上面的C语言也能干大事这个板块找到。</p>
<p> </p>
<div forimg="1">
<p><img class="blogimg" border="0" small="0" src="http://hiphotos.baidu.com/52elec/pic/item/2a899638c24fb50cb9998f4e.jpg"></p>
<p> </p>
<p>好了，最后祝所有爱好WINDOWS编程的同学都能够学有所成，加油吧。</p>
</div> <a href="http://hi.baidu.com/52elec/blog/item/3654136e5a2c3ed380cb4a17.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/52elec/blog/category/windows%20sdk%20%B1%E0%B3%CC">windows sdk 编程</a>&nbsp;<a href="http://hi.baidu.com/52elec/blog/item/3654136e5a2c3ed380cb4a17.html#comment">查看评论</a>]]></description>
        <pubDate>2009-07-23  11:43</pubDate>
        <category><![CDATA[windows sdk 编程]]></category>
        <author><![CDATA[就抽精品]]></author>
		<guid>http://hi.baidu.com/52elec/blog/item/3654136e5a2c3ed380cb4a17.html</guid>
</item>


</channel>
</rss>