【【51单片机的温度识别】】

51单片机的温度识别

这么热的天,再离我远一点

DS18B20温度读取
温度报警
我们这里对于单总线 也仿照I2C 总线的模样
【【51单片机的温度识别】】_第1张图片
以下是我们实现的onewire.c文件

#include 
//第一步从原理图触发先定义端口

sbit OneWire_DQ=P3^7;

//第一步初始化

unsigned char OneWire_Init(void)

    //初始化主机将总线拉低至少480us 然后释放总线
    //等待15-60us 存在的从机会拉低总线60-240us 以响应
    //之后从机释放主机
    {
        unsigned char i;
        unsigned char AckBit;
    //因为我们再执行任何状态都可以通过初始化去打断他
        //所以这里先将端口置为1
        OneWire_DQ=1;
        OneWire_DQ=0;
        //因为delay微秒很难控制
        //我们delay内部的while什么的跳转也需要时间 之前我们默认调准不需要时间
        //void Delay500us()        //@11.0592MHz
    i = 227;while (--i);
//上面这段我是用软件算出来的延迟500微妙
     OneWire_DQ=1;
        
        //接下来处理等待15-60us
        //江科大说延迟70us 行那我就按照他的逻辑延迟70
    i = 29;while (--i);
    //因为我们已经放手了,接下来直接读出状态就可以了
    AckBit=OneWire_DQ;
        i = 227;while (--i);
        //再delay 500us这个程序正好走完了
        return AckBit;
}
    

//第二步写发送模块

void OneWire_SendBit(unsigned char Bit)
    //发送一位 主机将总线拉低60-120us,然后释放总线 表示发送0
//主机将总线拉低1-15us,然后释放总线,表示发送1 
//从机将在总线拉低30us后 (这个30是典型值) 读取电平 整个时间片应大于60us
{
    unsigned char i;
    OneWire_DQ=0;
    i = 3;while (--i);  //Delay10us 
    OneWire_DQ=Bit;
    i = 22;while (--i); // delay50us
    OneWire_DQ=1;
    //释放掉就是置1 的意思
}
    



//第三步 接收模块
unsigned char OneWire_ReceiveBit(void)
    //主机将总线拉低1-15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us的末尾)
//读取为低电平则为接收0 ,读取为高电平则为接收1 ,整个时间片应大于60us
{
    unsigned char Bit;
    unsigned char i;
    OneWire_DQ=0;
    i = 1;while (--i);  //delay 5us
    OneWire_DQ=1;    //释放掉总线
    i = 1;while (--i);  //delay 5us
    Bit=OneWire_DQ;
    i = 22;while (--i); // delay50us
    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;
    for(i=0;i<8;i++)
    {
        if(OneWire_ReceiveBit())
        {
            Byte|=(0x01<<i) ;
        }
    }
    return Byte;
}

下面是实现的DS18B20.c

#include 
#include"OneWire.h"

#define DS18B20_SKIP_ROM      0xCC
#define DS18B20_CONVERT_T      0x44
#define DS18B20_READ_SCRATCHPAD 0xBE






//DS18B20 的基本操作流程
//初始化 : 从机复位,主机判断从机是否响应
//ROM操作 : ROM指令+本指令需要的读写操作
//功能操作 : 功能指令+本指令需要的读写操作

//本次想要实现的功能有
//温度变换 : 初始化->跳过ROM->开始温度变换

//温度读取: 初始化->跳过ROM->读暂存器-> 连续的读操作



//这上面都是一些指令
//温度变换的过程是这样的 初始化  跳过ROM 开始温度变化
void DS18B20_ConvertT(void)
{
    OneWire_Init();
    OneWire_SendByte(DS18B20_SKIP_ROM);
    OneWire_SendByte(DS18B20_CONVERT_T);
}




//温度读取: 初始化->跳过ROM->读暂存器-> 连续的读操作
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();
    TMSB=OneWire_ReceiveByte();
    Temp=(TMSB<<8)|TLSB;
    T=Temp/4.0;
    return T;
}

下面是完整的全部代码

main.c

#include 
#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)				//如果温度小于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);//显示温度小数部分
	}
}

Delay.c

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

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

DS18B20.c

#include 
#include "OneWire.h"

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

/**
  * @brief  DS18B20开始温度变换
  * @param  无
  * @retval 无
  */
void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

/**
  * @brief  DS18B20读取温度
  * @param  无
  * @retval 温度数值
  */
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();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0;
	return T;
}

DS18B20.h

#ifndef __DS18B20_H__
#define __DS18B20_H__

void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);

#endif

LCD1602.c

#include 

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

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

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

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
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();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
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();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
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));
	}
}

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

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
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]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
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');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(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(2,i-1)%2+'0');
	}
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

你可能感兴趣的:(51单片机微型设计,51单片机,嵌入式硬件,单片机)