11【模块学习】DS18B20(一):使用学习
DS18B20
- 1、单总线简介
- 2、DS18B20简介
- 2.1、时序
- 2.2、内部结构
- 2.3、指令操作
- 3、代码演示
1、单总线简介
单总线采用单根信号线传输。 这种协议由一个总线主节点、一个或多个从节点组成系统,通过根信号线进行数据的传输。每一个符合单总线协议的从机设备都有一个唯一的地址:8位的家族代码 + 48位的序列号 + 8位的CRC代码。主节点通过64位寻址对各个芯片进行双向通信
单总线结构如下图所示:
😀数据的收发都是通过一根总线进行传输,所以同一时间,只能进行数据读/数据写。由此单总线协议是异步半双工的通信协议,为了准确无误的数据传输,协议对时序的要求较严格。
😀单总线要求外接一个约为4.7k的上拉电阻,这样,当总线闲置时,其状态为高电平1。与I2C总线协议类似
2、DS18B20简介
DS18B20 需要严格的单总线协议以确保数据的完整性。协议包括集中单总线信号类型:复位脉冲、存在脉冲、写 0、写 1、读 0 和读 1。除了应答脉冲以外,都由主机发出。并且发送所有的命令和数据都是字节的低位在前。
由于单总线是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线命令序列,即初始化、ROM命令和功能命令。如果出现序列混乱,器件将不响应主机(搜索ROM命令、报警搜索命令除外)。
2.1、时序
- ①初始化(复位信号+从机应答信号)
主机将总线拉低并保持480 ~ 960us
以发送一个复位信号,然后释放总线,进入接收状态。单总线由4.7K上拉电阻拉到高电平。当DS18B20探测到 I/O 引脚上的上升沿后,等待15 ~ 60us
后,会将总线拉低持续60 ~ 240us
以产生一个应答信号。
单总线设备初始化代码如下:
sbit WireBUS = P2^4; //通信引脚:P2^4
void Delay600us() //@11.0592MHz
{unsigned char i, j;i = 2;j = 15;do{while (--j);} while (--i);
}void Delay90us() //@11.0592MHz
{unsigned char i;i = 38;while (--i);
}void Delay30us() //@11.0592MHz
{unsigned char i;i = 11;while (--i);
}/*** 单总线设备复位与应答*/
bit OneWire_Reset(void)
{bit ACK = 0;unsigned char i = 0;/* 1、复位 */WireBUS = 0; //主机将总线拉低Delay600us(); //等待600us,以产生一个复位信号WireBUS = 1; //主机将总线拉高,释放总线Delay90us(); //等待90us/* 2、获取应答 */ACK = WireBUS; //读取从机应答,若从机应答,则读取为低电平while(!WireBUS); //等待从机释放总线{i++;if(i > 150){return 1;//跳出循环}}return ACK;
}
- ②写时序
主机将总线拉低,持续1 ~ 15us
,在这段时间内向总线上写入数据(注意:不要拉低超过15us
后才写数据,一般在拉低4us
后写入数据),然后延时一段时间(30us
)等待从机读取总线上的数据。然后释放总线,准备写入下一位数据
向单总线从机设备写入数据的代码如下:
/*** 主机向从机写入一个字节的数据*/
void OneWire_Write(unsigned char Byte)
{unsigned tem = 0;unsigned char i = 0;for(i = 0; i < 8; i++){tem = 0x01 << i; //低位先行WireBUS = 0; //主机将总线拉低_nop_(); //2us_nop_(); //2usWireBUS = Byte & tem; //向总线上写入数据Delay30us(); //30us等待从机读取数据WireBUS = 1; //释放总线_nop_(); //2us_nop_(); //2us}
}
- ③读时序
主机将总线拉低大于1us
后,然后释放总线让从机向总线上写入数据,等待4us
后读取总线上的数据。然后延时60us
等待从机释放总线。【注意】最好别再15us
后读取数据,因为从机可能已经释放了总线。
向单总线从机设备读取数据的代码如下:
/*** 主机向从机读取一个字节的数据*/
unsigned char OneWire_Read(void)
{unsigned char Temp = 0x00;unsigned char i = 0;for(i = 0; i < 8; i++){WireBUS = 0; //主机将总线拉低_nop_(); //2us等待_nop_(); //2us等待WireBUS = 1; //主机释放总线_nop_(); //2us等待从机向总线上写入数据_nop_(); //2usif(WireBUS == 1) //主机读取总线上的数据{Temp |= (0x01 << i);}Delay30us(); Delay30us(); //60us等待从机释放总线}return Temp;
}
2.2、内部结构
2.3、指令操作
主机访问器件都必须严格遵循单总线命令序列,初始化–》ROM命令–》功能命令。
- ①ROM命令
ROM命令 | 功能 |
---|---|
0xf0 | 搜索ROM |
0x33 | 读取ROM(读取总线上设备的ROM码,注意:只能有一个设备才能读取) |
0x55 | 匹配ROM(总线上有多个设备,用此命令匹配设备) |
0xcc | 跳过ROM(总线上只有一个设备可用此命令) |
0xec | 搜索报警(搜索当温度超过触发值的设备) |
- ②功能命令
功能命令 | 功能 |
---|---|
0x44 | 启动温度转换 |
0x4e | 写寄存器(从暂存器的byte2开始写) |
0xbe | 读取寄存器(从暂存器的byte0开始读) |
0x48 | 复制寄存器 |
0xb8 | 粘贴到E2 |
0xb4 | 读取电源模式 |
3、代码演示
①OneWire.c文件的代码如下:
/************************************/
/* 此文件为单总线通信协议底层驱动函数 */
/* 通信引脚:P2^4 */
/************************************/
#include "OneWire.h"
#include "intrins.h"sbit WireBUS = P2^4; //通信引脚:P2^4
void Delay600us() //@11.0592MHz
{unsigned char i, j;_nop_();i = 2;j = 15;do{while (--j);} while (--i);
}void Delay90us() //@11.0592MHz
{unsigned char i;i = 25;while (--i);
}void Delay30us() //@11.0592MHz
{unsigned char i;i = 11;while (--i);
}/*** 单总线设备复位与应答*/
bit OneWire_Reset(void)
{bit ACK = 0;unsigned char i = 0;/* 1、复位 */WireBUS = 0; //主机将总线拉低Delay600us(); //等待600usWireBUS = 1; //主机将总线拉高,释放总线Delay90us(); //等待90us/* 2、获取应答 */ACK = WireBUS; //读取从机应答while(!WireBUS); //等待从机释放总线{i++;if(i > 150){return 1;//跳出循环}}return ACK;
}/*** 主机向从机写入一个字节的数据*/
void OneWire_Write(unsigned char Byte)
{unsigned tem = 0;unsigned char i = 0;for(i = 0; i < 8; i++){tem = 0x01 << i; //低位先行WireBUS = 0; //主机将总线拉低_nop_(); //2us_nop_(); //2usWireBUS = Byte & tem; //向总线上写入数据Delay30us(); //30us等待从机读取数据WireBUS = 1; //释放总线_nop_(); //2us_nop_(); //2us}
} /*** 主机向从机读取一个字节的数据*/
unsigned char OneWire_Read(void)
{unsigned char Temp = 0x00;unsigned char i = 0;for(i = 0; i < 8; i++){WireBUS = 0; //主机将总线拉低_nop_(); //2us等待_nop_(); //2us等待WireBUS = 1; //主机释放总线_nop_(); //2us等待从机向总线上写入数据_nop_(); //2usif(WireBUS == 1) //主机读取总线上的数据{Temp |= (0x01 << i);}Delay30us(); Delay30us(); //60us等待从机释放总线}return Temp;
}
②OneWire.h文件的代码如下:
#ifndef __OneWire_H
#define __OneWire_H
#include <REGX52.H> //包含51头文件,里面全是寄存器地址bit OneWire_Reset(void);
void OneWire_Write(unsigned char Byte);
unsigned char OneWire_Read(void);#endif
③DS18B20.C文件的代码如下:
#include "DS18B20.h"/*** DS18B20的初始化*/
void DS18B20_Init(void)
{bit ACK;ACK = OneWire_Reset();if(!ACK){OneWire_Write(SKIP_ROM); //发送跳过ROM指令}
}/*** 获取温度数据*/
float GET_Temp(void)
{unsigned char LSB,MSB;int tempReg; //有符号变量float T;DS18B20_Init(); //初始化(包括了ROM指令)OneWire_Write(CONVERT_T); //发送启动温度转换指令DS18B20_Init(); //初始化(包括了ROM指令)OneWire_Write(READ_REG); //发送读取寄存器指令LSB = OneWire_Read(); //读取低字节MSB = OneWire_Read(); //读取高字节tempReg = ((int)MSB << 8) | LSB;T = tempReg / 16.0;return T;
}
④DS18B20.h文件的代码如下:
#ifndef __DS18B20_H
#define __DS18B20_H
#include "OneWire.h"/* DS18B20的指令合集 */
//ROM指令
#define SEAECH_ROM 0xf0 //搜索ROM
#define RWAD_ROM 0x33 //读取ROM
#define MATH_ROM 0x55 //匹配ROM
#define SKIP_ROM 0xcc //跳过ROM
#define ALARM_SEARCH 0xec //搜索报警//寄存器指令
#define CONVERT_T 0x44 //温度转换
#define WRITET_REG 0x4e //写寄存器
#define READ_REG 0xbe //读取寄存器
#define COPY_REG 0x48 //复制寄存器
#define CALL_E2 0xb8 //粘贴到E2
#define READ_POWR 0xb4 //读取电源模式void DS18B20_Init(void);
float GET_Temp(void);#endif
⑤main.c文件的代码如下:
#include "LCD1602.h"
#include "DS18B20.h"void main(void)
{float Num = 0;LCD_Init(); while(1){Num = GET_Temp();LCD_ShowFloat(1, 1, Num, 3,3);}
}