温控风扇

转载需注明出处! https://blog.csdn.net/langzi_a/article/details/85267804

基于51单片机的温控风扇,供学弟学妹们学习用。感兴趣可以根据下面的资料自己焊接一个电路。

eeprom52.h文件百度云连接:

链接:https://pan.baidu.com/s/1oBYJWI3F76QNgdx20Ktb_g
提取码:e889

一、程序及说明

#include
#include			 //包含头文件
#define uchar unsigned char
#define uint unsigned int		 //宏定义
#include "eeprom52.h"
////////////////////
sbit dj=P1^0;//电机控制端接口
sbit DQ=P1^6;//温度传感器接口
//////////按键接口/////////////////////////////////
sbit key1=P3^5;//设置温度
sbit key2=P3^6;//温度加
sbit key3=P3^7;//温度减
//////////////////////////////////////////////////////
sbit w1=P2^4;
sbit w2=P2^5;
sbit w3=P2^6;
sbit w4=P2^7;			  //数码管的四个位
/////共阴数码管段选//////////////////////////////////////////////
uchar table[22]=
{0x3F,0x06,0x5B,0x4F,0x66,
0x6D,0x7D,0x07,0x7F,0x6F,
0x77,0x7C,0x39,0x5E,0x79,0x71,
0x40,0x38,0x76,0x00,0xff,0x37};//'-',L,H,灭,全亮,n	 16-21
uint wen_du;						//温度变量  
int shang,xia; //对比温度暂存变量
uchar dang;//档位显示
uchar flag;
uchar d1,d2,d3;//显示数据暂存变量
uchar m;
uchar js;

/******************把数据保存到单片机内部eeprom中******************/
void write_eeprom()
{
	SectorErase(0x2000);		//清除扇区
	byte_write(0x2000, shang);	//写上限数值到扇区
	byte_write(0x2001, xia);	//写下限数值到扇区
	byte_write(0x2060, a_a);	//写初始变量到扇区指定位置
}

/******************把数据从单片机内部eeprom中读出来*****************/
void read_eeprom()
{
	shang   = byte_read(0x2000);		 //从扇区读取上限数据
	xia = byte_read(0x2001);			 //从扇区读取下限数据
	a_a      = byte_read(0x2060);		 //从扇区读取初始变量
}

/**************开机自检eeprom初始化*****************/
void init_eeprom() 
{
	read_eeprom();		//先读扇区的数据
	if(a_a != 1)		//判断是否是新单片机(原理:新的单片机扇区里的数据都是0,这里判断是否不等于1。如果是不等于1,就是等于0,那就是新单片机了,就会执行下面的上下限值初始化数值的语句,并让a_a变成1,下次开机就会知道是用过的单片机了就会读取EEPROM里的上下限数据了)
	{
		shang   = 30;	//上限数值初始为30
		xia = 20;		//下限数值初始为20
		a_a = 1;		//初始值变量赋值1,下次开机就会直接读取EEPROM内的上下限数据
		write_eeprom();	   //将初始的数据保存进单片机的EEPROM
	}	
}

void delay(uint ms)		//延时函数,大约延时25us,不精确		  走一条指令约为1us
{
	uint x;
	for(ms;ms>0;ms--)
		for(x=10;x>0;x--);
}
/***********ds18b20延迟子函数(晶振12MHz )*******/ 
void delay_18B20(uint i)
{
	while(i--);
}
/**********ds18b20初始化函数**********************/
void Init_DS18B20() 
{
	 uchar x=0;
	 DQ=1;          //DQ复位
	 delay_18B20(8);  //稍做延时
	 DQ=0;          //单片机将DQ拉低
	 delay_18B20(80); //精确延时 大于 480us
	 DQ=1;          //拉高总线
	 delay_18B20(14);
	 x=DQ;            //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
	 delay_18B20(20);
}
/***********ds18b20读一个字节**************/  
uchar ReadOneChar()
{
	uchar i=0;
	uchar dat=0;
	for (i=8;i>0;i--)
	 {
		  DQ=0; // 给脉冲信号
		  dat>>=1;
		  DQ=1; // 给脉冲信号
		  if(DQ)
		  dat|=0x80;
		  delay_18B20(4);
	 }
 	return(dat);
}
/*************ds18b20写一个字节****************/  
void WriteOneChar(uchar dat)
{
 	uchar i=0;
 	for (i=8;i>0;i--)
 	{
  		DQ=0;
 		DQ=dat&0x01;
    	delay_18B20(5);
 		DQ=1;
    	dat>>=1;
	}
}
/**************读取ds18b20当前温度************/
void ReadTemperature()
{
	uchar a=0;
	uchar b=0;
	uchar t=0;
	Init_DS18B20();
	WriteOneChar(0xCC);    	// 跳过读序号列号的操作
	WriteOneChar(0x44); 	// 启动温度转换
	delay_18B20(100);       // this message is very important
	Init_DS18B20();
	WriteOneChar(0xCC); 	//跳过读序号列号的操作
	WriteOneChar(0xBE); 	//读取温度寄存器等(共可读9个寄存器) 前两个就是温度
	delay_18B20(100);
	a=ReadOneChar();    	//读取温度值低位
	b=ReadOneChar();   		//读取温度值高位
	wen_du=((b*256+a)>>4);    //当前采集温度值除16得实际温度值
}
void zi_keyscan()//自动模式按键扫描函数
{
	if(key1==0)							  //设置键按下
	{
		delay(300);						  //延时去抖
		if(key1==0)flag=1;				  //再次判断按键,按下的话进入设置状态
		while(key1==0);//松手检测		  //按键释放
	}
	while(flag==1)						  //进入设置上限状态
	{
		d1=18;d2=shang/10;d3=shang%10;	  //显示字母H 和上限温度值
		if(key1==0)						  //判断设置键是否按下
		{
			delay(300);					  //延时去抖
			if(key1==0)flag=2;			  //按键按下,进入设置下限模式
			while(key1==0);//松手检测
		}
		if(key2==0)						  //加键按下
		{
			delay(300);					  //延时去抖
			if(key2==0)					  //加键按下
			{
				shang+=5;				  //上限加5
				if(shang>=100)shang=100;  //上限最大加到100
			}while(key2==0);//松手检测
			write_eeprom();			   //保存数据
		}
		if(key3==0)						  //减键按下
		{
			delay(300);					  //延时去抖
			if(key3==0)					  //减键按下
			{
				shang-=1;				  //上限减1
				if(shang<=10)shang=10;	  //上限最小减到10
			}while(key3==0);//松手检测
			write_eeprom();			   //保存数据
		}		
	}
	while(flag==2)						  //设置下限
	{
		d1=17;d2=xia/10;d3=xia%10;		  //显示字母L 显示下限温度值
		if(key1==0)
		{
			delay(300);
			if(key1==0)flag=0;
			while(key1==0);//松手检测
		}
		if(key2==0)
		{
			delay(300);
			if(key2==0)
			{
				xia+=5;
				if(xia>=95)xia=95;	
			}while(key2==0);//松手检测
			write_eeprom();			   //保存数据
		}
		if(key3==0)
		{
			delay(300);
			if(key3==0)
			{
				xia-=1;
				if(xia<=0)xia=0;	
			}while(key3==0);//松手检测
			write_eeprom();			   //保存数据
		}		
	}
}
void zi_dong()//自动温控模式
{
	d1=dang;d2=wen_du/10;d3=wen_du%10;		//显示档位,显示当前温度值
	zi_keyscan();//按键扫描函数
	if(wen_du=xia)&&(wen_du<=shang))//温度大于下限,小于上限  1挡
	{dang=1;}
	if(wen_du>shang){dang=2;}//温度大于上限,2档
}

void init()		   //定时器初始化函数
{
	TMOD=0x01;	   //定时器0工作方式1
	TH0=0xf8;
	TL0=0x30;	   //定时器初值5ms
	ET0=1;		   //打开定时器0中断允许
	TR0=1;		   //打开定时器0定时器开关
	EA=1;		   //打开中断系统总开关
}
void main()		  //主函数
{
	uchar j;
	dj=0;		  //电机开
	init_eeprom();  //开始初始化保存的数据
	for(j=0;j<80;j++)	  //先读取温度值,防止开机显示85
	ReadTemperature();
	init();
	while(1)			  //进入while循环
	{
		if(js>=50)			//当js在定时器里加到50次时(js加一次是20ms,加到50次就是1000ms,也就是1秒读取一次温度)
		{
			ReadTemperature();	//读取温度值
			js=0;				//定时读取温度的变量js清零,重新计时下次读取温度
		}	
		
		zi_dong();//判断当前需要哪一个档位
	}
}

/*
控制占空比原理:
定时器每5ms控制变量m加一,当m加到4时,将m清零。
也就是占空比的一个周期是5ms*4=20ms,频率就是50Hz。
因为m是加四次是一个周期,也就是加一次占空比是加25%。
下面程序里if(m<=3)dj=1;else dj=0;就是让dj高电平的时间是m加3次的时间,而dj为低电平的时间就是加第四次的时间,所以占空比就是3/4就是75%
*/

void T0_TIME() interrupt 1		  //定时器工作函数,用于PWM工作
{
	TH0=0xf8;
	TL0=0x30;					  //定时器赋初值5ms
	m++;						  //5ms,m加一
	switch(dang)				  //判断档位
	{
		case 0:dj=0;break;		  //0档,控制电机停止
		case 1:if(m<=3)dj=1;else dj=0;break;//控制电机以75%占空比转动
		case 2:dj=1;break;		  //2档,控制电机100%占空比转动
		default:;				  //其他情况,直接跳出
	}
	switch(m)					  //判断m的数值
	{
		case 1:									//m为1时
				w4=1;P0=table[d1];w1=0; break;	//关闭低四位数码管位选;P0口输出对应数字的段码;打开第一位数码管位选
		case 2:
				w1=1;P0=table[16];w2=0; break;	//关闭低一位数码管位选;P0口输出对应数字的段码;打开第二位数码管位选
		case 3:
				w2=1;P0=table[d2];w3=0;	break;	//关闭低二位数码管位选;P0口输出对应数字的段码;打开第三位数码管位选
		case 4:
				w3=1;P0=table[d3];w4=0;m=0;if(js<50)js++;break; //关闭低三位数码管位选;P0口输出对应数字的段码;打开第四位数码管位选
																//js变量小于50时,就让js加,加到50后,主函数里就会执行一次读取温度函数
		default:;								//其他情况时跳出
	}
	if(m>4)	  //m加到大于4时,将m清零
	{
		m=0;  //m清零
	}
}
  • 1.本设计基于STC89C51/52(与AT89S51/52、AT89C51/52通用,可任选)单片机
  • 2.采用DS18B20温度传感器测温,74HC573驱动数码管显示温度和风扇的档位。
  • 3.共3个按键:设置、加、减。按一下设置可以设置上限,再按下设置下限,均可以按键加减调整。
  • 4.利用PWM调速,当温度低于下限时,风扇不转动,当温度处于上、下限之间时1档转动(50%的转速),当温度超过上限时,全速转动。

使用说明:

一共3个按键:设置、加、减

按下设置键的时候才可以加减。 

按一下设置键,是设置温度的上限,再按下设置键,是设置温度的下限,再按下设置键是退出并保存。

二、实物图

温控风扇_第1张图片  温控风扇_第2张图片

三、焊接效果

温控风扇_第3张图片温控风扇_第4张图片

温控风扇_第5张图片温控风扇_第6张图片

四、其他

1.数码管

.温控风扇_第7张图片

2、电源插口

温控风扇_第8张图片

3、轻触按键

温控风扇_第9张图片

4、三极管

常见的三极管为9012、s8550、9013、s8050.单片机应用电路中三极管主要的作用就是开关作用。
其中9012与8550为pnp型三极管,可以通用。
其中9013与8050为npn型三极管,可以通用。
区别引脚:三极管向着自己,引脚从左到右分别为ebc,原理图中有箭头的一端为e,与电阻相连的为b,另一个为c。箭头向里指为PNP(9012或8550),箭头向外指为NPN(9013或8050)。

温控风扇_第10张图片

 5、排阻

其实排阻就是由8个电阻组成的,其中一端全部接在一起,103为8个10K电阻,
102为8个1K电阻,他们在电路中起到“上拉”的作用,又称上拉电阻。
上拉就是将不确定的信号通过一个电阻嵌位在高电平,电阻同时起限流作用,下拉同理.
上拉是对器件注入电流,下拉是输出电流,弱强只是上拉电阻的阻值不同,没有什么严格区分,对于非集电极(或漏极)开路输出型电路(如普通门电路)提升电流和电压的能力是有限的,上拉电阻的功能主要是为集电极开路输出型电路输出电流通道。
上拉,就是把电位拉高,比如拉到VCC
下拉,就是把电压拉低,拉到GND
一般就是刚上电的时候,端口电压不稳定,为了让他稳定为高或低,就会用到上拉或下拉电阻。
有些芯片内部集成了上拉电阻(如单片机的P1、2、3口),所以外部就不用上拉电阻了。但是有一些开漏的(如单片机的P0口),外部必须加上拉电阻。

温控风扇_第11张图片温控风扇_第12张图片

 6、自锁开关

温控风扇_第13张图片

7、74ls573

温控风扇_第14张图片

8、芯片引脚图

温控风扇_第15张图片

 9、数码管显示电路

本电路的显示模块主要由一个4位一体的7段LED数码管构成,用于显示测量到的温度及当前的档位。它是一个共阴极的数码管,每一位数码管的a,b,c,d,e,f,g和dp端都各自连接在一起,用于接收单片机的P0口产生的显示段码。S1,S2,S3,S4引脚端为其位选端,用于接收单片机的P2口产生的位选码。本系统采用动态扫描方式。扫描方式是用其接口电路把所有数码管的8个比划段a~g和dp同名端连在一起,而每一个数码管的公共极COM各自独立地受I/O线控制。CUP从字段输出口送出字型码时,所有数码管接收到相同的字型码,但究竟是哪个数码管亮,则取决于COM端。COM端与单片机的I/O接口相连接,由单片机输出位位选码到I/O接口,控制何时哪一位数码管被点亮。在轮流点亮数码管的位扫描过程中,每位数码管的点亮时间极为短暂。但由于人的视觉暂留现象,给人的印象就是一组稳定显示的数码。动态方式的优点是十分明显的,即耗电省,在动态扫描过程中,任何时刻只有一个数码管是处于工作状态的。具体原理图如图3-18所示

温控风扇_第16张图片

               

10、上拉电阻总结

上拉电阻:

   1、当TTL电路驱动COMS电路时,如果TTL电路输出的高电平低于COMS电路的最低高电平(一般为3.5V),这时就需要在TTL的输出端接上拉电阻,以提高输出高电平的值。

   2、OC门电路必须加上拉电阻,才能使用。

   3、为加大输出引脚的驱动能力,有的单片机管脚上也常使用上拉电阻。

   4、在COMS芯片上,为了防止静电造成损坏,不用的管脚不能悬空,一般接上拉电阻产生降低输入阻抗,提供泄荷通路。

   5、芯片的管脚加上拉电阻来提高输出电平,从而提高芯片输入信号的噪声容限增强抗干扰能力。

   6、提高总线的抗电磁干扰能力。管脚悬空就比较容易接受外界的电磁干扰。

   7、长线传输中电阻不匹配容易引起反射波干扰,加上下拉电阻是电阻匹配,有效的抑制反射波干扰。

 

上拉电阻阻值的选择原则包括:

   1、从节约功耗及芯片的灌电流能力考虑应当足够大;电阻大,电流小。

   2、从确保足够的驱动电流考虑应当足够小;电阻小,电流大。

   3、对于高速电路,过大的上拉电阻可能边沿变平缓。综合考虑

以上三点,通常在1k到10k之间选取。对下拉电阻也有类似道理

 

对上拉电阻和下拉电阻的选择应结合开关管特性和下级电路的输入特性进行设定,主要需要考虑以下几个因素:

   1. 驱动能力与功耗的平衡。以上拉电阻为例,一般地说,上拉电阻越小,驱动能力越强,但功耗越大,设计是应注意两者之间的均衡。

   2. 下级电路的驱动需求。同样以上拉电阻为例,当输出高电平时,开关管断开,上拉电阻应适当选择以能够向下级电路提供足够的电流。

   3. 高低电平的设定。不同电路的高低电平的门槛电平会有不同,电阻应适当设定以确保能输出正确的电平。以上拉电阻为例,当输出低电平时,开关管导通,上拉电阻和开关管导通电阻分压值应确保在零电平门槛之下。

   4. 频率特性。以上拉电阻为例,上拉电阻和开关管漏源级之间的电容和下级电路之间的输入电容会形成RC延迟,电阻越大,延迟越大。上拉电阻的设定应考虑电路在这方面的需求。

下拉电阻的设定的原则和上拉电阻是一样的。

OC门输出高电平时是一个高阻态,其上拉电流要由上拉电阻来提供,设输入端每端口不大于100uA,设输出口驱动电流约500uA,标准工作电压是5V,输入口的高低电平门限为0.8V(低于此值为低电平);2V(高电平门限值)。

选上拉电阻时:

500uA x 8.4K= 4.2即选大于8.4K时输出端能下拉至0.8V以下,此为最小阻值,再小就拉不下来了。如果输出口驱动电流较大,则阻值可减小,保证下拉时能低于0.8V即可。

当输出高电平时,忽略管子的漏电流,两输入口需200uA

200uA x15K=3V即上拉电阻压降为3V,输出口可达到2V,此阻值为最大阻值,再大就拉不到2V了。选10K可用。COMS门的可参考74HC系列

设计时管子的漏电流不可忽略,IO口实际电流在不同电平下也是不同的,上述仅仅是原理,一句话概括为:输出高电平时要喂饱后面的输入口,输出低电平不要把输出口喂撑了(否则多余的电流喂给了级联的输入口,高于低电平门限值就不可靠了)                                     

 

在数字电路中不用的输入脚都要接固定电平,通过1k电阻接高电平或接地。

1. 电阻作用:

l 接电组就是为了防止输入端悬空

l 减弱外部电流对芯片产生的干扰

l 保护cmos内的保护二极管,一般电流不大于10mA

l 上拉和下拉、限流

l 1. 改变电平的电位,常用在TTL-CMOS匹配

2. 在引脚悬空时有确定的状态

3.增加高电平输出时的驱动能力。

4、为OC门提供电流

l 那要看输出口驱动的是什么器件,如果该器件需要高电压的话,而输出口的输出电压又不够,就需要加上拉电阻。

l 如果有上拉电阻那它的端口在默认值为高电平你要控制它必须用低电平才能控制如三态门电路三极管的集电极,或二极管正极去控制把上拉电阻的电流拉下来成为低电平。反之,

l 尤其用在接口电路中,为了得到确定的电平,一般采用这种方法,以保证正确的电路状态,以免发生意外,比如,在电机控制中,逆变桥上下桥臂不能直通,如果它们都用同一个单片机来驱动,必须设置初始状态.防止直通!

 

2、定义:

l 上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!下拉同理!

l 上拉是对器件注入电流,下拉是输出电流

l 弱强只是上拉电阻的阻值不同,没有什么严格区分

l 对于非集电极(或漏极)开路输出型电路(如普通门电路)提升电流和电压的能力是有限的,上拉电阻的功能主要是为集电极开路输出型电路输出电流通道。

 

3、为什么要使用拉电阻:

l 一般作单键触发使用时,如果IC本身没有内接电阻,为了使单键维持在不被触发的状态或是触发后回到原状态,必须在IC外部另接一电阻。

l 数字电路有三种状态:高电平、低电平、和高阻状态,有些应用场合不希望出现高阻状态,可以通过上拉电阻或下拉电阻的方式使处于稳定状态,具体视设计要求而定!

l 一般说的是I/O端口,有的可以设置,有的不可以设置,有的是内置,有的是需要外接,I/O端口的输出类似与一个三极管的C,当C接通过一个电阻和电源连接在一起的时候,该电阻成为上C拉电阻,也就是说,如果该端口正常时为高电平,C通过一个电阻和地连接在一起的时候,该电阻称为下拉电阻,使该端口平时为低电平,作用吗:

比如:当一个接有上拉电阻的端口设为输如状态时,他的常态就为高电平,用于检测低电平的输入。

l 上拉电阻是用来解决总线驱动能力不足时提供电流的。一般说法是拉电流,下拉电阻是用来吸收电流的,也就是你同学说的灌电流

电阻在选用时,选用经过计算后与标准值最相近的一个!

P0为什么要上拉电阻原因有:

1. P0口片内无上拉电阻

2. P0为I/O口工作状态时,上方FET被关断,从而输出脚浮空,因此P0用于输出线时为开漏输出。

3. 由于片内无上拉电阻,上方FET又被关断,P0输出1时无法拉升端口电平。

P0是双向口,其它P1,P2,P3是准双向口。

不错准双向口是因为在读外部数据时要先“准备”一下,为什么要准备一下呢?

单片机在读准双向口的端口时,现应给端口锁存器赋1,目的是使FET关断,不至于因片内FET导通使端口钳制在低电平。

上下拉一般选10k!

芯片的上拉/下拉电阻的作用

最常见的用途是,假如有一个三态的门带下一级门.如果直接把三态的输出接在下一级的输入上,当三态的门为高阻态时,下一级的输入就如同漂空一样.可能引起逻辑的错误,对MOS电路也许是有破坏性的.所以用电阻将下一级的输入拉高或拉低,既不影响逻辑又保正输入不会漂空.

改变电平的电位,常用在TTL-CMOS匹配; 在引脚悬空时有确定的状态; 为OC门的输出提供电流; 作为端接电阻; 在试验板上等于多了一个测试点,特别对板上表贴芯片多的更好,免得割线; 嵌位;

上、下拉电阻的作用很多,比如抬高信号峰峰值,增强信号传输能力,防止信号远距离传输时的线上反射,调节信号电平级别等等!当然还有其他的作用了具体的应用方法要看在什么场合,什么目的,至于参数更不能一概而定,要看电路其他参数而定,比如通常用在输入脚上的上拉电阻如果是为了抬高峰峰值,就要参考该引脚的内阻来定电阻值的!另外,没有说输入加下拉,输出加上拉的,有时候没了某个目的也可能同时既有上拉又有下拉电阻的!

加接地电阻--下拉

加接电源电阻--上拉

对于漏极开路或者集电极开路输出的器件需要加上拉电阻才可能工作。另外,普通的口,加上拉电阻可以提高抗干扰能力,但是会增加负载。

电源:+5V

普通的直立LED,

共八个,负极分别接到一个大片子的管脚上,

用多大的上拉电阻合适? 谢谢指教!

一般LED的电流有几个mA就够了,最大不超过20mA,根据这个你就应该可以算出上拉电阻值来了。

保献起见,还是让他拉吧,(5-0.7)/10mA=400ohm,差不多吧,不放心就用2k的

奇怪,新出了管压0.7V的LED了吗?据我所知好象该是1.5V左右。我看几百欧到1K都没太大问题,一般的片子不会衰到10mA都抗不住吧?

上拉电阻的作用:6N137的的输出三极管C极,如果没有上拉电阻,则该引脚上的电平不会发生随B极电平的高低变化。原因是它没有接到任何电源上。如果接上了上拉电阻,则B极电平为高时,C极对地导通(相当于开关接通),C极的电压就变低;如B极电压为低,则C极对地关断,C极的电压就升到高电平。为就是上面说的“将通断转换成高低电平”。你说的51与此图有一定的不同,参照着去理解吧。另外,一般地,C极低电平时器件从外部吸入电流的能力和高电平时向外部灌出电流的能力是不一样的。器件输出端常有Isink和Isource两个参数,且前者往往大于后者。

下拉电阻的作用:所见不多,常见的是接到一个器件的输入端,多作为抗干扰使用。这是由于一般的IC的输入端悬空时易受干扰或器件扫描时有间隙泄漏电压而影响电路的性能。后者,我们在某批设备中曾碰到过。

上拉电阻的阻值主要是要顾及端口的低电平吸入电流的能力。例如在5V电压下,加1K上拉电阻,将会给端口低电平状态增加5mA的吸入电流。在端口能承受的条件下,上拉电阻小一点为好。

提高负载能力、提高直流工作电平

无信号是给电路提供确定的电平

 

你可能感兴趣的:(51单片机)