单总线及DS18B20

目录

单总线

单总线介绍

单总线的电路规范

单总线时序结构

初始化

代码理解

发送一位

代码理解

接收一位

代码理解

发送一个字节

代码理解

接收一个字节

代码理解

DS18B20

DS18B20介绍

引脚及应用电路

内部结构

存储器结构

DS18B20操作流程

ROM指令

功能指令

DS18B20数据帧

温度变换

代码理解

温度读取

代码理解

温度的存储格式

举例

仿真案例

电路图

keil文件

单总线

单总线介绍

  • 单总线(1-wire BUS)是由Dallas公司开发的一种通用数据总线
  • 使用一根异步、半双工的通信线:DQ
  • 单总线只需要一根通信线即可实现数据的双向传输,当采用寄生供电时,可以省去设备的VDD线路,此时供电+通信只需要DQ和GND两根线

单总线的电路规范

  • 设备的DQ均要配置成开漏输出模式
  • DQ添加一个上拉电阻,阻值一般为4.7k欧左右
  • 若此总线的从机采用寄生供电,则主机还应配一个强上拉电阻

注意:第一个为电源供电电路,第二个为寄生供电电路(相对于第一个多了个强上拉)

单总线时序结构

初始化

前言:主机将总线拉低至少480us,然后释放总线,等待15——16us后,存在的从机会拉低总线60——240us以响应主机,之后从机释放总线(总过程至少960us)。

注意:上面弯的时序图部分是电阻的弱上拉作用,电阻拉的高电平是一种弱上拉,不会立即把总线拉高。

代码理解
//单总线初始化
unsigned char OneWire_Init(){
	unsigned char i=0,AckBit=0;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i=247;while(--i);	//延时500us
	OneWire_DQ=1; //释放总线
	i=32;while(--i);	//延时70us
	AckBit=OneWire_DQ; //读出IO口电平
	i=247;while(--i);	//延时500us
	return AckBit;
}

发送一位

前言:主机将总线拉低60-120us,然后释放总线,表示发送0;主机将总线拉低1-15us,然后释放总线表示发送1.从机将在总线拉低30us后(典型值)读取电平,发送的整个时间片应大于60us但不超过120us

代码理解
//单总线发送1位
void OneWire_SendBit(unsigned char Bit){
	unsigned char i=0;
	OneWire_DQ=0;
	i=4;while(--i); //延时10us
	OneWire_DQ=Bit;	//是1的话此时拉高,是0的话不拉高直接走完时序
	i=24;while(i--); //延时50us
	OneWire_DQ=1;
}

接收一位

前言:主机将总线拉低1-15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us末端)读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us。

注意:在15us内若电平变为1,则读取到的为1(主机将线拉下来后释放,释放之后总线立即弹上去说明从机发的是1),若电平依旧是0,则读取到的为0(阴影表示从机随时可能释放总线)

代码理解
//单总线接收一位
unsigned char OneWire_ReceiveBit(){
	unsigned char Bit=0,i=0;
	OneWire_DQ=0;
	i=2;while(i--);	//延时5us
	OneWire_DQ=1;
	i=2;while(i--);	//延时5us
	Bit=OneWire_DQ;
	i=24;while(i--); //延时50us
	return Bit;
}

发送一个字节

前言:连续调用8次发送1位的时序,依次发送一个字节的8位(低位在前)

代码理解
//单总线发送1字节
void OneWire_SendByte(unsigned char Byte){
	unsigned char i=0;
	for(i=0;i<8;i++){
		OneWire_SendBit(Byte&(0x01<<i)); //低位在前(任何数当作bit看不为0就为1)
	}
}

接收一个字节

前言:连续调用8次接收1位的时序,依次接收一个字节的8位(低位在前)

代码理解
//单总线接收1字节
unsigned char OneWire_ReceiveByte(){
	unsigned char i=0,Byte=0;
	for(i=0;i<8;i++){
		if(OneWire_ReceiveBit()==1){
			Byte=Byte|(0x01<<i);
		}
	}
	return Byte;
}

DS18B20

DS18B20介绍

  • DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点
  • 测温范围:-55摄氏度到+125摄氏度
  • 通信接口:1-Wire(单总线)
  • 其他特征:可形成总线结构(可以在一条通信线上挂载多个设备),内置温度报警功能、可寄生供电(电源不用接,直接接数据线和GND就可以)

理解:模拟温度传感器如热敏电阻,可以直接测温度,它输出的电压随着温度变化而变化;我们通过AD采集芯片(模拟到数字转化的芯片)将模拟的电压值转化为数字电压值,这样单片机读取后才会知道温度;由此观之模拟温度传感器比较复杂,需要外部电路和模数转换及系数配比才可得到具体温度;而数字传感器就集成了模拟温度传感器以及AD模数转换器以及微控制器,它内部读取模拟温度传感器,然后自动通过内部转化,将温度存在RAM中;因此我们只需通过引脚及单总线协议将温度转化读取出来就可以。

引脚及应用电路

内部结构

理解:

  • 最左边的电路为寄生电源电路,正常情况下电源用的是VDD进而让电流走向internal Vdd,若不用VDD,那么电流从DQ进流入internal Vdd(寄生供电使用时需要强上拉)。
  • power-supply-sense:电源供给感应模块,它可以感应我们外部VDD是否存在,若不存在(采用寄生供电)他会调节内部的结构来省电
  • 64bit ROM:一种光刻ROM,这种ROM标识着我们的ID号(每个DS18B20都有全球唯一的一个ID号)在通信时就作为器件的地址,用于总线的通信寻址;同时其也是单总线的一个接口
  • Memory control logic:64bit ROM便会进入,内存控制逻辑,其掌管着内部RAM
  • scartchpad:其是内部RAM,内部储存着温度等等一些配置参数,用于总线的数据交互(右边的连线为内部的一些设备)
  • 当我们想要通信的时候,经过64bit ROM,确定是对该设备通信,来和Memory control logic交流,若我们想读,那么他就会从scartchpad中取出数据放在总线上,若我们想写,那么他就会把我们的数据写到scartchpad里面
  • temperature sensor:内部的模拟温度传感器,其自动的将温度转换都做好了,当我们发出指令让他开始温度转换时,温度传感器就会工作,然后将他的数据放到RAM里面,我们之后通过数据交互就可以把温度值拿出来了
  • alarm high trigger:报警高触发计算器,用来存储我们的温度上限阈值,用于温度报警,其存储介质为E2PROM
  • alarm low trigger:报警低触发计算器,用来存储我们的温度下限阈值,用于温度报警,其存储介质为E2PROM
  • configuration register:配置寄存器,其用来设置我们的分辨率以及精度(出场默认最高分辨率0.0625)我们通过配置两位可以把分辨率降低,最低0.5摄氏度(降低后温度转换速度提升,该字节有8位,其中第六第七位为R0和R1位,通过配置这两位就可以配置不同分辨率)
  • 8位crcgenerator:将RAM之前的数据进行校验,得到校验码放到ROM后面(用于通信判断数据是否正确的)

存储器结构

理解:

  • 左边暂存器scartchpad总共9个字节,前两个字节共同组成了温度的数据,若上电直接读的话默认85摄氏度(80+5)
  • byte2、byte3、byte4分别对应右边的E2PROM;我们不能从外面发送一个数据存到E2PROM里面,我们只能先将数据写入暂存器,然后我们通过发送一条指令进而把暂存器中的数据复制到E2PROM中(读取就从E2PROM中将数据回调到暂存器)上电时会自动地将E2PROM的三个字节搬到暂存器中
  • byte5、byte6、byte7为保留位,都没有被使用
  • CRC校验:将前面的8个字节做一个运算,然后算出一个校验位跟在后面;我们把暂存器整个读出来后进行相同的运算,看看是不是得到对应的校验位,若是证明数据传输正确

DS18B20操作流程

  • 初始化:1.从机复位;2.从机是否响应
  • ROM操作:ROM指令,本指令需要的读写操作
  • 功能操作:功能指令,本指令需要的读写操作

ROM指令

  • 搜寻ROM:SEARCH ROM[F0h](用于确定挂载在同一总线上的DS18B20的个数和识别64位ROM地址)
  • 读取ROM:READ ROM[33h](读取DS18B20中ROM中的编码)
  • 匹配ROM:MATCH ROM[55h](发出指令后,接着发出64位ROM的编码,访问总线上与该编码相应的DS18B20)
  • 跳过ROM:SKIP ROM[CCh](忽略64位ROM地址,直接向DS18B20发送温度变换命令,适用于单片工作)
  • 报警搜索:ALARM SEARCH[ECh](执行后,只有温度超过设定值上限或下限的片子才做出响应)

功能指令

  • 温度变换:CONVERT T[44h](暂存器温度值从温度传感器中更新)
  • 写暂存器:WRITE SCRATCHPAD[4Eh](将字节数据写入到中间的RAM[byte2、3、4])
  • 读暂存器:READ SCRATCHPAD[BEh](将暂存器的值全部的读出来)
  • 复制暂存器:COPY SCRATCHPAD[48H](将RAM[byte2,3,4]字节写入到E2PROM)
  • 回调E2PROM:RECALL E2[B8h](将E2PROM的值覆盖到RAM[byte2,3,4]字节处)
  • 读取设备供电模式:READ POWER SUPPLY[B4h](读取DS18B20供电方式,寄生供电时DS1820发送0,外接电源时DS18B20发送1)

DS18B20数据帧

温度变换

前言:初始化——》跳过ROM——》开始温度变换

代码理解
//温度转换
void DS18B20_ConvertT(){
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

温度读取

前言:初始化——》跳过ROM——》读暂存器——》连续的读操作

注意:LSB和MSB共同组成具体温度.

代码理解
//读取温度
float DS18B20_READT(){
	unsigned char TLSB,TMSB;
	int Temp=0;
	float T=0;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0; //直接÷会损失精度,所以要÷浮点数
	return T;
}

温度的存储格式

注意:

  • MSB前5位均表示符号位,若温度值是负的,那么前五位全为1,若是正的,则前五位全为0.
  • LSB后四位均表示小数,bit3-0.5,bit2-0.25,bit1-0.125,bit0-0.0625(最低位变化一次整个温度值变化0.0625)

举例

注意:上面的负数采用了补码的行式。

仿真案例

需求:从传感器中读出温度数据。

电路图

keil文件

#include "reg51.h"
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
void delay(unsigned int n){
	unsigned int i=0,j=0;
	for(i=0;i<n;i++){
		for(j=0;j<120;j++);
	}
}
//写指令
void writecom(unsigned char com){
	//写指令
	RS=0;
	RW=0;
	E=0;
	P2=com;
	delay(5);
	E=1;
	E=0;
}
//写数据
void writedat(unsigned char dat){
	//写指令
	RS=1;
	RW=0;
	E=0;
	P2=dat;
	delay(5);
	E=1;
	E=0;
}
//初始化液晶屏
void initlcd(){
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}
//显示一个字符
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char){
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	writedat(Char);
}
int LCD_Pow(int X,int Y){
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++){
		Result*=X;
	}
	return Result;
}
//展示数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length){
	unsigned char i;
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	for(i=Length;i>0;i--){
		writedat('0'+Number/LCD_Pow(10,i-1)%10);
	}
}
//单总线相关
sbit OneWire_DQ=P3^3;
//单总线初始化
unsigned char OneWire_Init(){
	unsigned char i=0,AckBit=0;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i=247;while(--i);	//延时500us
	OneWire_DQ=1; //释放总线
	i=32;while(--i);	//延时70us
	AckBit=OneWire_DQ; //读出IO口电平
	i=247;while(--i);	//延时500us
	return AckBit;
}
//单总线发送1位
void OneWire_SendBit(unsigned char Bit){
	unsigned char i=0;
	OneWire_DQ=0;
	i=4;while(--i); //延时10us
	OneWire_DQ=Bit;	//是1的话此时拉高,是0的话不拉高直接走完时序
	i=24;while(i--); //延时50us
	OneWire_DQ=1;
}
//单总线接收一位
unsigned char OneWire_ReceiveBit(){
	unsigned char Bit=0,i=0;
	OneWire_DQ=0;
	i=2;while(i--);	//延时5us
	OneWire_DQ=1;
	i=2;while(i--);	//延时5us
	Bit=OneWire_DQ;
	i=24;while(i--); //延时50us
	return Bit;
}
//单总线发送1字节
void OneWire_SendByte(unsigned char Byte){
	unsigned char i=0;
	for(i=0;i<8;i++){
		OneWire_SendBit(Byte&(0x01<<i)); //低位在前(任何数当作bit看不为0就为1)
	}
}
//单总线接收1字节
unsigned char OneWire_ReceiveByte(){
	unsigned char i=0,Byte=0;
	for(i=0;i<8;i++){
		if(OneWire_ReceiveBit()==1){
			Byte=Byte|(0x01<<i);
		}
	}
	return Byte;
}
//DS18B20模块
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
//温度转换
void DS18B20_ConvertT(){
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}
//读取温度
float DS18B20_READT(){
	unsigned char TLSB,TMSB;
	int Temp=0;
	float T=0;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0; //直接÷会损失精度,所以要÷浮点数
	return T;
}
float T=0;
void main(){
	initlcd();
	while(1){
		DS18B20_ConvertT();
		T=DS18B20_READT();
		if(T<0){
			LCD_ShowChar(2,1,'-');
			T=-T;
		}else{
			LCD_ShowChar(2,1,'+');
		}
		LCD_ShowNum(2,2,T,3);
		LCD_ShowChar(2,5,'.');
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);
	}
}

  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值