其他分享
首页 > 其他分享> > STC89C52单片机单线通信(DS18B20温度)

STC89C52单片机单线通信(DS18B20温度)

作者:互联网

目录

DS18B20介绍

DS18B20温度传感器结构图:

 DS18B20温度传感器操作配置:

单总线介绍

单总线规范

单总线时序结构

初始化:

发送一位:(主机到从机)

接收一位:(从机到主机)

发送一个字节:

接收一个字节:

代码示例:

单线通信函数:


DS18B20介绍

DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点

测温范围:-55°C 到 +125°C

通信接口:1-Wire(单总线)

其它特征:可形成总线结构、内置温度报警功能、可寄生供电

DS18B20温度传感器结构图:

 DS18B20温度传感器操作配置:

在DS18B20温度传感器进行初始化操作的时候,由于我们这里单线通信的只有DS18B20这一个设备,所以ROM就不需要进行匹配,而且要将DS18B20温度传感器收集到的模拟信号转化为温度值

所以开始进行的是SKIP ROM(0xCC)与CONVERT T(0x44)的操作 

 这里在进行转换的时候有一定的时间限制,也就是说不是一转换就可以进行读数的,这里就一最大的750ms为标准,建议Delay(1000ms)

最后就是读取温度,利用读取温度的操作:READ SCRATCHPAD(0xBE)

在这里LS BYTE(TMSB)表示低位而MS BYTE(TLSB)表示低位,Temp=(TMSB<<8)|TLSB

这里需要将小数部分的4位向右移,得到实际温度的浮点数,左移一位x2,右移一位/2。T=Temp/16.0

单总线介绍

单总线(1-Wire BUS)是由Dallas公司开发的一种通用数据总线

一根通信线:DQ

异步、半双工

单总线只需要一根通信线即可实现数据的双向传输,当采用寄生供电时,还可以省去设备的VDD线路,此时,供电加通信只需要DQ和GND两根线

寄生供电就相当于数据线一样,就是DQ在传输数据的时候同时也用DQ来进行供电,以此节约端口

单总线规范

单总线时序结构

初始化:

主机将总线拉低至少480us,然后释放总线,等待15~60us后,存在的从机会拉低总线60~240us以响应主机,之后从机将释放总线

发送一位:(主机到从机)

主机将总线拉低60~120us,然后释放总线,表示发送0;(这里确认上限是120us是为了避免时间过长,表示成初始化)

主机将总线拉低1~15us,然后释放总线,表示发送1;

从机将在总线拉低30us后(典型值)读取电平,整个时间片应大于60us 

(在设计的时候可以在0us时刻的时候置初值0,10us时刻进行赋值,后延时50us。这样刚刚好是在最后延时50us这段时间里面读取的电平)

接收一位:(从机到主机)

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

(在设计的时候可以在0us时刻先置为0,然后在5us时刻置1,延时5us看从机是否拉低总线,然后读取的电平,最后延时50us结束),这里在第一个5us的时候将总线拉高置1,是为了让效果跟明显,图示中置的是0也是可以的

发送一个字节:

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

一般是用8次循环的“ & ”运算,依次将数据赋给DQ

接收一个字节:

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

一般是用8次循环的“ | ”运算,依次将数据读给中间变量

 代码示例:

main函数:

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"

float T;
extern unsigned char TLSB,TMSB;
void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数为默认值,而出现闪屏现象
	Delay(1000);			//等待转换完成
	LCD_Init();
	LCD_ShowString(1,1,"BIN:");
	while(1)
	{
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(2,1,'-');	//显示负号
			T=-T;			//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(2,1,'+');	//显示正号
		}
		LCD_ShowNum(2,2,T,3);		//显示温度整数部分
		LCD_ShowChar(2,5,'.');		//显示小数点
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//(T*10000)显示温度的整数与小数部分超过65536,所以定义为unsigned long
    LCD_ShowBinNum(1,5,TMSB,4);                       //%10000求的是最后4位
    LCD_ShowBinNum(1,9,TLSB,8);
	}
			
}

单线通信函数:

#include <REGX52.H>

//引脚定义
sbit OneWire_DQ=P3^7;

/**
  * @brief  单总线初始化
  * @param  无
  * @retval 从机响应位,0为响应,1为未响应
  */
unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i = 247;while (--i);//Delay 500us调用函数还需要时间us比较小,所以调用函数的话误差比较大
	OneWire_DQ=1;
	i = 32;while (--i);//Delay 70us
	AckBit=OneWire_DQ;
	i = 247;while (--i);//Delay 500us将时序走完
	return AckBit;//应答位
}

void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ=0;
	i = 4;while (--i);			//Delay 10us
	OneWire_DQ=Bit;
	i = 24;while (--i);			//Delay 50us从机在30us时读取电平
	OneWire_DQ=1;
}

unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i = 2;while (--i);			//延时5us后释放
	OneWire_DQ=1;
	i = 2;while (--i);			//Delay 5us等待总线变化
	Bit=OneWire_DQ;
	i = 24;while (--i);			//Delay 50us确保总时间>60us
	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(void)
{
	unsigned char i;
	unsigned char Byte=0x00;
	for(i=0;i<8;i++)
	{
		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
	}
	return Byte;
}

DS18B20温度传感器函数:

#include <REGX52.H>
#include "OneWire.h"

//DS18B20指令
#define DS18B20_SKIP_ROM			0xCC
#define DS18B20_CONVERT_T			0x44
#define DS18B20_READ_SCRATCHPAD 	0xBE


void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

unsigned char TLSB,TMSB;
float DS18B20_ReadT(void)
{
	//unsigned char虽然是无符号的,但是负数储存的时候是以补码的形式储存的,所以将它赋给一个有符号的数字,符号还是会显示的
	int Temp;
	float T;
	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;//将小数部分的4位向右移,得到实际温度,左移一位x2,右移一位/2
	return T;
}

LCD1602函数: 

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

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;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

Delay函数:

void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

标签:Delay,OneWire,DS18B20,STC89C52,unsigned,char,单片机,LCD
来源: https://blog.csdn.net/qq_60521516/article/details/122782914