基于51单片机的温控风扇

1、代码如下main.c:

#include<reg52.h>
#include<intrins.h>
#include<stdio.h>
#include "ds18b20.h" 
#define uint  unsigned int 
#define uchar unsigned char 
sbit  fan_A=P1^1;
sbit fan_B=P1^0;
	char jd;
char vo;
void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Time0Init()  //0.5ms
{
	  TMOD&=0XF0; //置位
	  TMOD|=0X01;	//清零  配置寄存器模式:定时器T0,工作方式一
    TH0=0xFE;   //配置高八位
	  TL0=0X33;   //配置低八位
  	TF0=0;     //当爆表的时候,硬件会修改bit5(TF0)位上面的数据
	  TR0=1;    //定时器T0开启标志
	
	  ET0=1; //开启定时器T0中断允许
	   EA=1;//开启总中断

}

void Time0Handle()  interrupt 1
{
	   char cnt;
		  cnt++;      // 统计爆表的次数
	    TH0=0xFE;   //配置高八位
	    TL0=0X33;   //配置低八位
	    if(cnt<jd)   //0.5ms 以内
			{
        fan_A=1;
		  	fan_B=0;
			}
			else 
			{
				fan_A=0;
		  	fan_B=0;
			}
			if(cnt==40)  //20MS 内
			{
				cnt=0;
				 fan_A=1;
		  	fan_B=0;

			}

}
void UartInit(void)		//9600bps@11.0592MHz
{
    SCON=0x40; //配置串行口方式1, REN禁止
	  TMOD &=0X0F;
	  TMOD |=0X20; //配置定时器1为8位自动重载
	  TH1=0xfd; //波特率设置 253
	  TL1=0xfd;
	  TR1=1;//打开定时计数器1;
}

void sendByte(char data_msg)
{
  SBUF=data_msg;
  while(!TI);
  TI=0;//发送中断请求标志位  来代替瞎延时
}

void sendString(char *str)
{
  while(*str!='\0')
	{
	   sendByte(*str);
		str++;
	}

}

char putchar (char c) //实现printf函数发送功能
{
	SBUF=c;
  while (!TI);
  TI = 0;
  return c;
}



void main ()
{
float tmp;
	int j;

	UartInit();
	Time0Init();
	ds18b20_init();
	while(1)
	{


    tmp=ds18b20_read_temperture();//23.458
	  j=(tmp*10+0.5)*10;//
		Delay300ms();
		Delay300ms();
		Delay300ms();
		Delay300ms();
		if(tmp>20)
		{
		   jd=40;

		}
		if(tmp<20)
		{
		   jd=15;
		}
		printf("温度为%d%d.%d%d℃\r\n",j/1000,j%1000/100,j%100/10,j%10);
	}
}

```c
#include "ds18b20.h" 
#include "intrins.h"
#include<reg52.h>
/********************************************************************
***********
* 函 数 名 : ds18b20_init
* 函数功能 : 初始化 DS18B20 的 IO 口 DQ 同时检测 DS 的存在
* 输 入 : 无
* 输 出 : 1:不存在,0:存在
*********************************************************************
**********/
u8 ds18b20_init(void)
{
	ds18b20_reset();	// 复位 DS18B20
	return ds18b20_check();	// 检测 DS18B20 是否存在
}
 
 
/********************************************************************
***********
* 函 数 名 : ds18b20_reset
* 函数功能 : 复位 DS18B20
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
 
void ds18b20_reset(void)
{
	DS18B20_PORT=0;	//首先拉低总线,给这个总线,DQ输出个低电平
	Delay10us(75);	//输出这个总线有个要求,要持续480-960us之间,这里要有个延时函数
	DS18B20_PORT=1;//延时过后要释放总线,拉高总线,给这个总线,DQ输出个高电平
	Delay10us(2); // 释放总线有个要求,要持续15-60us之间,这里要有个延时函数
}
/********************************************************************
***********
* 函 数 名 : ds18b20_check
* 函数功能 : 检测 DS18B20 是否存在
* 输 入 : 无
* 输 出 : 1:未检测到 DS18B20 的存在,0:存在
*********************************************************************
**********/
u8 ds18b20_check(void)
{
	u8 time_temp=0;
//while(DS18B20_PORT&&time_temp<20) ,等待 DQ 为低电平,,根据与运算,任何一个为假则退出,第一种检测到DS18B20_PORT低电平,
//则直接退出。第二种检测DS18B20_PORT高电平,则进入while循环,持续等待,每循环一次time_temp+1,当time_temp>=20,
//则还没有检测到低电平,就退出循环。
 
	while(DS18B20_PORT&&time_temp<20) 
	{
		time_temp++;
		Delay10us(1);
	}
	if(time_temp>=20)return 1; //如果超时则强制返回 1,等待20次没有检测到低电平就返回1,表示未检测到 DS18B20 的存在
	else time_temp=0;	//检测到低电平,则直接进else 语句,不会执行上面if语句,time_temp归零等待下次检测
 
//while((!DS18B20_PORT)&&time_temp<20),等待 DQ 为高电平,,根据与运算,任何一个为假则退出,第一种检测到DS18B20_PORT高电平,
//这里(!DS18B20_PORT)非一下,就变成低电平,条件为假,则直接退出。第二种检测DS18B20_PORT低电平,这里(!DS18B20_PORT)非一下,
//就变成高电平,则进入while循环,持续等待,每循环一次time_temp+1,当time_temp>=20,则还没有检测到低高平,就退出循环。
	while((!DS18B20_PORT)&&time_temp<20) //等待 DQ 为高电平
	{
		time_temp++;
		Delay10us(1);
	}
	if(time_temp>=20)return 1; //如果超时则强制返回 1 ,等待20次没有检测到高电平就返回1,表示未检测到 DS18B20 的存在
	return 0; //如果
}
/*******************************************************************************
* 函 数 名         : ds18b20_read_bit
* 函数功能		   : 从DS18B20读取一个位
* 输    入         : 无
* 输    出         : 1/0
*******************************************************************************/
u8 ds18b20_read_bit(void)  //读是没有入口参数的是void类型
{
	u8 dat=0;//定义一个变量保存读取到的值,初值为0
	DS18B20_PORT=0;//根据时序图,我们要先输出一个低电平
	_nop_();_nop_(); //延时2个us
	DS18B20_PORT=1;	//释放总线,因为IO口有上拉电阻,置1才视为释放总线
//当发送完0后,DS18B20将会释放总线,则通过上拉电阻该总线将会恢复到高电平的闲置状态。
//从DS18B20中输出的数据在初始化读时序后仅有15us的有效时间。因此,主设备在开始改读时
//段后的15us之内必须释放总线,并且对总线进行采样
	_nop_();_nop_(); //该段时间不能过长,必须在15us内读取数据
	if(DS18B20_PORT)dat=1; //如果总线上为1则数据dat为1,否则为0
	else dat=0;
	Delay10us(5);	
	return dat;//返回读取到的值
}
/*******************************************************************************
* 函 数 名         : ds18b20_read_byte
* 函数功能		   : 从DS18B20读取一个字节
* 输    入         : 无
* 输    出         : 一个字节数据
*******************************************************************************
举例:ds18b20_read_bit=10010001,循环8次,每次读取一位,且先读低位再读高位,temp8次读取到的位依次是如下
           temp<<7		  dat>>1	  dat=(temp<<7)|(dat>>1);
temp=1	   10000000		  00000000	  10000000
temp=0	   00000000		  01000000	  01000000
temp=0	   00000000		  00100000	  00100000
temp=0	   00000000		  00010000	  00010000
temp=1	   10000000		  00001000	  10001000
temp=0	   00000000		  01000100	  01000100
temp=0	   00000000		  00100010	  00100010
temp=1	   10000000		  00010001	  10010001
*******************************************************************************/
 
u8 ds18b20_read_byte(void)//读是没有入口参数的是void类型
{
	u8 i=0;//一个字节8位,要循环8次,定义一个变量
	u8 temp=0;//保存读取到的位
	u8 dat=0; //保存读取到的字节
	for(i=0;i<8;i++)
	{
		temp=ds18b20_read_bit();//循环8次,每次读取一位,且先读低位再读高位
 
		dat=(temp<<7)|(dat>>1);	//现将读取的位,左移7位到最高位,因为是先读低位再读高位,在右移一位,循环8次,移到最低位
		                        //为了之前读取到的数值,在下次循环的时候不丢失,这里用 | 或运算(参加运算的两个数只要两个数中的一个为1,结果就为1。),
								//把(temp<<7)和(dat>>1) 两个相加在赋予dat
 
	}
	return dat;
 
}	
 
/*******************************************************************************
* 函 数 名         : ds18b20_write_byte
* 函数功能		   : 写一个字节到DS18B20
* 输    入         : dat:要写入的字节
* 输    出         : 无
*******************************************************************************/
void ds18b20_write_byte(u8 dat)
{
	u8 i=0;
	u8 temp=0; //把要写入的字节保存在temp里面
	for (i=0;i<8;i++) //循环8次,每次写一位,且先写低位再写高位
	{
		temp=dat&0x01; //选择低位准备写入,根据与运算方法,前后条件同时满足表达式为真,是从低位开始写,dat最低位是1,和0x01比较,temp=1,如果
		               //dat最低位是0,和0x01比较,temp=0,
		dat>>=1;//因为这里dat&0x01比较的是最低位,所以要将次高位移到低位
		if(temp)
		{
			DS18B20_PORT=0;//主机DS18B20_PORT输出低电平,延时 2us,然后释放总线,延时 60us。
 
//* 函 数 名         : _nop_()
//* 函数功能		   : 指令的延迟时间为 1us
//51单片机中,1个机械周期 = 12个时钟周期 = 12 * ( 1 / f)。(f 为晶振频率)。
// 如果只用的是12MHZ的晶振,那么 一个机械周期就是1us;也就是说:
// _nop_(); 指令的延迟时间为 1us。可以较为精确得控制延迟时间
			_nop_();_nop_();//延时2us ,一个_nop_()是1us
			DS18B20_PORT=1;	//然后释放总线,	 DS18B20_PORT输出高电平
			Delay10us(6); //延时 60us
		}
		else
			DS18B20_PORT=0;	//写 0时序:主机DS18B20_PORT输出低电平,延时 60us,然后释放总线,延时 2us。
			Delay10us(6);	//延时 60us
			DS18B20_PORT=1;	//然后释放总线,	 DS18B20_PORT输出高电平
			_nop_();_nop_();//延时2us ,一个_nop_()是1us	
			
			
	}
}
 
 
/********************************************************************
***********
* 函 数 名 : ds18b20_start
* 函数功能 : 开始温度转换
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void ds18b20_start(void)
{
	ds18b20_reset(); //复位
	ds18b20_check(); //检查DS18B20
	ds18b20_write_byte(0XCC);//发 SKIP ROM 命令 ROM
	ds18b20_write_byte(0X44);//发开始转换命令(0X44)
 
}
 
 
/********************************************************************
***********
* 函 数 名 : ds18b20_read_temperture
* 函数功能 : 从 ds18b20 得到温度值
* 输 入 : 无
* 输 出 : 温度数据
*********************************************************************
**********/
 
float ds18b20_read_temperture(void)//因为温度有可能是小数,负数等,所以定义一个float类型的返回值
{
	u8 dath=0;//保存读取的高字节数据
	u8 datl=0;//保存读取的低字节数据
	u16 value=0;//保存dath和datl合并后的数据
	float temp=0;//保存读取到的实际温度
	ds18b20_start();//开始转换
	//delay_ms(1);//此处也可以不用延时,在检测ds18b20_check()里面已经包含 ,这里可以省略
	ds18b20_reset(); //复位
	ds18b20_check(); //检查DS18B20
	ds18b20_write_byte(0XCC);//发 SKIP ROM 命令 ROM
	ds18b20_write_byte(0XBE);//发读存储器命令
	datl=ds18b20_read_byte();//读取的低字节
	dath=ds18b20_read_byte();//读取的高字节
	value=(dath<<8)+datl; //dath和datl两个8字节的数据,合并为16个字节的数据
	if((value&0xf800)==0xf800)//通过&运算来判断前5位是否位1
	{
		value=(~value)+1;//如果为1,就是负温度,读到的数值需要取反加 1 再乘以 0.0625 即可得到实际温度。
	    temp=value*(-0.0625);//将读到的实际温度保存在temp里面,因为是负温度,所以这里乘以-0.0625
	}
	else //如果不等于1,那就是0 ,就是正温度,正温度直接乘以0.0625 即可得到实际温度
	{
		 temp=value*0.0625;//将读到的实际温度保存在temp里面
		
	}
 
	return temp; //将得到的温度返回出去
 
}

void Delay10us(u8 z)		//@11.0592MHz
{
	unsigned char data i;
	unsigned char data j;
 for(j=z;j>0;j--)
 {
	i = 2;
	while (--i);
 }
}

实验结果

在这里插入图片描述
在这里插入图片描述


`
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值