DS18B20时序问题的详细讨论

<p>今天弄DS18B20,发现按照DataSheet写的续写函数无法正常工作,估计是对DataSheet的理解不够。找来一个例程,仔细对比发现了差异。</p>
<p>详细分析如下:</p>
<p><a href="http://www.benp366.com/attachments/month_1006/z20106321721.png"><img title="image" border="0" alt="image" width="650" height="521" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/l20106321739.png" /></a></p>
<p><a href="http://www.benp366.com/attachments/month_1006/020106321753.png"><img title="image" border="0" alt="image" width="650" height="248" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/52010632189.png" /></a></p>
<h4>一、先看写时间片。</h4>
<h5>根据上面的说明:</h5>
<p>&nbsp;&nbsp;&nbsp; 写时间片在主机把数据线从高电平拉到低电平时开始。不论是写0还是写1都必须持续至少60us,写周期之间需要有1us的恢复间隔。</p>
<p>&nbsp;&nbsp;&nbsp; DS18B20在DQ线被拉低后的15us到60us内对DQ线进行采样。如果DQ线为高,则产生了一次写1操作,如果DQ线为0则产生了一次写0操作。</p>
<p>&nbsp;&nbsp;&nbsp; 主机要发出一个写1时间片,数据线必须拉低并且接着被释放(?这里的释放应该怎样理解?),以此来允许数据线在写时间片开始后的15us内上升到高电平。</p>
<p>&nbsp;&nbsp;&nbsp; 主机要发出一个写0时间片,数据线必须被拉低并且保持低电平60us。</p>
<p>根据以上说明和时序图,我写了如下的写字节函数。</p>
<h5>程序:</h5>
<p>sbit DQ=P1^7;</p>
<p>/*—————————————————————–*/</p>
<p>void delay(unsigned int i) <br />
{ <br />
&nbsp;&nbsp;&nbsp; while ((i–)!=1); <br />
}</p>
<p>/*—————————————————————–*/ <br />
void TmWrByte(unsigned char dat)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //读写都是从最低有效位开始 <br />
{ <br />
&nbsp;&nbsp;&nbsp; unsigned char k; <br />
&nbsp;&nbsp;&nbsp; for (k=1;k&lt;=8;k++) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=dat&amp;0x01; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delay(6);&nbsp;&nbsp;&nbsp; //while( (i–)!=1 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 延时10*i个机器周期 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里必须要拉高 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dat&gt;&gt;=1; <br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; delay(5); <br />
}</p>
<h5>分析:</h5>
<p>DQ = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里必须要拉高&nbsp;&nbsp; ,我不明白为什么应该有这一条语句,但是没有这条语句就不能正常写操作。我猜想是一方面必须用拉高总线来结束写(一个位)操作,另一方面,完成一次写操作后需要释放总线。</p>
<p><span style="color: #ff0000">补充:通过查找资料,明白了这里DQ=1操作的含义。&ldquo;最后DQ又恢复为1,是总线的规范,在操作完后保证其为高电平,总线空闲时为高电平。如果不置为高电平,问题也不大,不过不操作时置高电平,是总线操作的习惯。&rdquo;</span></p>
<h3>二、再看读时序</h3>
<p><a href="http://www.benp366.com/attachments/month_1006/d20106321845.png"><img title="image" border="0" alt="image" width="650" height="221" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/e2010632199.png" /></a></p>
<h5>根据上面的说明:</h5>
<p>&nbsp;&nbsp;&nbsp; 当数据从DS18B20被读出来的时候主机开始读时间片。当主机把数据线从高拉到低时开始一个读时间片。数据线必须至少保持低电平1us;在读时间片的下降沿后的15us内DS18B20的输出数据都是有效的。同时,从读时间片开始后15us内主机必须停止驱动DQ脚为低从而来读取改线的状态。在读时间片结束时,DQ脚将会经由外部上拉电阻拉回到高电平。所有的读时间片必须持续至少60us,包含一个最短1us的读周期之间按的回复时间。</p>
<p>我写了如下程序:</p>
<p>/*—————————————————————–*/ <br />
unsigned char TmRdByte(void)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //读写都是从最低有效位开始 <br />
{ <br />
&nbsp;&nbsp;&nbsp; unsigned char k,v_byte=0; <br />
&nbsp;&nbsp;&nbsp; for(k=0;k&lt;8;k++) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v_byte=v_byte&gt;&gt;1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=1;&nbsp;&nbsp;&nbsp; //必须像把I/O作为输入口使用一样先置1,再读取 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (DQ) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v_byte|=0x80; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delay(6); <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; return(v_byte); <br />
}</p>
<h5>分析:</h5>
<p>这里在读取DQ之前(也就是if语句之前)还必须要DQ=1,我猜测,这是因为需要像把I/O作为输入口使用一样先置1,再读取。</p>
<p>关键就是这两个时序问题。</p>
<p>———————————————————————————————————-<br />
补充两个参考资料:</p>
<p>DS18B20 测温程序完全解读 <a href="http://bbs.21ic.com/viewthread.php?tid=44595&amp;highlight=DS18B20">http://bbs.21ic.com/viewthread.php?tid=44595&amp;highlight=DS18B20</a></p>
<p>&nbsp;振南的《单片机基础外设九日通》视频教程<u><font color="#0000ff"><a href="http://v.youku.com/v_playlist/f4243496o1p3.html">http://v.youku.com/v_playlist/f4243496o1p3.html</a></font></u></p>

版权申明:

本站保留所有原创文章的版权,本站地址:奔跑的博客[http://www.elecbench.com]

原创文章转载时请注明出处,并添加文章所在页面的链接:https://www.elecbench.com/117/

本站所有 2010年3月4日 以后发表、未标明为“转载”的文章均是本站原创。

发表评论


(设置自己的个性头像)

申请属于你的免费顶级域名