基于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;
	}		 

}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章