小伙伴们家里是不是还是手动按键式电扇?是的话就跟我改起来,改过之后手动按键不影响,还是可以用哟,增加红外遥控功能,定时增加到8小时(你的是不是还只有1小时定时呀,呵呵!),还有哟!再加个睡眠功能:如果打开睡眠功能,定时时间到之后自动跳到1档,不然下半夜冻坏罗,不打开睡眠功能,定时时间到之后自动关闭。是不是很贴心啦!本来还想加个仿自然风,就是扇一会停一会再扇一会…………,网友们都说那样太伤电机,于是取消了。废话少说,上图:
二档走起,中间小灯为电源指示灯,左边有三个小灯,为风量档位指示灯,一档亮一个,二档亮两个,三档亮三个。手动按键的话也一样,会亮指示灯,手动过后再用遥控也是可以的。不按机械按键直接遥控也是可以的,遥控后再按钮也是可以的,如果没按机械按键直接遥控打开的,此时想要按机械按键关闭要先按三档中任一键再按0键关闭。
定时设置状态,数码管亮起,右边一个数码管为小写h,左边一个数码管表示1到8小时设置。
已经确定为6小时,后面的h变为大写的H,100秒之前为剩余小时显示,之后为剩余分钟的倒计时
看到定时数码管下面的小灯了吧,那是睡眠指示小灯,表示打开了睡眠模式。
三个并排的键依次为1档、2档、3档,上翻键下翻键为档位的加减,档位加到三档时上翻不再增加,档位减到1档时,再减就关闭了。
OK为关闭。
V-为定时设置键,定时设置状态时,上翻下翻键为定时时间的加减,OK键为确认。
右翻键为睡眠模式开关切换键。V+是管我们家电灯的啦~~
看看我的万能板
电源部分直接用的旧手机充电器,
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- /******************************************************************
- /* 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黑下载附件…………
复制代码 接下来是重点
所有资料51hei提供下载:
遥控风扇程序.rar
(122.38 KB, 下载次数: 359)
风扇电路仿真图.rar
(42.08 KB, 下载次数: 264)
|