玩具上的废旧电机千万别扔,做个单片机控制的智能风扇吧
在中国从北到南都逃脱不了炎热的夏天,天气那么热做一个空调也不太现实,我们何不动手制作一个风扇呢?家里都会一下玩具上的废旧电机,扔掉又太可惜了,直接把电机连在电源两端不能调速又太无聊了,我们何不DIY一个单片机控制的智能风扇,今天给大家展示一下之前做的一个智能风扇,感兴趣的网友可以参考一下。
先来给大家一个制作成功图片
智能风扇
我们所选用的单片机为STC生产的51系列的芯片,初次之外还有一些其它材料像废旧电机、1602显示屏、电机驱动芯片、按键和洞洞板等,对于经常搞单片机diy的网友来说,这些材料都是搞小制作的必需品。
先来介绍一下我们所要制作的智能风扇的功能
1602显示屏
1602显示屏是我们必需品,在这上面我们可以实时读出外界温度以及智能风扇工作状态,显示屏上显示OFF表示风扇不开启,左下角显示智能风扇开启温度,中间显示外界环境的温度,智能风扇分为三个档,温度越高转速越快,大家可以参考一下,如果有技术远远可以扩展的功能很强大。
这个图片显示的风扇开启的状态,除了具有风扇由温度控制开启以外,还可以由使用者强制开启,无论外界温度是多少度都可以开启,但是只能开启最快的档位,在显示屏上我们也可以看到开启的档位为三挡,但是外界温度是很低,这个是我在冬天测试的时候实拍的图片。
我们制作 这个智能风扇尽可能的体现它的价值,如果你想送人的话,特别是自己的女友(通过关注我的粉丝比例来看,喜欢单片机的男生占99.9%)我们可以在显示屏上显示一些你想说的话,就像上图显示的内容,当然这个不是固定的,想显示什么完全是由你自己决定。
正常工作状态
除了显示屏之外我还加了四个按键,左面两个是调节智能风扇的启动温度,启动温度就是指显示屏左下角显示的那个数字,现在是26度我们可以通过左面两个按键进行启动温度的增减,第三个按键就是你想对女神或女友说的话,至于显示什么,得看你想说什么了,第四个按键就是智能风扇强制启动按键,按下之后无论智能风扇处于哪种状态,都能强制启动。
个人觉得还是挺好玩的,现在天气很热,非常具有使用价值,我们可以在有空的时候制作一个,由于文章中不能添加代码,所以想直接要代码的朋友只能说声抱歉了,制作起来不是很难,自己动手完全可以的。
小创意:用单片机给老风扇增加红外遥控、定时及睡眠功能
小伙伴们家里是不是还是手动按键式电扇?是的话就跟我改起来,改过之后手动按键不影响,还是可以用哟,增加红外遥控功能,定时增加到8小时(你的是不是还只有1小时定时呀,呵呵!),还有哟!再加个睡眠功能:如果打开睡眠功能,定时时间到之后自动跳到1档,不然下半夜冻坏罗,不打开睡眠功能,定时时间到之后自动关闭。是不是很贴心啦!本来还想加个仿自然风,就是扇一会停一会再扇一会…………,网友们都说那样太伤电机,于是取消了。废话少说,直接上图:
二档走起,中间小灯为电源指示灯,左边有三个小灯,为风量档位指示灯,一档亮一个,二档亮两个,三档亮三个。手动按键的话也一样,会亮指示灯,手动过后再用遥控也是可以的。不按机械按键直接遥控也是可以的,遥控后再按钮也是可以的,如果没按机械按键直接遥控打开的,此时想要按机械按键关闭要先按三档中任一键再按0键关闭。
定时设置状态,数码管亮起,右边一个数码管为小写h,左边一个数码管表示1到8小时设置。
已经确定为6小时,后面的h变为大写的H,100秒之前为剩余小时显示,之后为剩余分钟的倒计时
看到定时数码管下面的小灯了吧,那是睡眠指示灯,表示打开了睡眠模式。
遥控器是这个样子滴
三个并排的键依次为1档、2档、3档,上翻键下翻键为档位的加减,档位加到三档时上翻不再增加,档位减到1档时,再减就关闭了。
OK为关闭。
V-为定时设置键,定时设置状态时,上翻下翻键为定时时间的加减,OK键为确认。
右翻键为睡眠模式开关切换键。V+是管我们家电灯的啦~~
最后给大家看一下我调试的功能板:
电源部分直接用的是旧手机充电器,为了达到更好的效果我特意做了仿真文件如下:
部分参考源代码如下:功能说明
/******************************************************************
/* STC89C52单片机 *
/* 11.0592M晶振 *
/*程序用了外部中断0接收红外信号,IO口为P32 *
/*遥控OK键为关闭,在定时设置状态时为确认 *
/*遥控上、下翻键为档位加、减,在设置定时状态时为定时时间加、减, *
/*遥控V-键为进入设置定时模式 *
/*右翻键为睡眠模式的开启与关闭,睡眠模式指定时时间到后自动切为1档 *
/*遥控返回键为1档,遥控主页键为2档,遥控菜单键为3档, *
/*定时设置状态时,第二个数码管为小写H,设置完成后为大写H. *
/*最多定时8小时,99分钟内显示分钟倒计时 *
/******************************************************************/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
#define const_key_time1 20 //按键去抖延时的时间
#define const_1s 440 //大概1秒钟所需要的中断数
void delay_long(unsigned int uiDelaylong);
void delay(uchar x); //x*0.14MS
void delay1(int ms);
void T0_time(); //定时器0中断函数
void key_service(); //按键服务的应用程序
void key_scan(); //按键扫描函数,放在定时中断里
void key_service1(); //关闭的应用程序
void initial_myself(); //初始化单片机
void initial_peripheral();//初始化外围
void LCD_XSservice(); //数码管显示程序
void display_drive(); //数码管字模驱动函数
sfr ISP_CONTR=0xe7; //软复位地址
sbit IRIN = P3^2; //红外接收器数据线,外部中断0
sbit K1 = P2^0; //按键1
sbit K2 = P2^1; //按键2
sbit K3 = P2^2; //按键3
//风量1档最小,3档最大
sbit SC1 = P2^3; //1档输出,控制PNP三极管,三极管再控制BT136双向可控硅
sbit SC2 = P2^4; //2档输出,控制PNP三极管,三极管再控制BT136双向可控硅
sbit SC3 = P2^5; //3档输出,控制PNP三极管,三极管再控制BT136双向可控硅
sbit LED1 = P1^0; //档位指示小灯1
sbit LED2 = P1^1; //档位指示小灯2
sbit LED3 = P1^2; //档位指示小灯3
sbit LED4 = P1^3; //睡眠模式指示小灯
sbit LCD1 = P2^6; //接PNP三极管控制定时显示数码管1的阳极(显示数码管为共阳管)
sbit LCD2 = P2^7; //接PNP三极管控制定时显示数码管2的阳极(显示数码管为共阳管)
//定时显示数码管的八个阴极接P0
uchar IRCOM[7]; //定义红外接收数组
uchar code Tab0[]= //定义数码管数组,没有小数点
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x89
};//0,1,2,3,4,5,6,7,8,9,h
uint code Dingshi0[]= //定义定时数组
{0,60,120,180,240,300,360,420,480
};
unsigned char ly_dis1;//定义显示缓冲区
unsigned char ly_dis2;//定义显示缓冲区
unsigned char ucKeySec=0; //被触发的按键编号
unsigned int uiKeyTimeCnt1=0; //按键1去抖延时计数器
unsigned char ucKeyLock1=0; //按键1触发后自锁的变量标志
unsigned int uiKeyTimeCnt2=0; //按键2去抖延时计数器
unsigned char ucKeyLock2=0; //按键2触发后自锁的变量标志
unsigned int uiKeyTimeCnt3=0; //按键3去抖延时计数器
unsigned char ucKeyLock3=0; //按键3触发后自锁的变量标志
unsigned char anjiank=0; //有按键被触发
unsigned char hw_anjiank=0; //红外按键被触发
unsigned char LCDSec=0; //定时设置状态
unsigned char LCDszxs=0; //数码管定时的变量
unsigned int DSSJ=0; //定时的时间
unsigned char DSBZ=0; //定时标志
unsigned char iii=0; //动态数码管定时显示变量
unsigned char posit=0;//动态数码管扫描步骤
unsigned int uiTimeCnt=0; //倒计时的时间计数器
unsigned int js1m=0;//计时秒
unsigned char Guanbi=0; //关闭标志
unsigned char SMMS=0; //睡眠模式标志
unsigned char SMMSJK=0; //睡眠模式监控
/*******************************************************************/
main()
{
initial_myself(); //初始化
delay_long(100);
initial_peripheral();//初始化外围
while(1)
{
key_service1(); //关闭的应用程序
key_service();//按键服务的应用程序
LCD_XSservice(); //数码管显示程序
}
}
//end main
/**********************************************************/
void LCD_XSservice() //数码管显示程序
{
if (DSBZ==1)
{
if (DSSJ>60)
{
if (DSSJ>99) {iii=2;}
if (DSSJ>120) {iii=3;}
if (DSSJ>180) {iii=4;}
if (DSSJ>240) {iii=5;}
if (DSSJ>300) {iii=6;}
if (DSSJ>360) {iii=7;}
if (DSSJ>420) {iii=8;}
ly_dis1=iii;//P0口驱动数码管2到8的定时显示
ly_dis2=10; //显示个位值
}
if (DSSJ<=99)
{
if (DSSJ>0)
{
ly_dis1=DSSJ/10; //显示十位值
ly_dis2=DSSJ%10; //显示个位值
}
}
if (DSSJ==0)
{
if (SMMS==1)
{
LCD1=1;
LCD2=1;
DSBZ=0;
LED4=1;
SMMSJK=0;
hw_anjiank=1; //表明由红外按键触发
ucKeySec=1;//触发1档按键
}
if (SMMS==0)
{
if (DSBZ==1)
{
ISP_CONTR=0x20; //关闭所有,所有变量清零,软复位
}
}
}
}
}
/**********************************************************/
void key_scan()//按键扫描函数,放在定时中断里
{
if (LCDSec!=1)
{
if(K1==1)//IO口是高电平,说明按键1一直没有按下,这时要及时清零一些标志位
{
ucKeyLock1=0; //按键自锁标志清零
uiKeyTimeCnt1=0;//按键去抖延时计数器清零
}
else if(ucKeyLock1==0)//有按键按下,且是第一次按下
{
uiKeyTimeCnt1++; //累计定时中断次数
if(uiKeyTimeCnt1>const_key_time1)
{
uiKeyTimeCnt1=0;
ucKeyLock1=1; //自锁按键置位,避免一直触发
hw_anjiank=0; //表明解除由红外按键触发
anjiank=1; //表明由按键触发
ucKeySec=1; //触发1档按键
}
}
if(K2==1)//IO口是高电平,说明按键2一直没有按下,这时要及时清零一些标志位
{
ucKeyLock2=0; //按键自锁标志清零
uiKeyTimeCnt2=0;//按键去抖延时计数器清零
}
else if(ucKeyLock2==0)//有按键按下,且是第一次按下
{
uiKeyTimeCnt2++; //累计定时中断次数
if(uiKeyTimeCnt2>const_key_time1)
{
uiKeyTimeCnt2=0;
ucKeyLock2=1; //自锁按键置位,避免一直触发
hw_anjiank=0; //表明解除由红外按键触发
anjiank=1; //表明由按键触发
ucKeySec=2; //触发2档按键
}
}
if(K3==1)//IO口是高电平,说明按键3一直没有按下,这时要及时清零一些标志位
{
ucKeyLock3=0; //按键自锁标志清零
uiKeyTimeCnt3=0;//按键去抖延时计数器清零
}
else if(ucKeyLock3==0)//有按键按下,且是第一次按下
{
uiKeyTimeCnt3++; //累计定时中断次数
if(uiKeyTimeCnt3>const_key_time1)
{
uiKeyTimeCnt3=0;
ucKeyLock3=1; //自锁按键置位,避免一直触发
hw_anjiank=0; //表明解除由红外按键触发
anjiank=1; //表明由按键触发
ucKeySec=3; //触发3档按键
}
}
}
}
/**********************************************************/
void key_service1() //关闭的应用程序
{
if(anjiank==1) //判断按键是否有按下,如果按键触发,但三个按键都为高电平,那么表示按了按键关按键
{
if(K1&K2&K3==1)
{
ISP_CONTR=0x20; //关闭所有,所有变量清零,软复位
}
}
if(hw_anjiank==1)//判断红外关按键是否按下
{
if(Guanbi==1) //关闭标志
{
//关闭所有,所有变量清零,软位
initial_myself(); //初始化
delay_long(100);
initial_peripheral();//初始化外围
Guanbi=0; //关闭标志清零
}
}
}
/**********************************************************/
void key_service() //按键服务的应用程序
{
switch(ucKeySec) //按键的切换
{
case 1: //按键1--1档
LED1 = 1;
LED2 = 1;
LED3 = 1;
LED1 = 0;
SC2 = 1;
SC3 = 1;
delay(300);
if (SC2&SC3)
{
SC1 = 0;
}
ucKeySec=0; //响应按键服务处理程序后,按键编号清零,避免一直触发
break;
case 2: //按键2--2档
LED1 = 1;
LED2 = 1;
LED3 = 1;
LED1 = 0;
LED2 = 0;
SC1 = 1;
SC3 = 1;
delay(300);
if (SC1&SC3)
{
SC2 = 0;
}
ucKeySec=0; //响应按键服务处理程序后,按键编号清零,避免一直触发
break;
case 3: //按键3--3档
LED1 = 1;
LED2 = 1;
LED3 = 1;
LED1 = 0;
LED2 = 0;
LED3 = 0;
SC1 = 1;
SC2 = 1;
delay(300);
if (SC1&SC2)
{
SC3 = 0;
}
ucKeySec=0; //响应按键服务处理程序后,按键编号清零,避免一直触发
break;
case 4: //OK按键短按
ucKeySec=0; //响应按键服务处理程序后,按键编号清零,避免一直触发
break;
}
}
/**********************************************************/
void IR_IN() interrupt 0 //using 0 接收红外信号
{
unsigned char j,k,N=0;
EX0 = 0;
delay(15);
if (IRIN==1)
{ EX0 =1;
return;
}
//确认IR信号出现
while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
{delay(1);}
for (j=0;j<4;j++) //收集四组数据
{
for (k=0;k<8;k++) //每组数据有8位
{
while (IRIN) //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
{delay(1);}
while (!IRIN) //等 IR 变为高电平
{delay(1);}
while (IRIN) //计算IR高电平时长
{
delay(1);
N++;
if (N>=30)
{ EX0=1;
return;} //0.14ms计数过长自动离开。
} //高电平计数完毕
IRCOM[j]=IRCOM[j] >> 1; //数据最高位补“0”
if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;} //数据最高位补“1”
N=0;
}//end for k
}//end for j
if (IRCOM[2]!=~IRCOM[3])
{ EX0=1;
return; }
if (LCDSec!=1)
{
if (IRCOM[2]==0xC5)//返回键 这一步就是判断,如果对应按键,则执行下面动作!
{
anjiank=0; //表明解除由按键触发
hw_anjiank=1; //表明由红外按键触发
ucKeySec=1;//触发1档按键
}
if (IRCOM[2]==0x88)// 主页键 这一步就是判断,如果对应按键,则执行下面动作!
{
anjiank=0; //表明解除由按键触发
hw_anjiank=1; //表明由红外按键触发
ucKeySec=2;//触发2档按键
}
if (IRCOM[2]==0x82)//菜单键 这一步就是判断,如果对应按键,则执行下面动作!
{
anjiank=0; //表明解除由按键触发
hw_anjiank=1; //表明由红外按键触发
ucKeySec=3;//触发3档按键
}
}
if (IRCOM[2]==0xCA)//上翻键,这一步就是判断,如果对应按键,则执行下面动作!
{
if (LCDSec==1)//如果在时间设置状态,就是设置时间的加
{
LCDszxs++;
if (LCDszxs>8)
{
LCDszxs=0;
}
}
else //除了时间设置状态,为风量档位加
{
if (SC1&SC2&SC3)
{
ucKeySec=1;
}
if (SC1==0)
{
ucKeySec=2;
}
if (SC2==0)
{
ucKeySec=3;
}
anjiank=0; //表明解除由按键触发
hw_anjiank=1; //表明由红外按键触发
}
}
if (IRCOM[2]==0xD2)//下翻键,这一步就是判断,如果对应按键,则执行下面动作!
{
if (LCDSec==1)//如果在时间设置状态,就是设置时间的减
{
if (LCDszxs>0)
{
LCDszxs--;
}
if (LCDszxs==0)
{
LCDszxs=8;
}
}
else //除了时间设置状态,为风量档位减
{
if (SC1==0)
{
Guanbi=1; //关闭标志打开
}
if (SC2==0)
{
ucKeySec=1;
}
if (SC3==0)
{
ucKeySec=2;
}
anjiank=0; //表明解除由按键触发
hw_anjiank=1; //表明由红外按键触发
}
}
if (IRCOM[2]==0x81)// V-键 这一步就是判断,如果对应按键,则执行下面动作!定时设置
{
if ((SC1&SC2&SC3)==0)
{
LCDSec=1; //定时设置状态,数码管闪动
LCDszxs=0; //数码管定时的变量
LCD1=0;
LCD2=0;
}
}
if (IRCOM[2]==0xce)//OK键 这一步就是判断,如果对应按键,则执行下面动作!确认并退出定时设置
{
if (LCDSec==1)
{
if (LCDszxs>0)
{
DSSJ=Dingshi0[LCDszxs];
DSBZ=1;
LCDSec=0;
SMMSJK=0;
}
else
{
LCD1=0;
LCD2=0;
LCDSec=0;
}
}
else
{
initial_myself(); //初始化
delay_long(100);
initial_peripheral();//初始化外围
Guanbi=0; //关闭标志清零
}
}
if (IRCOM[2]==0xC1)//右翻键,这一步就是判断,如果对应按键,则执行下面动作!
{
if ((SC1&SC2&SC3)==0)
{
if (LCDSec==0)
{
LED4=!LED4; //LED4取反
if (LED4==0)
{
SMMS=1;
if (DSBZ==0)
{
if(SMMSJK==0)
{
LCD1=0;
LCD2=0;
LCDszxs=3;
DSSJ=Dingshi0[LCDszxs];
DSBZ=1;
SMMSJK=1;
}
}
}
if (LED4==1)
{
SMMS=0;
if (DSBZ==1)
{
if(SMMSJK==1)
{
LCD1=1;
LCD2=1;
DSBZ=0;
LCDszxs=0;
DSSJ=Dingshi0[LCDszxs];
SMMSJK=0;
}
}
}
}
}
}
- EX0 = 1;
}
/**********************************************************/
void display_drive() //数码管字模驱动函数
{
if (DSBZ|LCDSec)
{
switch(posit)
{
case 1:
LCD1=0;
LCD2=1;
if (LCDSec==1)
{
P0=Tab0[LCDszxs];//P0口驱动数码管0到8的定时显示
}
else
{
P0=Tab0[ly_dis1];//P0口驱动数码管1到8的定时显示
}
break;
case 2:
LCD1=1;
LCD2=0;
if (LCDSec==1)
{
P0=0X8b;//显示H
}
else
{
P0=Tab0[ly_dis2];//P0口驱动数码管1到8的定时显示
}
break;
}
posit++;
if(posit>2)
{
posit=1;
}
}
else
{
LCD1=1;
LCD2=1;
}
}
/**********************************************************/
void T0_time() interrupt 1 //定时器0函数
{
TF0=0; //清除中断标志
TR0=0; //关中断
key_scan(); //按键扫描函数
- if(DSBZ==1) //启动定时倒计时计数器
{
uiTimeCnt++;
if(uiTimeCnt>=const_1s) //1秒时间到
{
js1m++;
if (js1m==210)
{
if(DSSJ!=0) //防止倒计时到0秒
{
DSSJ--; //倒计时直减1
}
js1m=0;
}
uiTimeCnt=0; //计时器清零,准备重新开始
}
}
display_drive(); //数码管字模驱动函数
TH0=0xfe; //重装初始值(65535-500)=635035=0xfe0b
TL0=0x0b;
TR0=1; //开中断
}
/*******************************************************/
void initial_myself() //初始化单片机
{
//I/O口初始化
IRIN=1; //红外接收器数据线,外部中断0
K1 = 1; //按键1
K2 = 1; //按键2
K3 = 1; //按键3
SC1 = 1; //1档输出
SC2 = 1; //2档输出
SC3 = 1; //3档输出
LED4 = 1; //仿自然风指示小灯
……………………
鉴于篇幅限制,只能写部分代码,通过仿真和实践完美实现了所需要的远程遥控定时和睡眠功能,小伙伴们如果感兴趣你们也试一下吧,如果硬件方面有困难也可以直接用开发板哦!
最后,如果有什么意见或者建议欢迎您留言给我,让我们共同学习一起进步,如果需要 完整代码或设计文件,请在下方留言或者私信我,看到后会第一时间回复。
谢谢!
如果喜欢我的文章请评论转发加关注哦。
相关问答
51 单片机 通过继电器如何控制220v 风扇 电机?单片机输出高电平,或低电平都不足以驱动继电器,必须再加个三极管,三极管的集电极经继电器线圈接电源,当三极管导通时,继电器吸合,利用继电器的常开点使风扇...
电 风扇 的晶振是什么样的?电风扇电路中没有晶振。普通电风扇电路中不含电子零件,仅由电机、启动电容、开关、定时器组成,没有复杂的电子电路,不需要晶振。即使是含电子控制电路的电风...
led 风扇 成像原理原理是风扇叶片上有一排发光二极管,当它们高速旋转并闪光时,由于视觉暂留的原因,我们看到的是一段一段的弧形线段。如果使用单片机控制二极管闪光的时序和时间...
如何用 单片机 控制220V交流电的通断,不用继电器?朋友们好,我是电子及工控技术,我来回答这个问题。用单片机控制强电它的方法还是比较多的,我们在平时生活中的电器中都可以随处可见,比如有的电风扇控制就是用...
S8050三极管控制电路, 风扇 转动?基极通过限流电阻接单片机io口,然后集电极接数码管,发射极接地。当相应io输出0的时候,集电极和发射极导通,此时集电极也送出0。.基极通过限流电阻接单片机io...
科技小制作小发明之 电风扇 怎么做 - 学点总对 的回答 - 懂得看你想做什么规模的了,如果只是简单的匀速的风速,可以直接弄个小电机,再在上面加一个风扇页子就行了。如果想要比较好一点的,可以弄一个步进电机,通...
pwm调速 风扇 怎么调转速 单片机 ?PWM调速风扇的转速是由单片机程序控制的,通过控制PWM信号的占空比来改变电动机输入电压的大小,进而达到调速的目的。具体实现方法是,将PWM信号引脚与风扇驱动...
笔记本 风扇 这四根线分别是什么含义?一根是地,二根是供电,另外两根一根是温控,一根是转速感应。将那两根供电的线分别接在正负极上风扇就可以转了,另外两根是需要主板支持的。以往的风扇都是3p...
显字 风扇 的工作原理是怎样的?_住范儿家装官网这种东西一般有几片叶子,叶子上面都是LED,然后根据叶片的旋转速度,根据机械机械位原理进行逐行扫描编制程序!这产品不知道是多少年前的产品了,风扇...
风扇 电机如何接线使其实现正反转?把链接启动电容的那个启动绕组接线对调!就可以实现了固态继电器控制是可以的!你会单片机吗!搞一个程序接触开关人工和自动两种方式人工的就是触发...