目录
一、设计背景
在当今这个科技日新月异的时代,家电产品正以前所未有的速度向智能化、自动化迈进,旨在为用户带来更加便捷、舒适的生活体验。电风扇,作为夏季不可或缺的家用电器,其传统功能已逐渐显得力不从心,尤其是在面对用户对于精准温控、节能高效以及操作便捷性的更高要求时。因此,开发一款基于51单片机的智能风扇控制系统,成为了家电行业创新发展的重要方向。
传统电风扇主要通过机械换挡或人工设定档位来调节风速,这种方式不仅风速变化不连续,难以精确满足用户的舒适度需求,还容易造成能源浪费。基于51单片机的智能风扇控制系统不仅提升了风扇的智能化水平,还实现了节能环保和安全可靠的目标。通过自动控制风扇,系统能够在保证散热效果的同时降低能耗,减少能源浪费。
总之,基于51单片机的智能风扇控制系统是家电行业智能化发展的一个重要成果。它不仅解决了传统风扇存在的诸多问题,还为用户带来了更加舒适、便捷、节能的使用体验。随着科技的不断进步和人们生活水平的持续提高,相信这种智能风扇控制系统将在未来的家电市场中占据更加重要的地位,为人们的生活带来更多便利和舒适。
二、实现功能
本设计以51单片机为控制核心,设计一种智能风扇控制系统。整个系统包括MCU、晶振电路、时钟电路、DS18B20测温电路、风扇控制电路、风速测量电路以及OLED显示电路。可具体实现以下功能:
(1)本设计通过检测外部环境的风速和温度来控制电风扇运不运行。
(2)当风速较低(低于20km/h)或者是温度较高(高于35度)时电风扇转动,否则电风扇不转动。
三、仿真演示
完整仿真图如下:
采用VSPD虚拟串口软件和XCOM串口调试助手,模拟风速传感器,默认风速传感器传来三个字节的数据,0xbb为帧头,0x10为第一路风速测量值,0x06为第二路风速测量值,本次仿真仅用到第二路,因此通过改变第二路的值来模拟风速的变化。当第二路值为0x06时,风速为6km/h,此时温度为32度,由于风速低于风速阈值20km/h,风扇转动。
当第二路值为0x10时,风速为16km/h时,此时温度为32度,由于风速低于风速阈值20km/h,风扇转动。
当第二路值为0x16时,风速为22km/h时,此时温度为32度,风扇不转动。
当温度为36度,风速为22km/h时,此时温度超过温度阈值35度,风扇转动。
当温度为38度,风速为22km/h时,此时温度超过温度阈值35度,风扇转动。
四、源程序(部分)
main.c文件
#include "oled.h"
#define uchar unsigned char
#define uint unsigned int //宏定义
uchar dat[3]; //接收缓存
sbit Fan=P1^0;//风扇继电器控制接口
sbit DQ=P1^4;//温度传感器接口
uint wen_du; //温度变量
uint shang,xia; //对比温度暂存变量
uchar j=0,js=0,m=0;
uchar RecFlag=0; //接收标志位
/***********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 wery important
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
delay_18B20(100);
a=ReadOneChar(); //读取温度值低位
b=ReadOneChar(); //读取温度值高位
wen_du=((b*256+a)>>4); //当前采集温度值除16得实际温度值
}
void Timer0init() //定时器初始化函数
{
TMOD=0x01; //定时器0工作方式1
TH0=0xf8;
TL0=0x30; //定时器初值5ms
ET0=1; //打开定时器0中断允许
TR0=1; //打开定时器0定时器开关
EA=1; //打开中断系统总开关
}
void uart_init()
{
TMOD=0x21; //定时器1工作于方式2,八位自动重装
TR1=1;
TH1=0xfd;
TL1=0xfd; //波特率9600
SCON=0x50; //串口工作于方式1,10位uart
ES=1;
EA=1; //开串口中断,总中断,串口中断优先
}
unsigned int i=0;
void main() //主函数
{
for(j=0;j<80;j++) //先读取温度值,防止开机显示85
ReadTemperature();
Timer0init();
OLED_Init(); //OLED初始化
OLED_Clear(); //清屏,下同
uart_init();
while(1) //进入while循环
{
if(js>=200) //当js在定时器里加到50次时(js加一次是20ms,加到50次就是1000ms,也就是1秒读取一次温度)
{
ReadTemperature(); //读取温度值
EA=0;SBUF=0xaa;while(!TI);TI=0;EA=1;
OLED_ShowString(3,0,"Wind Rate:",10);
OLED_ShowNum(95,0,dat[2],3,12);//显示脉搏数据
OLED_ShowString(3,2,"Temp Data:",10);//第二行显示存储数据
OLED_ShowNum(95,2,wen_du,3,12);
if((wen_du>35)||(dat[2]<20))
{
Fan=0;
}
else
{
Fan=1;
}
}
}
}
void T0_TIME() interrupt 1 //定时器工作函数,用于PWM工作
{
TH0=0xf8;
TL0=0x30; //定时器赋初值5ms
m++; //5ms,m加一
if(js<200) js++;
}
void uart_interrupt()interrupt 4
{
if(RecFlag==0)
{
while(!RI);RI=0;dat[0]=SBUF;//接收头字节
if(dat[0]==0xbb)
{
RecFlag=1;
}
}
else if(RecFlag==1)
{
while(!RI);RI=0;dat[1]=SBUF;//接收头字节
RecFlag=2;
}
else
{
while(!RI);RI=0;dat[2]=SBUF; //2#风速值
RecFlag=0;
}
}
oled.c文件
#include "oled.h"
#include "oledfont.h"
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
/**********************************************
//IIC Start
**********************************************/
void IIC_Start()
{
OLED_SCLK_Set() ;
OLED_SDIN_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop()
{
OLED_SCLK_Set() ;
//OLED_SCLK_Clr();
OLED_SDIN_Clr();
OLED_SDIN_Set();
}
void IIC_Wait_Ack()
{
OLED_SCLK_Set() ;
OLED_SCLK_Clr();
}
/**********************************************
// IIC Write byte
**********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
unsigned char m,da;
da=IIC_Byte;
OLED_SCLK_Clr();
for(i=0;i<8;i++)
{
m=da;
// OLED_SCLK_Clr();
m=m&0x80;
if(m==0x80){OLED_SDIN_Set();}
else OLED_SDIN_Clr();
da=da<<1;
OLED_SCLK_Set();
OLED_SCLK_Clr();
}
}
/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
IIC_Start();
Write_IIC_Byte(0x78); //Slave address,SA0=0
IIC_Wait_Ack();
Write_IIC_Byte(0x00); //write command
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
IIC_Start();
Write_IIC_Byte(0x78); //D/C#=0; R/W#=0
IIC_Wait_Ack();
Write_IIC_Byte(0x40); //write data
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
if(cmd) {Write_IIC_Data(dat);}
else {Write_IIC_Command(dat);}
}
//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1){x=0;y=y+2;}
if(Char_Size ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else
{
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
unsigned char j=0;
while (chr[j]!='\0')
{ OLED_ShowChar(x,y,chr[j],Char_Size);
x+=8;
if(x>120){x=0;y+=2;}
j++;
}
}
//初始化SSD1306
void OLED_Init(void)
{
OLED_WR_Byte(0xAE,OLED_CMD);//--display off
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
OLED_WR_Byte(0x81,OLED_CMD); // contract control
OLED_WR_Byte(0xFF,OLED_CMD);//--128
OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
OLED_WR_Byte(0x00,OLED_CMD);//
OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
OLED_WR_Byte(0x80,OLED_CMD);//
OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
OLED_WR_Byte(0x05,OLED_CMD);//
OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
OLED_WR_Byte(0xF1,OLED_CMD);//
OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
OLED_WR_Byte(0x12,OLED_CMD);//
OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
OLED_WR_Byte(0x30,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
OLED_WR_Byte(0x14,OLED_CMD);//
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}
仿真源文件及源程序百度网盘链接:https://pan.baidu.com/s/1i3V_uHmDF2ODFe9VvU2dzw?pwd=b1r6
提取码: b1r6