51单片机实验三:实现温度报警功能(基础)

139 阅读4分钟

一、实验的基本功能:

            1.实现温度报警功能系统,通过DS18B20温度传感芯片


            2.实现功能:随时监控传感周边的温度,并且设置最高温度,当达到阈值蜂鸣器报警                

二、实现大概内容如下:

            1.熟悉DS18B20芯片工作状态,如:DS18B20d的储存器
            
            2.熟悉DS18B20与单片机的单总线通信(one-wire),比如:one-wire通信时序,ROM、功能指
            
            3.熟悉蜂鸣器的工作状态
            
            4.主要过程:由DS18B20实时监控温度变换,得到的Float传给单片机,单片机通过LCD1602显示数值。
              通过单片机给DS18B20传达设置最高温度,达到阈值蜂鸣器报警

三、DS18B20芯片的知识

1.DS18B20内部结构

微信图片_20230325153832.png

  ·BIT ROM: 作为器件储存地址,用于总线通信的寻址(与暂存器对接),当有很多暂存器,就要寻址
  ·SCRATCHPD:暂存器,用于总线数据交
  ·EEPROM:用于保存温度触发阈值和配置参数

2.DS18B20储存器件

微信图片_20230325152928.jpg

  ·Byte0 ~ Byte1:读取有效值,与总线进行交流(掉电丢失)
  ·Byte2 ~ Byte3:保存温读触发的阈值和配置参数
  ·Byte4 ~ Byte7:保留位
  ·Byte8:检验位

3.DS18B20通信的时序定义

初始化信号

微信图片_20230325153606.png

 ·主机总线拉低至480us,释放总线,等待60us,从机会拉低240us以响应主机,之后从机将释放总线
 

发送信号

微信图片_20230325153612.png

 ·主机总线拉低至60u ~ 120us,释放总线,表示发送0。
 ·主机总线拉低至1u ~ 15us,释放总线,表示发送1。
 ·从机将在总线拉低30us后,读取1电平,整个时间大于60us
 ·需要注意的是:不是最后单元的低或高电平代表0/1,而是一个过程代表0/1
 

接收信号

微信图片_20230325153617.png

 ·主机总线拉低至1u ~ 15us,然后释放总线,并在拉低电平15us内读取总线电平,读取低电平就是0,高电平就是1     
 

四、OneWire通信功能实现的功能函数

unsigned char OneWire_Init(void);          //OneWire通信开始信号
void OneWire_sendBit(unsigned char Bit);   //OneWire发送一个bit的传输
unsigned char OneWire_ReceiveBit(void);    //OneWire接收一个bit的传输
void OneWire_SendByte(unsigned char Byte); //OneWire发送一个字节通信
unsigned char OneWire_ReceiveByte(void);   //OneWire接收一个字节通信
void DS18B20_Convert(void);                //改变改变温度转换命令
float DS18B20_ReadT(void);                 //读取DS18B20的温度命令

五、配置单总线通信(one-wire)的代码演示及解释

1.端口的调用和地址的重置命名

sbit OneWire_DQ = P3^7;

#define DS18B20_SKIP_ROM  				0xCC
#define DS18B20_CONVERT_T  				0x44
#define DS18B20_READ_SCRATCHPAD 	                0xBE
·命令指令: 
          DS18B20_SKIP_ROM   跳过寻址指令
          DS18B20_CONVERT_T  改变变寄存器的温度指令
          DS18B20_READ_SCRATCHPAD  读取寄存器的温度
                       

2.OneWire通信开始信号

unsigned char OneWire_Init(void)
{	
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ = 1;			//释放总线
	OneWire_DQ = 0;			//总线拉低至480us
	i = 218;while (--i);		//@11.0592    500us
	OneWire_DQ = 1;			//释放总线,等待60us,从机会拉低240us以响应主机(无需关心,是硬件拉低)
	i = 29;while (--i);		//@11.0592    70us
	AckBit = OneWire_DQ;		//获取响应的低电平
	i = 218;while (--i);		//@11.0592    500us
	
	return AckBit;
}
·整根据通信时序拉低时序即可,需要注意的是硬件会发高电平信号,进行接收

3.OneWire发送一个bit的传输

void OneWire_sendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ = 0;			//将总线拉低
	i = 3;while (--i);		//@11.0592    10us
	OneWire_DQ = Bit;		//对总线赋值0/1
	i = 22;while (--i);		//当发送0时,10+50us,才释放总线,发送为0,当发送1是,总线被拉低10us,释放总线
	OneWire_DQ = 1;			//@11.0592    50us
}
·该函数不同if语句,115s以内,060s以内,所以在10s后,将传值bit赋给OneWire。
  如果是0就是继续拉低,如果是1就是已经在15以内拉低,表示1

4.OneWire接收一个bit的传输

unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ = 0;			//拉低5us
	i = 1;while (--i);		//@11.0592    5us
	OneWire_DQ = 1;			//释放总线
	i = 1;while (--i);		//@11.0592    5us
	Bit = OneWire_DQ;		//读取总线电平,硬件怎么发送信号的无需关心
	i = 22;while (--i);		//拉低
	return Bit;
}
·主机总线拉低至1u ~ 15us,然后释放总线,并在拉低电平15us内读取总线电平。
·硬件是怎么发送电平的无需关心,只发送一位bit0/1

5.OneWire发送一个字节通信

void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		 OneWire_sendBit(Byte&(0x01<<i));
	}
}
·将Byte一位一位取出,先考虑的是先取高位还是低位
·“&”bit&11就是1,是0就是0
·取每一位<<,>>将0x01进行移位

6.OneWire接收一个字节通信

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;
}
·接收0/1组成Byte,通过if的布尔类型,0/1而进入下一步
·“|”的功能byte|=(0x01<<i),或运算,也就是说进入if就为对应位赋值1

7.改变改变温度转换命令

void DS18B20_Convert(void)
{
     OneWire_Init();	//通信初始化                              
     OneWire_SendByte(DS18B20_SKIP_ROM);//发送跳过ROM寻址指令
     OneWire_SendByte(DS18B20_CONVERT_T);//发送功能指令,改变温度转换		
}

8.读取DS18B20的温度命令

float DS18B20_ReadT(void)
{
	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;			     	 //整合温度数据
	T = Temp/16.0;								
	return T;
}

七、mian函数运行

#include "Onewire.h"
#include "LCD1602.h"
#include <REGX52.H>
#include "Delay.h"
#include "Buzzer.h"
#include "I2C.H"

float T,TShow;
char TLow,THigh;
unsigned char KeyNum;


void main()
{	
	DS18B20_Convert();
	Delay(1000);
	LCD_Init();
	THigh=AT24C02_ReadByte(0);	//读取温度阈值数据
	TLow=AT24C02_ReadByte(1);
	if(THigh>125 || TLow<-55 || THigh<=TLow)
	{
		THigh=20;			//如果阈值非法,则设为默认值
		TLow=15;
	}
	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_Convert();
		T = DS18B20_ReadT();
		//显示数据格式
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(1,3,'-');	//显示负号
			TShow=-T;		//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			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);//显示温度小数部分
		
			if(T>THigh)			//越界判断
		{
			LCD_ShowString(1,13,"OV:H");
			Buzzer_Time(100);
		}
		else if(T<TLow)
		{
			LCD_ShowString(1,13,"OV:L");
			Buzzer_Time(100);
		}
		else
		{
			LCD_ShowString(1,13,"    ");
		}
	}
}