基于51单片机的智能温控风扇

1.功能
本设计为一种温控风扇系统,具有灵敏的温度感测和显示功能,系统选用STC89C52单片机作为控制平台对风扇转速进行控制。可在测得温度值在高低温度之间时打开风扇弱风档,当温度升高超过所设定的温度时自动切换到大风档,当温度小于所设定的温度时自动关闭风扇,控制状态随外界温度而定。

2.硬件设计
在这里插入图片描述
硬件电路主要由:

  1. 单片机最小系统
  2. 风扇驱动电路
  3. LCD1602显示屏电路
  4. DS18B20温度采集电路

3.程序设计

(1)LCD1602驱动程序

#define LCD1602_DB  P0
sbit LCD1602_RS = P2^0;
sbit LCD1602_RW = P2^1;
sbit LCD1602_E  = P2^2;

/* 等待液晶准备好 */
void LcdWaitReady()
{
    unsigned char sta;
    
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;
        sta = LCD1602_DB; //读取状态字
        LCD1602_E = 0;
    } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
    
    if (y == 0)  //由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x;  //第一行字符地址从0x00起始
    else
        addr = 0x40 + x;  //第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);  //设置RAM地址
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
    LcdSetCursor(x, y);   //设置起始地址
    while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);
    }
}
/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
    LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}

(2)DS18B20驱动程序

sbit IO_18B20=P3^2;

/*软件延时函数,延时时间(t*10)us*/
void DelayX10us(unsigned char t)
{
	do{
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
	}while(--t);
}
/*复位总线,获取存在脉冲,以启动一次读写操作*/
bit Get18B20Ack()
{
	bit ack;
	
	EA=0;	   			//禁止总中断
	IO_18B20=0;			//产生500us复位脉冲
	DelayX10us(50);
	IO_18B20=1;
	DelayX10us(6);		//延时60us
	ack=IO_18B20;		//读取存在脉冲
	while(!IO_18B20);   //等待存在脉冲结束
	EA=1;				//重新使能总中断
	return ack;
}
/*向DS18B20写入一个字节,dat-待写入字节*/
void Write18B20(unsigned char dat)
{
	unsigned char mask;
	EA=0;
	for(mask=0x01;mask!=0;mask<<=1)//低位在先,依次移出8个bit
	{
		IO_18B20=0;//产生2us低电平脉冲
		_nop_();
		_nop_();
		if((mask&dat)==0)//输出该bit值
			IO_18B20=0;
		else
			IO_18B20=1;
		DelayX10us(6);//延时60us
		IO_18B20=1;//拉高通信引脚
	}
	EA=1;
}
/*从DS18B20读取一个字节,返回值-读到的字节*/
unsigned char Read18B20()
{
	unsigned char dat;
	unsigned char mask;

	EA=0;
	for(mask=0x01;mask!=0;mask<<=1)//低位在先,依次采集8个bit
	{
		IO_18B20=0;//产生2us低电平脉冲
		_nop_();
		_nop_();
		IO_18B20=1;//结束低电平脉冲,等待18B20输出数据
		_nop_(); //延时2us
		_nop_();
		if(!IO_18B20)//读取通信引脚上的值
			dat &= ~mask;
		else
			dat |= mask;
		DelayX10us(6);//再延时60us
	}
	EA=1;
	return dat;
}
/*启动一次18B20温度转换,返回值-表示是否启动成功*/
bit Start18B20()
{
	bit ack;
	ack=Get18B20Ack();//执行总线复位,并获取18B20应答
	if(ack==0)
	{
		Write18B20(0xCC);
		Write18B20(0x44);
	}
	return ~ack;
}
/*读取DS18B20转换的温度值,返回值-表示是否读取成功*/
bit Get18B20Temp(int *temp)
{
	bit ack;
	unsigned char LSB,MSB;//16bit温度值的低字节和高字节

	ack=Get18B20Ack();//执行总线复位,并获取18B20应答
	if(ack==0)
	{
		Write18B20(0xCC);//跳过ROM操作
		Write18B20(0xBE);//发送读命令
		LSB=Read18B20();//读温度值的低字节
		MSB=Read18B20();//读温度值的高字节
		*temp=((int)MSB<<8)+LSB;//合成为16bit整型数
	}
	return ~ack;
}

(3)主程序

sbit IN1=P2^7;
sbit IN2=P2^6;
sbit ENA=P2^5;

bit flag1s=0;//1s定时标志
unsigned char T0RH=0;
unsigned char T0RL=0;

int temp;//读取到的当前温度值
unsigned char len;
int intT,decT;//温度值的整数和小数部分
unsigned char str[12];

void Compare();
void GetTemp();
void ConfigTimer0(unsigned int ms);
unsigned char IntToString(unsigned char *str,int dat);
extern bit Start18B20();
extern bit Get18B20Temp(int *temp);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);

void main()
{
	bit res;

	EA=1;
	ConfigTimer0(10);//T0定时10ms
	Start18B20();//启动DS18B20
	InitLcd1602();//初始化液晶

	while(1)
	{		
		if(flag1s)//每秒更新一次温度
		{
			flag1s=0;
			res=Get18B20Temp(&temp);//读取当前温度
			if(res)//读取成功时,刷新当前温度显示
			{
				GetTemp();
			
				LcdShowStr(0,0,"Welcome to use");//显示字符及温度值
				LcdShowStr(0,1,"Current T:");
				LcdShowStr(10,1,str);
					Compare();
			}
			else //读取失败时,提示错误信息
			{
				LcdShowStr(0,0,"error!");

			}
			Start18B20();//重新启动下一次转换					 
		}
	}
}
/*温度获取函数,获取当前环境温度值并保存在str数组中*/
void GetTemp()
{

	intT=temp>>4;//分离出温度值整数部分
	decT=temp &0x0F;//分离出温度值小数部分
			
	len=IntToString(str,intT);//整数部分转换成字符串
			
	str[len++]='.';
	decT=(decT*10)/16;//二进制的小数部分转换为1位十进制位
	str[len++]=decT+'0';//十进制小数位再转换为ASCII字符
	while(len<6)//用空格补齐到6个字符长度
	{
		str[len++]=' ';
	}
	str[len++]='\0';
}
/*延时函数,用于PWM控制*/
void delay(unsigned int z)
{
	unsigned int x,y;
	for(x=z;x>0;x--)
		for(y=110;y>0;y--);
} 
/*比较函数,通过温度值的比较设置电机的转速*/
void Compare()
{
	unsigned int i=0;
	unsigned char j;

	if((intT>= 24) && (intT<26))   //以两度为一个温差范围,并设温度范围索引
	{
		j=0;	
	}
	else if((intT>=26) &&(intT<28))
	{
		j=1;
	}
	else if((intT>=28) &&(intT<30))
	{
		j=2;
	}
	else if(intT>=30)
	{
		j=3;
	}
	switch(j)		  //根据温度索引设置电机转速
	{
		case 0:	IN1=1;
				IN2=0;
		  		for(i=0;i<200;i++)
	      		{
					ENA=1;
	     			delay(20);
	      		    ENA=0;
					delay(30);
				}
				break;
	
		case 1:	IN1=1;
				IN2=0;
		  		for(i=0;i<200;i++)
	      		{
					ENA=1;
	     			delay(30);
	      		    ENA=0;
					delay(30);
				}
				break;	 
	
		case 2:	IN1=1;
				IN2=0;
		  		for(i=0;i<200;i++)
	      		{
					ENA=1;
	     			delay(55);			 
	      		    ENA=0;
					delay(30);
				}
				break;	 
							
		case 3:	IN1=1;
				IN2=0;
		  	    ENA=1;
				break;

		default:break;	 	 
	}
}  

/*整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度*/
unsigned char IntToString(unsigned char *str,int dat)
{
	signed char i=0;
	unsigned char len=0;
	unsigned char buf[6];

	if(dat<0)//如果为负数,首先取绝对值,并在指针上添加负号
	{
	 	dat=-dat;
		*str++='-';
		len++;
	}
	do{	   //先转换为低位在前的十进制数组
		buf[i++]=dat%10;
		dat /=10;
	}while(dat>0);
	len += i;//i最后的值就是有效字符的个数
	while(i-->0)//将数组值转换为ASCII码反向拷贝到接收指针上
	{
		*str++=buf[i]+'0';
	}
	*str='\0';
	return len;
}
void ConfigTimer0(unsigned int ms)
{
	unsigned long tmp;

	tmp=11059200/12;
	tmp=(tmp*ms)/1000;
	tmp=65536-tmp;
	tmp=tmp+12;
	T0RH=(unsigned char)(tmp>>8);
	T0RL=(unsigned char)tmp;
	TMOD &= 0xF0;
	TMOD |= 0x01;
	TH0=T0RH;
	TL0=T0RL;
	ET0=1;
	TR0=1;
}
void InterruptTimer0() interrupt 1
{
	static unsigned char tmr1s=0;

	TH0=T0RH;
	TL0=T0RL;
	tmr1s++;
	if(tmr1s>=100)
	{
		tmr1s=0;
		flag1s=1;
	}		 

}

源码+电路图 下载:关注公众号,首页回复“温控风扇”获取资料
在这里插入图片描述

  • 78
    点赞
  • 636
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
基于单片机温控风扇的设计 摘 要 温控风扇在现代社会中的生产以及人们的日常生活中都有广泛的应用,如工业生产中大型机械散热系统中的风扇、现在笔记本电脑上的广泛应用的智能CPU风扇等。本文设计了基于单片机温控风扇系统,采用单片机作为控制器,利用温度传感器DS18B20作为温度采集元件,并根据采集到的温度,通过一个达林顿反向驱动器ULN2803驱动风扇电机。根据检测到的温度与系统设定的温度的比较实现风扇电机的自动启动和停止,并能根温度的变化自动改变风扇电机的转速,同时用LED八段数码管显示检测到的温度与设定的温度。 关键词:单片机、DS18B20、温控风扇 第一章 整体方案设计 1.1 前 言 在现代社会中,风扇被广泛的应用,发挥着举足轻重的作用,如夏天人们用的散热风扇、工业生产中大型机械中的散热风扇以及现在笔记本电脑上广泛使用的智能CPU风扇等。而随着温度控制技术的发展,为了降低风扇运转时的噪音以及节省能源等,温控风扇越来越受到重视并被广泛的应用。在现阶段,温控风扇的设计已经有了一定的成效,可以使风扇根据环境温度的变化进行自动无级调速,当温度升高到一定时能自动启动风扇,当温度降到一定时能自动停止风扇的转动,实现智能控制。 随着单片机在各个领域的广泛应用,许多用单片机作控制的温度控制系统也应运而生,如基于单片机温控风扇系统。它使风扇根据环境温度的变化实现自动启停,使风扇转速随着环境温度的变化而变化,实现了风扇智能控制。它的设计为现代社会人们的生活以及生产带来了诸多便利,在提高人们的生活质量、生产效率的同时还能节省风扇运转所需的能量。 本文设计了由ATMEL公司的8052系列单片机AT89C52作为控制器,采用DALLAS公司的温度传感器DS18B20作为温度采集元件,并通过一个达林顿反向驱动器ULN2803驱动风扇电机的转动。同时使系统检测到得环境温度以及系统预设的温度动态的显示在LED数码管上。根据系统检测到得环境温度与系统预设温度的比较,实现风扇电机的自动启停以及转速的自动调节。 1.2 系统整体设计 本设计的整体思路是:利用温度传感器DS18B20检测环境温度并直接输出数字温度信号给单片机AT89C52进行处理,在LED数码管上显示当前环境温度值以及预设温度值。其中预设温度值只能为整数形式,检测到的当前环境温度可精确到小数点后一位。同时采用PWM脉宽调制方式来改变直流风扇电机的转速。并通过两个按键改变预设温度值,一个提高预设温度,另一个降低预设温度值。系统结构框图如下: 结 论 本次设计的系统以单片机为控制核心,以温度传感器DS18B20检测环境温度,实现了根据环境温度变化调节不同的风扇电机转速,在一定范围能能实现转速的连续调节,LED数码管能连续稳定的显示环境温度和设置温度,并能通过两个独立按键调节不同的设置温度,从而改变环境温度与设置温度的差值,进而改变电机转速。实现了基于单片机温控风扇的设计。 本系统设计可推广到各种电动机的控制系统中,实现电动机的转速调节。在生产生活中,本系统可用于简单的日常风扇智能控制,为生活带来便利;在工业生产中,可以改变不同的输入信号,实现对不同信号输入控制电机的转速,进而实现生产自动化,如在电力系统中可以根据不同的负荷达到不同的电压信号,再由电压信号调节不同的发电机转速,进而调节发电量,实现电力系统的自动化调节。综上所述,该系统的设计和研究在社会生产和生活中具有重要地位。 附录2:程序代码 #include <reg52.h> #define uchar unsigned char #define uint unsigned int sbit DQ=P1^7; sbit key1=P1^3; sbit key2=P1^4; sbit dianji=P3^1; float ff; uint y3; uchar shi,ge,xiaoshu,sheding=20,gaonum,dinum; uchar code dispcode[]={ //段码 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; uchar code tablel[]={ //带小数点的段码 0xbf,0x86,0xdb,0xcf, 0xe6,0xed,0xfd, 0x87,0xff,0xef}; uchar dispbitcode[]={ //位选 0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f}; uchar dispbuf[8]={0,0,0,0,0,0,0,0}; void Delay(uint num)// 延时函数 { while( --num ); } void digitalshow(uchar a4,uchar a3,uchar a2,uchar a1,uchar a0) { dispbuf[0]=a0; dispbuf[1]=a1; dispbuf[2]=a2; dispbuf[3]=a3; dispbuf[4]=a4; P2=0xff; P0=dispcode[dispbuf[0]]; P2=dispbitcode[5]; Delay(1);
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值