一.概述
采用单根信号线,既传递时钟又传输数据,而且数据传输是双向的。
1-Wire适用于单个主机,能够控制一个或多个从机设备。
1.单总线的ROM码
每个单总线的ROM 中的 64 位序列号是出厂前被光刻好的,以表示其ID号。
地址序列号。64 位光刻 ROM 的排列是:开始 8 位(28H)是产品类型标号,接着的 48 位是唯一的序列号,最后 8 位是前面 56 位的循环冗余校
验码(CRC)。
2.传输速率
通常为16.3kb/s
超速时142kb/s
速度要求不高的场合
3.以DS18B20为例
二.单总线基本操作
(1)初始化时序图
总线控制器低电平:主机发出
DS1820:从机发出l
单总线上的所有通信都是以初始化序列开始。(由于上拉电阻,总线上为高电平)
主机输出低电平,保持低电平时间至少 480us(该时间的时间范围可以从 480 到 960us),以产生复位脉冲。
接着主机释放总线,外部的上拉电阻将单总线拉高,延时 15~60 us,并进入接收模式。
接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,
若为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要 480us。
/*******************************************************************************
Function: Driver_1WireRst
Description: DS18B20 初始化时序
Input: 无
Output: 无
Return: 无
*******************************************************************************/
bit Driver_1WireRst()
{
bit ack;
DS18B20 = 0; //拉低总线,总机发送复位脉冲。480us - 960us,这里取600us
Delay600us();
DS18B20 = 1; //主机释放总线,外部的上拉电阻将单总线拉高,15 -60 us
Delay60us();
ack = DS18B20; //读取DS18B20的ack
while(!DS18B20); //等待脉冲结束,DS18B20释放的是低电平。
return ack;
}
(3)写时序
写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2 次独立的写时序之间至少需要 1us 的恢复时间, 最长没限制。
写 0时序:主机拉低总线(单片机将引脚拉低),持续时间60us-120us。单片机拉低15us后,DS18B20会从15us-60us之间读取这一位数据。(最早在15us读取,典型值在30us读取,最多60us),这里延时超过60us即可。
写 1 时序:主机输出低电平,拉低时间至少1us,马上释放总线(即拉高引脚),延时 60us,然后释放总线,DS18B20会从15us-60us之间读取这个1。
nop(); //库函数_NOP_指令,一个机器周期就是一个us
/*******************************************************************************
Function: Driver_1Wire_Write
Description: DS18B20 写操作
Output: unsigned char date:写一字节
Return: 无
*******************************************************************************/
void Driver_1Wire_Write(unsigned char date)
{
EA = 0;
unsigned char tmp;
for (temp = 0x01; temp != 0;temp <<= 1) //第一位与第一位与操作,循环第二位与第二位与操作。
{
DS18B20 = 0; //首先拉低到低电平
_nop_(); //库函数_NOP_指令,一个机器周期就是一个us
_nop_(); //先拉低两个us,当作写1操作。
if((date & temp) == 0) // 0x01和date 与操作(全1为1),如果还为0,说明输入的这一位是0
{
DS18B20 = 0; //拉低到低电平,说明是写0的时序
}
else
{
DS18B20 = 1; //置位高电平,说明是写1的时序
}
Delay60us();
DS18B20 = 1;
EA =1;
}
if((date & temp) == 0) ,temp:0x01(0000 0001)&date(0000 0000) ==0000 0000
temp:0x01(0000 0001)&date(0000 0001) ==0000 0001
(3)读时序
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。
所有读时序至少需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。
每个读时序都由单片机发起,单片机首先拉低这个引脚(至少拉低总线 )1us。主机在读时序期间必须释放总线,并从拉低引脚到读取引脚状态,不能超过15us。
总的读时序时间应该在60us。
>读数据时,一定把中断关闭。单总线程序一定防止中断破坏时序,导致读出的数字不正确。
/*******************************************************************************
Function: Driver_1Wire_Read
Description: DS18B20 读操作
Output: unsigned char date:读一字节
Return: 无
*******************************************************************************/
unsigned char Driver_1Wire_Read()
{
EA = 0;
unsigned char date;
unsigned char tmp;
for (temp = 0x01; temp != 0;temp <<= 1)
{
DS18B20 = 0;
_nop_();
_nop_();
DS18B20 = 1;
_nop_();
_nop_();
if(!DS18B20) //如果返回是0;取反为1。
{
date &= ~temp // temp =0x00.取反为0xfe(1111 1111)。与返回的date 0(0000 0000)与操作,为0000 0000
}
else
{
date |= temp // temp =0x01(0000 0001)。与返回的date 0(0000 0000)或操作,为0000 0001
}
elay60us();
}
EA = 1;
return date
}
三.DS18B20的主要性能
1.上电默认12位的分辨率,转换为750ms。
2.DS18B20典型电路连接
2.DS18B20内部结构
byte 1 byte 2 是为了在多机模式,响应报警搜索指令。是否达到某个DS18B20的高低温触发值
使用拷贝指令将RAM的命令拷贝到EEPROM中,防止掉电不丢失。
当温度为正时,符号位为0,把温度寄存器中的数据乘以0.0625即可得到温度值。
当温度为负时,符号位为1,把温度寄存器中的数据取反加1,乘以0.0625即可得到温度值,最后再加上个负号。
三.DS18B20指令
1.ROM指令
命令均为8位,用来搜索,甄别从器件
1.器件操作的功能指令
存储器操作,转换启动
3.单总线的操作流程
(1)初始化
(2)ROM指令
(3)功能指令
/*******************************************************************************
Function: BSP_DS18B20_Start()
Description:启动DS18B20
Input: 无
Output: 无
Return: 无
*******************************************************************************/
bit BSP_DS18B20_Start()
{
bit ack;
ack = Driver_1WireRst(); //初始化
if(ack == 0)
{
Driver_1Wire_Write(BSP_SKIP_ROM); //ROM指令的
Driver_1Wire_Write(Convert); //功能指令,启动温度转换
}
return ~ack;
}
/*******************************************************************************
Function: BSP_DS18B20_Start()
Description:启动DS18B20
Input: 无
Output: 无
Return: 无
*******************************************************************************/
bit BSP_DS18B20_Read(int *temp) //这里以指针地址方式传递,如果想获取数据则使用&取地址符
{
bit ack;
unsigned char MSB,LSB;
ack = Driver_1WireRst(); //初始化
if(ack == 0)
{
Driver_1Wire_Write (Read_Register);
LSB = Driver_1Wire_Read() //低位字节保存LSB
MSB = Driver_1Wire_Read() //高位字节保存MSB
*temp =((int)MSB<<8)+LSB; //8位的MSB强制转为16位
}
return ~ack;
}
main.c
oid Timer0Init(void); //10微秒@12.000MHz
unsigned char flag; //定义一个标志
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
unsigned char ack;
int temp; //保存温度数据
int itemp; //分离温度数据整数
int dtemp; //分离温度数据小数
unsigned char str[12]; //使用1602显示,定义一个数组,保存数据转换成的字符串
unsigned char len;
BSP_DS18B20_Start();
LCD_Init();
Timer0Init;
while(1)
{
}
}
void Timer0Init(void) //10微秒@12.000MHz
{
//AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xF6; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
ET0 = 1;
EA = 1;
TR0 = 1; //定时器0开始计时
}
dtemp =(dtemp * 100) *0.0625;
str[len++] = dtemp / 10 + ' 0';15/10=1
str[len++] = dtemp % 10 + ' 0';15%10=5
str[len] = '\0';