温度范围:-55℃到125℃ 默认12位精度,0.0625℃一格
因为网上有很多ds18b20中文资料,我只说几个最不容易理解的点。
单总线通信。数据在一条线上传输。 为什么读写时序一样?因为在阅读和写作之前必须先发出命令。比如先发一个0x44是启动温度转换,然后发送0xbe,再读数据。温度转换后,温度数据被放置在温度转换后ram中的第1.2字节,断电丢失,芯片复位不丢失。因此,执行温度转换可以读几次。但请记住,复位函数应在每次发送命令之前执行,然后发送命令。可以放置温度的2字节和配置eeprom但是目前没用。 默认精度为12位,11位数据为1位符号。其余4位随符号位变化。
在执行完ROM操作命令后,我们需要执行RAM让我们先了解一下高速暂存的操作命令RAM。由9个字节组成的暂存器。
第一个和第二个字节包含温度信息,温度传感器(温度敏感元件)测得的温度值存储在高速临时存储器中。 以12位精度存储温度,最高位为符号位,负温度S=1,正温度S=0.将存储器中的二进制数求补转换为十进制数乘以精度(0.5、0.25、0.0625)获得被测温度值。如0550H为 85℃,0191H为 25.0625℃,FC90H为-55℃,上电初始为 85℃。第三和第四个字节是 TH 和 TL 易失性副本(从EEPROM复制到高速暂存器这两个字节),每次上电复位时刷新;
第五个字节是配置寄存器,如图所示,用户可以根据温度计精度配置表进行修改R1R设置2的值DS18B20精度,默认设置上电R1R0=11(12位精度),其他配置寄存器均保留,禁止写入; 六、七、八字节保留,禁止写入; 第九个字节只读,包括上述八个字节CRC码;
再看一下RAM操作指令(功能指令) 在发送ROM操作指令后,下一步需要执行RAM操作指令。这些指令允许总线控制器读写DS18B20暂存器启动温度转换和识别电源模式。DS18B详见下文。 CONVERTT [44h] (温度转换指令) 该命令用于启动温度转换。执行温度转换指令,产生的温度转换结果数据以两个字节的形式存储在高速临时存储器中,然后DS18B保持等待状态。寄生电源模式下达命令后,在温度转换期间(tconv),必须在10us(最多)给单总线一个强上拉。如果DS18B20外部电源供电,总线控制器发出此命令后跟随读时序,DS18B20如果在转换中,将返回总线 0.如果温度转换完成,则返回 1。在寄生电源模式下,这种通信技术不会在总线被强上拉高之前使用。 WRITESCRATCHPAD [4Eh] (写临时存器指令) 这条命令向 DS18B20 将数据写入临时存储器,开始位置 TH 寄存器(暂存器第一 两个字节),然后写入 TL 寄存器(暂存器第一 3 个字节),最后写入配置寄存器(暂存器第一 4 字节)。数据以最低有效率传输。在总线控制器发出复位命令之前,必须发生上述三个字节的写入,否则将停止写入。 写是往2.3.四个字节依次写数据。
只有两个配置寄存器可以改变,R1R0;
所以这样写就行了。先给他加前两个,然后写命令,然后写在配置寄存器里。
DS18B20Write(0x4e); //写暂存器指令4E DS18B20Write(0x4b); //写高速缓存器TH高温限值75度 DS18B20Write(0x00); //写高速缓存器TL低温限值0度 DS18B20Write(0x1f); //0x1f : 0.5000°C 转换时间93.75ms //0x3f : 0.2000°C 转换时间187.5ms //0x5f : 0.1250°C 转换时间375ms //0x7f : 0.0625°C 转换时间750ms
接下来是一些命令,有些前带0是错的,不需要看第一个0
每次读写前都要对 DS18B20 复位成功后发送一个 ROM 最后发送指令 RAM 指令,这样才能正确 DS18B20 进行预定操作。
虽然不能使用温度报警,但我们还是写下来,因为我们通常控制外部,判断温度是否超标
以下是一些细节。如果你知道,你可以不看
推挽电路和漏极开路的帖子: https://www.zhihu.com/question/28512432 https://blog.csdn.net/u012604283/article/details/84647237
代码开始
#include "ds18b20.h"
#include "public.h"
uchar ds18b20Init(void)
{
uchar i=0;
DATA=0;
delay700us();
DATA=1;
delay100us();
while(DATA)
{
if(i>=5)
{
return 0;
}
i++;
}
return 1;
}
void writeByte(uchar dat)
{
uchar i;
DATA=0;
delay4us();
for(i=0;i<8;i++)
{
DATA=0;
delay4us();
DATA=dat&0x01;
delay60us();
DATA=1;
dat>>=1;
}
}
uchar readByte()
{
uchar i,dat=0;
uchar da=0;
for(i=0;i<8;i++)
{
DATA=0;
_nop_();
DATA=1;
delay4us();
da=DATA;
da<<=7;
dat=(dat>>1)|da;
delay60us();
}
return dat;
}
void changeTemp()
{
ds18b20Init();
delay700us();
writeByte(0xcc);
writeByte(0x44);
delay1s();
}
void readTempCommand()
{
ds18b20Init();
delay700us();
writeByte(0xcc);
writeByte(0xbe);
}
int readTemp()
{
int dat=0;
uchar tmh, tml;
changeTemp();
readTempCommand();
tml = readByte(); //读取温度值共16位,先读低字节
tmh = readByte();
dat=tmh;
dat<<=8;
dat|=tml;
return dat;
}
ds18b20.h
#ifndef __DS18B20_H_
#define __DS18B20_H_
#include "public.h"
sbit DATA=P3^7;
uchar ds18b20Init(void);
void writeByte(uchar dat);
uchar readByte();
void changeTemp();
void readTempCommand();
int readTemp();
#endif
main.c
#include "uart.h"
#include "public.h"
#include "ds18b20.h"
void main()
{
int dat;
int DAT;
uchar ge,shi,bai,qian;
uart_init();
while(1)
{
dat=readTemp();
if(dat>0)
{
DAT=dat*6.25+0.5;
qian=(uchar)(DAT/1000);
bai=(uchar)(DAT/100%10);
shi=(uchar)(DAT/10%10);
ge=(uchar)(DAT%10);
uart_send_sentence("now, the temperature is :");
uart_send_byte('0'+qian);
uart_send_byte('0'+bai);
uart_send_byte('.');
uart_send_byte('0'+shi);
uart_send_byte('0'+ge);
uart_send_byte('\r');
uart_send_byte('\n');
}
else
{
dat=dat-1;
dat=~dat;
DAT=dat*0.0625*100+0.5;
qian=(uchar)(DAT/1000);
bai=(uchar)(DAT/100%10);
shi=(uchar)(DAT/10%10);
ge=(uchar)(DAT%10);
uart_send_byte('-');
uart_send_byte('0'+qian);
uart_send_byte('0'+bai);
uart_send_byte('0'+shi);
uart_send_byte('0'+ge);
}
delay1s() ; //误差 0us
}
}
/* uchar i; i=ds18b20Init(); while(1) { if(i==1) uart_send_byte('y'); else uart_send_byte('n'); delay(); } */
uart.c
#include "uart.h" #include "public.h" // 串口设置为: 波特率9600、数据位8、停止位1、奇偶校验无 // 使用的
晶振是11.0592MHz的,注意12MHz和24MHz的不行 void uart_init(void) { // 波特率9600 SCON=0X50; //设置为工作方式1 TMOD=0X20; //设置计数器工作方式2 PCON=0X80; //波特率加倍 TH1=0XF3; //计数器初始值设置,注意波特率是4800的 TL1=0XF3; //ES=1; //打开接收中断 //EA=1; //打开总中断 TR1=1; } // 通过串口发送1个字节出去 void uart_send_byte(unsigned char c) { // 第1步,发送一个字节 SBUF = c; // 第2步,先确认串口发送部分没有在忙 while (!TI); // 第3步,软件复位TI标志位 TI = 0; } void uart_send_sentence(unsigned char *sen) { while(*sen!='\0') { uart_send_byte(*sen); sen++; } }
uart.h
#ifndef __UART_H__
#define __UART_H__
void uart_init(void);
void uart_send_byte(unsigned char c);
void uart_send_sentence(unsigned char *sen);
#endif
public.c
#ifndef __PUBLIC_H__
#define __PUBLIC_H__
#include <reg51.h>
#include <intrins.h>
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
void delay700us(void) ; //误差 0us
void delay100us(void) ; //误差 0us
void delay4us(void); //误差 0us
void delay60us(void) ; //误差 0us
void delay1s(void) ; //误差 0us
#endif
public.h
#include "public.h"
void delay700us(void) //误差 0us
{
unsigned char a,b;
for(b=41;b>0;b--)
for(a=7;a>0;a--);
}
void delay100us(void) //误差 0us
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=47;a>0;a--);
}
void delay4us(void) //误差 0us
{
_nop_(); //if Keil,require use intrins.h
_nop_(); //if Keil,require use intrins.h
}
void delay60us(void) //误差 0us
{
unsigned char a,b;
for(b=3;b>0;b--)
for(a=8;a>0;a--);
}
void delay1s(void) //误差 0us
{
unsigned char a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_(); //if Keil,require use intrins.h
}