STC89C52单片机单线通信(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