DS18B20介绍
DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线)”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器。
DS18B20 温度传感器具有如下特点:
- 适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电。
- 独特的单线接口方式,DS18B20 在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯
- DS18B20 支持多点组网功能,多个 DS18B20 可以并联在唯一的三线上,实现组网多点测温。
- DS18B20 在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内。
- 温范围-55℃ —— +125℃,在-10 —— +85℃时精度为±0.5℃
- 可编程的分辨率为 9~12 位,对应的可分辨温度分别为 0.5℃、0.25℃、0.125℃ 和 0.0625℃,可实现高精度测温。
- 在 9 位分辨率时最多在 93.75ms 内把温度转换为数字,12 位分辨率时最多在 750ms 内把温度值转换为数字,速度更快。
- 测量结果直接输出数字温度信号,以"一根总线"串行传送给 CPU,同时可传送 CRC 校验码,具有极强的抗干扰纠错能力。
- 负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。
DS18B20外观实物
从 DS18B20 外观图可以看到,当我们正对传感器切面(传感器型号字符那一面)时,传感器的管脚顺序是从左到右排列。管脚 1 为 GND,管脚 2 为数据DQ,管脚 3 为 VDD。如果把传感器插反,那么电源将短路,传感器就会发烫,很容易损坏,所以一定要注意传感器方向,通常我们在开发板上都会标出传感器的凸起出,所以只需要把传感器凸起的方向对着开发板凸起方向插入即可。
DS18B20内部结构
ROM 中的 64 位序列号是出厂前被光刻好的,它可以看作是该 DS18B20 的地址序列号。64 位光刻 ROM 的排列是:开始 8 位(28H)是产品类型标号,接着的48 位是该 DS18B20 自身的序列号,最后 8 位是前面 56 位的循环冗余校验码。光刻 ROM 的作用是使每一个 DS18B20 都各不相同,这样就可以实现一根总线上挂接多个DS18B20 的目的。
DS18B20 温度传感器的内部存储器包括一个高速的暂存器 RAM 和一个非易失性的可电擦除的 EEPROM,后者存放高温度和低温度触发器TH、TL和配置寄存器。
配置寄存器是配置不同的位数来确定温度和数字的转化,配置寄存器结构如下:
低五位一直都是"1",TM 是测试模式位,用于设置 DS18B20 在工作模式还是在测试模式。在 DS18B20 出厂时该位被设置为 0,用户不需要去改动。R1 和R0 用来设置 DS18B20 的精度(分辨率),可设置为 9,10,11 或 12 位,对应的分辨率温度是 0.5℃,0.25℃,0.125℃和 0.0625℃。R0 和 R1 配置如下图:
在初始状态下默认的精度是 12 位,即 R0=1、R1=1。高速暂存存储器由 9 个字节组成,其分配如下:
| 寄存器内容 |
字节地址 |
| 温湿度低位(LS Byte) |
0 |
| 温湿度高位(MS Byte) |
1 |
| 高温限值(TH) |
2 |
| 低温限值(TL) |
3 |
| 配置寄存器 |
4 |
| 保留 |
5 |
| 保留 |
6 |
| 保留 |
7 |
| CRC校验值 |
8 |
当温度转换命令(44H)发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第 0 和第 1 个字节。存储的两个字节,高字节的前 5 位是符号位S,单片机可通过单线接口读到该数据,读取时低位在前,高位在后,
温度寄存器格式
如果测得的温度大于 0,这 5 位为‘0’,只要将测到的数值乘以 0.0625(默认精度是 12 位)即可得到实际温度;如果温度小于 0,这 5 位为‘1’,测到的数值需要取反加 1 再乘以 0.0625 即可得到实际温度。 温度与数据对应关系如下:
| 温度℃ |
数据输出(二进制) |
数据输出(十六进制) |
| +125 |
0000 0111 1101 0000 |
07D0h |
| +85 |
0000 0101 0101 0000 |
0550h |
| +25.0625 |
0000 0001 1001 0001 |
0191h |
| +10.125 |
0000 0000 1010 0010 |
00A2h |
| +0.5 |
0000 0000 0000 1000 |
0008h |
| 0 |
0000 0000 0000 0000 |
0000h |
| -0.5 |
1111 1111 1111 1000 |
FFF8h |
| -10.125 |
1111 1111 0101 1110 |
FF5Eh |
| -25.0625 |
1111 1110 0110 1111 |
FE6Eh |
| -55 |
1111 1100 1001 0000 |
FC90h |
*上电复位时温度寄存器默认值为+85℃
比如我们要计算+85 度,数据输出十六进制是 0X0550,因为高字节的高 5位为 0,表明检测的温度是正温度,0X0550 对应的十进制为 1360,将这个值乘以 12 位精度 0.0625,所以可以得到+85 度。
由于DS18B20是单总线器件,所有的单总线器件都要求采用严格的信号时序,以保证 数据的完整性。DS18B20 时序包括如下几种:初始化时序、写(0 和 1)时序、 读(0和 1)时序。 DS18B20 发送所有的命令和数据都是字节的低位在前。这里我们简单介绍这几个信号的时序:
初始化时序
单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少 480us(该时间的时间范围可以从 480 到 960 微妙),以产生复位脉冲。接着主机释放总线,外部的上拉电阻将单总线拉高,延时 15~60us,并进入接收模式。接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,若为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要480 微妙。初始化时序图如下:
初始化时序
写时序
写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2 次独立的写时序之间至少需要 1us 的恢复时间,两种写时序均起始于主机拉低总线。写 1 时序:主机输出低电平,延时 2us,然后释放总线,延时 60us。写 0时序:主机输出低电平,延时 60us,然后释放总线,延时 2us。写时序图如下:
读时序
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。每个读时序都由主机发起,至少拉低总线 1us。主机在读时序期间必须释放总线,并且在时序起始后的 15us 之内采样总线状态。读时序图如下:
典型的读时序过程为:主机输出低电平延时 2us,然后主机转入输入模式延时 12us,然后读取单总线当前的电平,然后延时 50us。
在了解了单总线时序之后,我们来看看 DS18B20 的典型温度读取过程,DS18B20 的典型温度读取过程为:复位→发 SKIPROM 命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送 SKIPROM 命令(0XCC)→发读存储器命令(0XBE)→连续读出两个字节数据(即温度)→结束。
硬件设计
本实验使用到硬件资源如下:
- 动态数码管
- DS18B20
DS18B20模块电路
从上图中可以看出,该电路是独立的,并且该接口可以支持DS18B20温度传感器和DHT11温湿度传感器。
软件设计
本实验要实现的功能时:插上DS18B20温度传感器,数码管显示检测的温度值。
程序框架如下:
- 编写数码管显示功能
- 编写DS18B20读取温度功能
- 编写主函数
实物接线图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include "public.h" #include "smg.h" #include "ds18b20.h"
void main() { u8 i = 0; int temp_value; u8 temp_buf[5]; ds18b20_init(); while(1) { i++; if(i % 50 == 0) temp_value = ds18b20_read_temperture() * 10; if(temp_value < 0) { temp_value = -temp_value; temp_buf[0] = 0x40; } else temp_buf[0] = 0x00; temp_buf[1] = gsmg_code[temp_value / 1000]; temp_buf[2] = gsmg_code[temp_value % 1000 / 100]; temp_buf[3] = gsmg_code[temp_value % 1000 % 100 / 10] | 0x80; temp_buf[4] = gsmg_code[temp_value % 1000 % 100 % 10]; smg_display(temp_buf,4); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include "smg.h"
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void smg_display(u8 dat[],u8 pos) { u8 i=0; u8 pos_temp=pos-1;
for(i=pos_temp;i<8;i++) { switch(7-i) { case 0: LSC=1;LSB=1;LSA=1;break; case 1: LSC=1;LSB=1;LSA=0;break; case 2: LSC=1;LSB=0;LSA=1;break; case 3: LSC=1;LSB=0;LSA=0;break; case 4: LSC=0;LSB=1;LSA=1;break; case 5: LSC=0;LSB=1;LSA=0;break; case 6: LSC=0;LSB=0;LSA=1;break; case 7: LSC=0;LSB=0;LSA=0;break; } SMG_A_DP_PORT=dat[i-pos_temp]; delay_10us(100); SMG_A_DP_PORT=0x00; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
| #include "ds18b20.h" #include "intrins.h"
void ds18b20_reset(void) { DS18B20_PORT=0; delay_10us(75); DS18B20_PORT=1; delay_10us(2); }
u8 ds18b20_check(void) { u8 time_temp=0;
while(DS18B20_PORT&&time_temp<20) { time_temp++; delay_10us(1); } if(time_temp>=20)return 1; else time_temp=0; while((!DS18B20_PORT)&&time_temp<20) { time_temp++; delay_10us(1); } if(time_temp>=20)return 1; return 0; }
u8 ds18b20_read_bit(void) { u8 dat=0; DS18B20_PORT=0; _nop_();_nop_(); DS18B20_PORT=1; _nop_();_nop_(); if(DS18B20_PORT)dat=1; else dat=0; delay_10us(5); return dat; }
u8 ds18b20_read_byte(void) { u8 i=0; u8 dat=0; u8 temp=0;
for(i=0;i<8;i++) { temp=ds18b20_read_bit(); dat=(temp<<7)|(dat>>1); } return dat; }
void ds18b20_write_byte(u8 dat) { u8 i=0; u8 temp=0;
for(i=0;i<8;i++) { temp=dat&0x01; dat>>=1; if(temp) { DS18B20_PORT=0; _nop_();_nop_(); DS18B20_PORT=1; delay_10us(6); } else { DS18B20_PORT=0; delay_10us(6); DS18B20_PORT=1; _nop_();_nop_(); } } }
void ds18b20_start(void) { ds18b20_reset(); ds18b20_check(); ds18b20_write_byte(0xcc); ds18b20_write_byte(0x44); }
u8 ds18b20_init(void) { ds18b20_reset(); return ds18b20_check(); }
float ds18b20_read_temperture(void) { float temp; u8 dath=0; u8 datl=0; u16 value=0;
ds18b20_start(); ds18b20_reset(); ds18b20_check(); ds18b20_write_byte(0xcc); ds18b20_write_byte(0xbe);
datl=ds18b20_read_byte(); dath=ds18b20_read_byte(); value=(dath<<8)+datl;
if((value&0xf800)==0xf800) { value=(~value)+1; temp=value*(-0.0625); } else { temp=value*0.0625; } return temp; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include "public.h"
void delay_10us(u16 ten_us) { while(ten_us--); }
void delay_ms(u16 ms) { u16 i,j; for(i=ms;i>0;i--) for(j=110;j>0;j--); }
|
相关头文件