学习目标:实现测温
一、DS18B20介绍
Vcc和Vdd是器件的电源端。Vcc是双极器件的正,Vdd多半是单极器件的正。
初始化:总线初始状态为高电平,当主机想开始数据传输时,主机将总线至少拉低480us,然后释放总线,等待一定时间后,存在的主机会拉低总线一定时间以响应主机,在此期间主机读取IO口电平以了解从机是否存在,最后从机释放总线。
发送一位:主机向从机发送一位数据。从机会在发送期间读取电平(即读取主机发来的数据),发送0的整个过程不能超过120us(不然会和开始信号有所冲突)
接收一位:主机接收从机传来的数据。
主机将总线拉低一定时间后释放总线并读取总线电平,如果总线电平随着主机的释放变为高电平,则说明从机没有将总线拉低,如果主机释放了总线,但总线还是维持在低电平,说明从机将总线拉低了,即可获取从机发送的数据。
skip rom(跳过):总线上只有一个从机时可跳过。(本次实验使用这个)
read/write scratchpad是主机与暂存器交换数据,copy/recall scratchpad是eeprom与暂存器交换数据,暂存器会掉电丢失,放在ROM里面就不会掉电丢失了。
发送/读取数据帧
这里主要使用skip rom,convert t,read scratchpad指令。温度由2个字节存储,在读取暂存器时要分别读取温度数据的低字节和高字节。ms byte高5位是符号位,如果温度为正,那么前5位都是0,反之则为1。ls byte 后四位存的温度数据的小数部分,前4位是整数部分。
代码部分
一、测温部分
整体思路:onewire.c包含初始化,发送接收一位、一个字节的操作,DS18B20.c功能包括温度转化,读取温度。主函数调用DS18B20实现测温。
main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "delay.h"
float T;
void main()
{
DS18B20_convertT();//上电先转换一次温度,防止第一次读取数据错误
delay(1000);//等待转换完成
LCD_Init();
LCD_ShowString(1,1,"temperature:");
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);//显示小数部分,数据类型强制转换之后取余
}
}
onewire.c
#include <REGX52.H>
sbit onewire_dq=P3^7;//重新命名引脚
unsigned char onewire_init()//初始化函数
{
unsigned char i;
unsigned char ackbit;//应答位
onewire_dq=1;//确保拉低前总线为高电平
onewire_dq=0;//拉低总线
i = 227;while (--i);//延时500us
onewire_dq=1;//主机释放
i = 29;while (--i);//延时70us
ackbit= onewire_dq;//获取总线电平
i = 227;while (--i);//延时500us
return ackbit;
}
void onewire_sendbit(unsigned char Bit)//发送一位
{
unsigned char i;
onewire_dq=0;//拉低总线
i=4;while(--i);//调用一个函数体的时间是4微妙,在这里我们没有调用函数体,直接把函数内部的内容写在这里了,所以要加上4微妙的时间
onewire_dq=Bit;//在14us时将要发送的一位赋值给总线
i = 22;while (--i);//延时50us
onewire_dq=1;//发送之后释放总线
}
unsigned char onewire_receivebit()
{
unsigned char i;
unsigned char Bit;
onewire_dq=0;//拉低总线
i=1;while(--i);//延时5us
onewire_dq=1;//释放总线
i=1;while(--i);//延时5us
Bit=onewire_dq;//获取总线电平
i=22;while(--i);//延时50us
return Bit;
}
void onewire_sendbyte(unsigned char byte)//发送一个字节
{
unsigned char i;
for(i=0;i<8;i++)
{
onewire_sendbit(byte&(0x01<<i));//取出要发送的字节的每一位
}
}
unsigned char onewire_receivebyte()
{
unsigned char i;
unsigned char byte=0x00;
for(i=0;i<8;i++)
{
if(onewire_receivebit())
{byte|=(0x01<<i);}
}
return byte;
}
DS18B20.c
#include <REGX52.H>
#include "onewire.h"
#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);//跳过rom
onewire_sendbyte(DS18B20_convert_T);//开始温度变换
}
float DS18B20_readT()//读取温度
{
unsigned char TLSB,TMSB;
int temp;
float T;//温度
onewire_init();//初始化
onewire_sendbyte(DS18B20_skip_rom);//跳过rom
onewire_sendbyte(DS18B20_read_scratchpad);//读暂存器
TLSB=onewire_receivebyte();
TMSB=onewire_receivebyte();
temp=(TMSB<<8)|TLSB;//组成完整的16位的二进制补码
T=temp/16.0;//转化为浮点数
return T;
}