前言
本篇文章属于STC89C52单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。
一、 DS18B20介绍
简单介绍
DS18B20内部集成了模拟温度传感器,只需读取数字信号即可。
引脚及应用电路
R1为上拉电阻
内部结构框图
存储器结构
二、单总线介绍
简单介绍
单总线电路规范
上面的电路是没有采用寄生供电的电路,下面的电路是采用了寄生供电的电路。
单总线的时序结构
从机复位+主机判断从机是否响应
发送一位
从机最终读到的就是总线当前所处的电平
接受一位
从机随时会因为自身原因把总线释放掉,所以总机要及时读取数据
发送和接受一个字节
注意:发送和接受都是低位在前,而I2C总线是高位在前
三、DS18B20操作流程
基本流程和一系列指令
DS18B20数据帧
温度存储格式
高位的前五位是符号位,全0表示正数,全1表示负数,低位的后四位是存储小数的位。
负数在计算机中是以补码的形式存储的。
四、实例一(DS18B20温度读取)
主要分为三个模块OneWire.c和DS18B20.c和main.c
OneWire.c
#include <REGX52.H>
sbit OneWire_DQ=P3^7;
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char Ackbit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 227;while (--i); //Delay 500us
OneWire_DQ=1;
i = 29;while (--i); //Delay 70us
Ackbit=OneWire_DQ;
i = 227;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 = 27;while (--i); //Delay 60us
OneWire_DQ=1;
}
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i,Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 27;while (--i); //Delay 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.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(void)
{
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}
float DS18B20_ReadT(void)
{
unsigned char TLSB,TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB=OneWire_ReceiveByte(); //温度的低8位
TMSB=OneWire_ReceiveByte(); //温度的高8位
Temp=(TMSB<<8)|TLSB; //合起来变为16位
T=Temp/16.0; //最低位的位权是2的-4次方,所以要转换一下
return T;
}
DS18B20_SKIP_ROM是ROM指令,DS18B20_CONVERT_T和DS18B20_READ_SCRATCHPAD是功能指令,两个函数分别位温度转换和温度读取
main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
float T;
void main()
{
DS18B20_ConvertT(); //上电先进行温度转换
Delay(1000); //延时1s,等待温度转换完成
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); //小数部分
}
}
注意,上电后先进行温度转换,不然刚开始显示的是初始值85摄氏度,这时温度还没有转换好
五、实例二(DS18B20温度报警器)
主要是main.c模块
#include <REGX52.H>
#include "AT24C02.h"
#include "Delay.h"
#include "Key.h"
#include "LCD1602.h"
#include "DS18B20.h"
float T,TShow;
char THigh,TLow;
unsigned char KeyNum;
void main()
{
DS18B20_ConvertT();
Delay(1000);
THigh=AT24C02_ReadByte(0);
TLow=AT24C02_ReadByte(1);
if(THigh>125 || TLow<-55 || THigh<=TLow)
{
THigh=20;
TLow=10;
}
LCD_Init();
LCD_ShowString(1,1,"T:");
LCD_ShowString(2,1,"TH:");
LCD_ShowString(2,9,"TL:");
LCD_ShowSignedNum(2,4,THigh,3);
LCD_ShowSignedNum(2,12,TLow,3);
while(1)
{
/*温度读取及显示*/
DS18B20_ConvertT();
T=DS18B20_ReadT();
if(T<0)
{
LCD_ShowChar(1,3,'-');
TShow=-T;
}
else
{
LCD_ShowChar(1,3,'+');
TShow=T;
}
LCD_ShowNum(1,4,TShow,3);
LCD_ShowChar(1,7,'.');
LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);
/*阈值判断及显示*/
KeyNum=Key();
if(KeyNum)
{
if(KeyNum==1)
{
THigh++;
if(THigh>125){THigh=125;}
}
if(KeyNum==2)
{
THigh--;
if(THigh<=TLow){THigh++;}
}
if(KeyNum==3)
{
TLow++;
if(TLow>=THigh){TLow--;}
}
if(KeyNum==4)
{
TLow--;
if(TLow<-55){TLow=-55;}
}
LCD_ShowSignedNum(2,4,THigh,3);
LCD_ShowSignedNum(2,12,TLow,3);
AT24C02_WriteByte(0,THigh);
Delay(5);
AT24C02_WriteByte(1,TLow);
Delay(5);
}
if(T>THigh)
{
LCD_ShowString(1,13,"OV:H");
}
else if(T<TLow)
{
LCD_ShowString(1,13,"OV:L");
}
else
{
LCD_ShowString(1,13," ");
}
}
}