ds18b20详解及程序

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最近都在学习和写单片机的程序, 今天有空又模仿DS18B20温度测量显示实验写了一个与DS18B20基于单总线通信的程序.
DS18B20 数字温度传感器(参考:智能温度传感器DS18B20的原理与应用)是DALLAS 公司生产的1-Wire,即单总线器件,具有线路简单,体积小的特点。

因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计。

DS18B20 产品的特点: (1)、只要求一个I/O 口即可实现通信。

(2)、在DS18B20 中的每个器件上都有独一无二的序列号。

(3)、实际应用中不需要外部任何元器件即可实现测温。

(4)、测量温度范围在-55 到+125℃之间; 在-10 ~ +85℃范围内误差为±5℃; (5)、数字温度计的分辨率用户可以从9 位到12 位选择。

将12位的温度值转换为数字量所需时间不超过750ms;
(6)、内部有温度上、下限告警设置。

DS18B20引脚分布图
DS18B20 详细引脚功能描述:
1、GND 地信号;
2、DQ数据输入出引脚。

开漏单总线接口引脚。

当被用在寄生电源下,此引脚可以向器件提供电源;漏极开路, 常太下高电平. 通常要求外接一个约5kΩ的上拉电阻.
3、VDD可选择的VDD 引脚。

电压范围:3~; 当工作于寄生电源时,此引脚必须接地。

DS18B20存储器结构图
暂存储器的头两个字节为测得温度信息的低位和高位字节;
第3, 4字节是TH和TL的易失性拷贝, 在每次电复位时都会被刷新;
第5字节是配置寄存器的易失性拷贝, 同样在电复位时被刷新;
第9字节是前面8个字节的CRC检验值.
配置寄存器的命令内容如下:
0 R1 R0 11111
MSB
LSB
R0和R1是温度值分辨率位, 按下表进行配置.默认出厂设置是R1R0 = 11, 即12位.
温度值分辨率配置表
R1R0分辨率最大转换时间(ms)
009bit(tconv/8)
4种分辨率对应的温度分辨率为0.5℃, 0.25℃, 0.125℃, 0.0625℃(即最低一位代表的温度值)
12位分辨率时的两个温度字节的具体格式如下:
低字节:
高字节:
其中高字节前5位都是符号位S, 若分辨率低于12位时, 相应地使最低为0, 如: 当分辨率为10位时, 低字节为:
, 高字节不变....
一些温度与转换后输出的数字参照如下:
由上表可看出, 当输出是负温度时, 使用补码表示, 方便计算机运算(若是用C语言, 直接将结果赋值给一个int变量即可).
DS18B20 的使用方法:
由于DS18B20 采用的是1-Wire 总线协议方式,即在一根数据线实现数据的双向传输,而对单片机来说,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。

由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。

DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。

该协议定义了几种信号的时序:初始化时序(dsInit()实现)、读时序(readByte())、写时序(writeByte())。

所有时序都是将主机作为主设备,单总线器件作为从设备。

而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。

数据和命令的传输都是低位在先。

DS18B20与单片机连接电路图:
利用软件模拟DS18B20的单线协议和命令:主机操作DS18B20必须遵循下面的顺序
1. 初始化
单线总线上的所有操作都是从初始化开始的. 过程如下:
1)请求: 主机通过拉低单线480us以上, 产生复位脉冲, 然后释放该线, 进入Rx接收模式. 主机释放总线时, 会产生一个上升沿脉冲.
DQ : 1 -> 0(480us+) -> 1
2)响应: DS18B20检测到该上升沿后, 延时15~60us, 通过拉低总线60~240us来产生应答脉冲.
DQ: 1(15~60us) -> 0(60~240us)
3)接收响应: 主机接收到从机的应答脉冲后, 说明有单线器件在线. 至此, 初始化完成. DQ: 0
2. ROM操作命令
当主机检测到应答脉冲, 便可发起ROM操作命令. 共有5类ROM操作命令, 如下表
3. 内存操作命令
在成功执行ROM操作命令后, 才可使用内存操作命令. 共有6种内存操作命令:
4. 数据处理
DS18B20要求有严格的时序来保证数据的完整性. 在单线DQ上, 有复位脉冲, 应答脉冲, 写0, 写1, 读0, 读1这6种信号类型. 除了应答脉冲外, 其它都由主机产生. 数据位的读和写是通过读、写时隙实现的.
1) 写时隙: 当主机将数据线从高电平拉至低电平时, 产生写时隙.所有写时隙都必须在
60us以上, 各写时隙间必须保证1us的恢复时间.
写"1" : 主机将数据线DQ先拉低, 然后释放15us后, 将数据线DQ拉高;
写"0" : 主机将DQ拉低并至少保持60us以上.
2)读时隙: 当主机将数据线DQ从高电平拉至低电平时, 产生读时隙. 所有读时隙最短必须持续60us, 各读时隙间必须保证1us的恢复时间.
读: 主机将DQ拉低至少1us,. 此时主机马上将DQ拉高, 然后就可以延时15us后, 读取DQ 即可.
源代码: (测量范围: 0 ~ 99度)
DS18B20
1#include <>
23f4f7f6f7c14void delay(unsigned char i) 15{
16unsigned char j, k;
17for(j = i; j > 0; j--)
18{
19for(k = 125; k > 0; k--);
20}
21}
22
23
18void delay(unsigned int i) 19{
20unsigned int j;
21while(i--)
22{
23for(j = 0; j < 125; j++);
24}
25}
26
27//初始化DS18B20
28//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动29void dsInit()
30{
31//对于时钟, unsigned int型的i, 作一个i++操作的时间大于为8us 32unsigned int i;
33ds = 0;
34i = 100; //拉低约800us, 符合协议要求的480us以上
35while(i>0) i--;
36ds = 1; //产生一个上升沿, 进入等待应答状态
37i = 4;
38while(i>0) i--;
39}
40
41void dsWait()
42{
43unsigned int i;
44while(ds);
45while(~ds); //检测到应答脉冲
46i = 4;
47while(i > 0) i--;
48}
49
50//向DS18B20读取一位数据
51//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
52//之后DS18B20则会输出持续一段时间的一位数据
53bit readBit()
54{
55unsigned int i;
56bit b;
57ds = 0;
58i++; //延时约8us, 符合协议要求至少保持1us
59ds = 1;
60i++; i++; //延时约16us, 符合协议要求的至少延时15us以上61 b = ds;
62i = 8;
63while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求64return b;
65}
66
67//读取一字节数据, 通过调用readBit()来实现
68unsigned char readByte()
69{
70unsigned int i;
71unsigned char j, dat;
72dat = 0;
73for(i=0; i<8; i++)
74{
75j = readBit();
76//最先读出的是最低位数据
77dat = (j << 7) | (dat >> 1);
78}
79return dat;
80}
81
82//向DS18B20写入一字节数据
83void writeByte(unsigned char dat)
84{
85unsigned int i;
86unsigned char j;
87bit b;
88for(j = 0; j < 8; j++)
89{
90 b = dat & 0x01;
91dat >>= 1;
92//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
93if(b)
94{
95ds = 0;
96i++; i++; //拉低约16us, 符号要求15~60us内97ds = 1;
98i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
99}
100else//写"0", 将DQ拉低60us~120us
101{
102ds = 0;
103i = 8; while(i>0) i--; //拉低约64us, 符号要求104ds = 1;
105i++; i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
106}
107}
108}
109
110//向DS18B20发送温度转换命令
111void sendChangeCmd()
112{
113dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化114dsWait(); //等待DS18B20应答
115delay(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
116writeByte(0xcc); //写入跳过序列号命令字Skip Rom
117writeByte(0x44); //写入温度转换命令字Convert T
118}
119
120//向DS18B20发送读取数据命令
121void sendReadCmd()
122{
123dsInit();
124dsWait();
125delay(1);
126writeByte(0xcc); //写入跳过序列号命令字Skip Rom
127writeByte(0xbe); //写入读取数据令字Read Scratchpad
128}
129
130//获取当前温度值
131int getTmpValue()
132{
133unsigned int tmpvalue;
134int value; //存放温度数值
135float t;
136unsigned char low, high;
137sendReadCmd();
138//连续读取两个字节数据
139low = readByte();
140high = readByte();
141//将高低两个字节合成一个整形变量
142//计算机中对于负数是利用补码来表示的
143//若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value 144tmpvalue = high;
145tmpvalue <<= 8;
146tmpvalue |= low;
147value = tmpvalue;
148
149//使用DS18B20的默认分辨率12位, 精确度为度, 即读回数据的最低位代表度150t = value * ;
151//将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
152//如t=, 进行计数后, 得到value = 1106, 即度
153//如t=, 进行计数后, 得到value = -1106, 即度
154value = t * 100 + (value > 0 : ; //大于0加, 小于0减155return value;
156}
157
158unsigned char const timeCount = 3; //动态扫描的时间间隔
159//显示当前温度值, 精确到小数点后一位
160//若先位选再段选, 由于IO口默认输出高电平, 所以当先位选会使数码管出现乱码161void display(int v)
162{
163unsigned char count;
164unsigned char datas[] = {0, 0, 0, 0, 0};
165unsigned int tmp = abs(v);
166datas[0] = tmp / 10000;
167datas[1] = tmp % 10000 / 1000;
168datas[2] = tmp % 1000 / 100;
169datas[3] = tmp % 100 / 10;
170datas[4] = tmp % 10;
171if(v < 0)
172{
173//关位选, 去除对上一位的影响
174P0 = 0xff;
175wela = 1; //打开锁存, 给它一个下降沿量
176wela = 0;
177//段选
178P0 = 0x40; //显示"-"号
179dula = 1; //打开锁存, 给它一个下降沿量
180dula = 0;
181
182//位选
183P0 = 0xfe;
184wela = 1; //打开锁存, 给它一个下降沿量
185wela = 0;
186delay(timeCount);
187}
188for(count = 0; count != 5; count++)
189{
190//关位选, 去除对上一位的影响
191P0 = 0xff;
192wela = 1; //打开锁存, 给它一个下降沿量
193wela = 0;
194//段选
195if(count != 2)
196{
197/* if((count == 0 && datas[count] == 0)
198|| ((count == 1 && datas[count] == 0) && (count == 0 && datas[count - 1] == 0)))
199{
200P0 = 0x00; //当最高位为0时, 不作显示201}
202else*/
203P0 = table[datas[count]]; //显示数字204}
205else
206{
207P0 = tableWidthDot[datas[count]]; //显示带小数点数字
208}
209dula = 1; //打开锁存, 给它一个下降沿量
210dula = 0;
211
212//位选
213P0 = _crol_(0xfd, count); //选择第(count + 1) 个数码管214wela = 1; //打开锁存, 给它一个下降沿量
215wela = 0;
216delay(timeCount);
217}
218}
219
220void main()
221{
222unsigned char i;
223
224while(1)
225{
226//启动温度转换
227sendChangeCmd();
228//显示5次
229for(i = 0; i < 40; i++) 230{
231display(tempValue); 232}
233tempValue = getTmpValue(); 234}
235}
改进后的效果图:
只有一位小数
两位小数, 并消除下一位对上一位的影响。

相关文档
最新文档