找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1515|回复: 12
打印 上一主题 下一主题
收起左侧

用51单片机改装电风扇遥控系统

  [复制链接]
跳转到指定楼层
楼主
       自家用多丽牌落地风扇,型号是FS11-40,最近出现故障,无规律自动开机、关机,无规律自变档位。特别是晚上睡觉后自动开机,很是烦恼。上网查询打算网购一块电脑板,但均找不到匹配的。家里正好有一些单片机配件,决定自己改装及维修。       第一步:拆机。
       观察电路板上单片机芯片,型号为“KEJIE-38/S8EC_94H4”,DIP20封装,测单片机供电只有4.5V,怀疑供电不足,在断开220V交流电的情况下,用直流5V直接供电,故障依然无规律出现,所以基本判断芯片内部损坏,决定自己改装。
       第二步:改装准备。
       1.遥控器的匹配,在单片机开发板上测试原机遥控器,无响应,读不出键值。试了家里海信电视的遥控器,能读出键值,最下面四个按键键值分别为“62、64、63、65”,这四个按键电视机用不上,所以决定用作风扇的控制,功能分别定为“关机、开机/风速、摇头、定时”。
         
      2.功能增减:
      风扇原遥控器有“风类”调节功能,由单片机“定时器+PWM”控制电机模拟各种风类,由于这个功能平时不常用,所以删减了这个功能。
      家人经常有出门不关风扇的情况发生,决定增加无条件定时关机功能,定时时间为4小时,一但开机,4小时后必定自动关机。
      原电路采用15个LED显示工作状态,包括显示“1、2、3”档位和“0.5h、1.0h、2.0h、4.0h”定时状态和风类等信息。这15个LED和4个按键采用查理复用电路或是矩阵电路,没有深究,因待改装的单片机型号为STC89C52,IO口够用,所以决定用两位共阳数码管代替原机的15个LED,4个按键保留。
      第三步:改装。
      1.将原机单片机芯片拆下,焊下15个LED,保留原机阻容降压电路、整流滤波电路、5.1V稳压电路、4个按键、红外接收管、4路双向可控硅电路等。将数码管用硅胶固定在原LED相应位置,8个段线分别加100欧限流电阻,2个位线分别加8550三极管驱动。用洞洞板焊了一个最小系统板,用硅胶固定在原电路板的背面,不妨碍安装即可。
      2.连线,数码管10线、按键4线、风扇电机3线、摇头电机1线、蜂鸣器1线、电源2线、红外接收管1线、共22根线。
                              
      第四步:编程与仿真。
      除红外遥控功能外,其他功能都可以仿真。程序附后。
        

      第五步:程序下载与测试。
      测试成功,最终效果不错。附件中有视频。
        

附单片机程序(部分):
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
uchar code SEG[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};  //数码管代码

sbit IR_GET = P3^2;                           //红外接收头数据输入端
uchar  RXDDATA[]={0x00,0x00,0x00,0x00}; //存放接收到的四组红外编码
uchar  IRDATA;                                //遥控键键值

sbit COM1 = P1^6;     //数码管十位
sbit COM2 = P1^7;     //数码管个位

sbit KEY1 = P3^4;     //关
sbit KEY2 = P3^5;     //开/风速
sbit KEY3 = P3^6;     //摇头
sbit KEY4 = P3^7;     //定时

sbit LED1 = P1^0;     //一档,仿真用LED,实际接电机低速档(蓝色线)
sbit LED2 = P1^1;     //二档,电机中速档(白色线)
sbit LED3 = P1^2;     //三档  电机高速档(红色线)
sbit LED4 = P1^3;     //摇头,电机高速档(紫色线)
sbit BEEP = P1^4;     //蜂鸣器

uchar keypress;      //KEY2的按键值,即档位值
uint keytime;        //倒计时时间,单位为小时,数码管显示值
int time=14759;      //倒计时时间,单位为秒
uint cnt1;           //定时器1计数变量
uchar flag=0;        //档位标志
bit L_R=0;           //摇头状态变量
bit L_R_flag;        //摇头标志
bit key4_flag;       //定时按键标志

/*--------------1ms延时---------------*/                              
void delay_ms(uint xms)
{
    uchar i;
    while(xms--)
    {
        i=123;
        while(i--);
    }
}

/*--------红外专用延时,约0.1ms延时函数----------*/
void delay(uchar x)   
{
    unsigned char i;
    while(x--)
    {
        for (i = 0; i<10; i++);
    }
}

/*--------数码管显示一:显示档位---------------*/
void show_seg1(uchar dat)
{
    if(flag!=0)
    {
        if(L_R==1)          //如果是摇头状态,则十位显示“-”,否则不显示
        {
            P2=0xbf;        //“-”
            COM1=0;
            delay_ms(4);
            COM1=1;
        }
        P2=SEG[dat%10];     //个位显示档位“123”
        COM2=0;
        delay_ms(4);
        COM2=1;
    }
}

/*--------数码管显示二:显示倒计时时间---------------*/
void show_seg2(uchar time)
{
    if(cnt1<500)  P2=SEG[time/10] & 0x7f; //显示时间十位,带秒点并闪烁
    else          P2=SEG[time/10];
    COM1=0;
    delay_ms(4);
    COM1=1;

    P2=SEG[time%10];    //显示时间个位
    COM2=0;
    delay_ms(4);
    COM2=1;
}

/*--------蜂鸣器函数---------------*/
void beep()         //蜂鸣器,这里选用有源蜂鸣器
{
    BEEP=0;         //若选用无源蜂鸣器,则可模拟输出方波驱动发声
    delay_ms(70);
    BEEP=1;         //关闭蜂鸣器
}

/*--------------按键扫描---------------*/
void scan_key()
{
    if(KEY1==0)           //关机控制
    {
        beep();           //使用蜂鸣器发声时的延时作消抖
        if(KEY1==0)
        {
            flag=0;       //档位标志复位,关闭风扇电机
            keypress=0;   //KEY2的按键值复位
            L_R_flag=0;   //摇头状态标志复位,关闭摇头电机
        }
    }

    if(KEY2==0)           //开机、档位变换控制
    {
        beep();
        if(KEY2==0)
        {
             keypress++;                      //档位加
             if(keypress > 3) keypress = 1;   //值的约束,在开机状态下,轮流显示“123”,表示123档
             flag = keypress;                 //档位值赋给状态标志
             while(!KEY2)show_seg1(keypress); //按键松手检测
        }
    }

    if(flag!=0)           //摇头控制
    {
        if(KEY3==0)         
        {
            beep();
            if(KEY3==0)
            {
                 L_R = ! L_R;        //摇头状态翻转,开或关两个状态
                 LED4 = ! L_R;       //摇头电机开启或状态, P1^3输出0为开启摇头电机
                 while(!KEY3)show_seg1(keypress);
            }
        }
    }

    if(flag!=0)          //定时设置
    {
        if(KEY4==0)      
        {
            beep();
            if(KEY4==0)
            {
                 key4_flag = 1;                  //定时状态标志
                 keytime = keytime+5;            //按键每按一次加5,即“0-5-10-15-20-25-30”,这里加大了10位,后面需缩小10倍处理
                                                 //实际显示“0.0-0.5-1.0-1.5-2.0-2.5-3.0”,单位为小时
                 if(keytime > 30) keytime = 0;   //定时时间最大定为3小时,用户可以更改
                 if(keytime!=0) time = keytime*360+359; //时间换算成秒,这里本应为“*3600”,因需缩小10倍处理,故为“*360”
                 while(!KEY4) show_seg2(keytime) ;  
            }
        }
    }
}

/*--------------定时器1初始化---------------*/
void Timer_Init(void)                //1000微秒@12.000MHz
{
    TMOD |= 0x10;                //设置定时器模式
    TL1 = 0x18;                        //设置定时初始值
    TH1 = 0xFC;                        //设置定时初始值
    ET1 = 1;                        //使能定时器0中断
}

/*------------外部中断EX0初始化-------------*/
void init()
{
        EX0= 1;                 //使能 INT0 外部中断
        IT0 =1;      //外中断0下降沿触发
        IR_GET=1;    //I/O口初始化
}

/*--------------主程序---------------*/
void main()
{
    Timer_Init();
    init();     
    EA = 1;
    beep(); beep(); beep();

    while(1)
    {
        scan_key();
        if((key4_flag==0)|(keytime==0)) show_seg1(keypress);  //非定时状态或定时设定时间为0时,显示档位值
        else              show_seg2(time/360);                //否则显示倒计时时间
        switch(flag)
        {
            case 0: LED1 = 1;  LED2 = 1;  LED3 = 1;  LED4 = 1;    L_R=0; keypress=0;  keytime=0;  TR1=0;  time=14759;  break;
            case 1: LED1 = 1;  LED2 = 1;  LED3 = 1;  LED1 = 0;    TR1=1;  break;  //考虑到档位电压的冲撞,先关闭所有档位再打开,下同
            case 2: LED1 = 1;  LED2 = 1;  LED3 = 1;  LED2 = 0;    TR1=1;  break;
            case 3: LED1 = 1;  LED2 = 1;  LED3 = 1;  LED3 = 0;    TR1=1;  break;
        }
    }
}

/*--------------定时器中断处理---------------*/
void Timer1_Isr(void) interrupt 3
{
    TL1 = 0x18;                 //重装初始值
    TH1 = 0xFC;                //重装初始值
    cnt1++;
    if(cnt1>1000)       //1秒溢出
    {
        cnt1=0;
        time--;                            //定时时间秒自减1
        if(time<358) {flag=0;time=14759;}  //时间到,关机
    }
}

/*--------------外部中断处理:处理红外码--------------*/
void intt_0() interrupt 0 //下降沿触发:接收不到红外时OUT高电平,接收到红外时OUT低电平。
{
        uchar four,one,num=0;
        EX0 = 0;          //关中断0使能,防止处理过程中再接收红外信号
        delay_ms(2);          //稍延时2ms,防干扰
        if (IR_GET)       //再检测红外接收脚(9ms的前导低电平),为高电平说明是干扰
        {
                EX0 =1;              //使能中断0
                return;              //退出中断程序
        }
        while(!IR_GET);   //等IR变为高电平,跳过9ms的前导低电平信号。
        while (IR_GET);   //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
        for (four=0;four<4;four++)    //四组数据
        {
                for (one=0;one<8;one++)   //每组数据8位
                {
                        while (!IR_GET);  //等 IR 变为高电平
                        while (IR_GET)    //计算IR高电平时长(低电平时长是一样的,不用计)
                        {
                                delay(1);  //计时
                                num++;      //计时N次     
                                if (num>=20)        //20*0.1ms=2ms
                                {                 //数据“1”的时长最长也就1.685ms,计数超过则数据错误,退出中断
                                        EX0=1;        //使能中断0
                                        return;        //退出中断
                                }                  
                        }    //高电平计数完毕     
                        RXDDATA[four]>>=1;          //从低位读出,随着one的循环8次刚好读出一字节
                        if(num>6&&num<20)         // 20*0.1ms=2ms>1.685ms
                                RXDDATA[four]|=0x80;  //数据“1”
                        num=0; //计时值清0,为下一位数据的计时做准备
                }//一组数据接收结束
        }//全部四组数据接收结束
        if (RXDDATA[2]!=~RXDDATA[3])  //检测接收到的数据是否正确
        {                           //不正确则
                EX0=1;           //使能中断0
                return;   //退出中断
        }
    IRDATA=RXDDATA[2];

    switch(IRDATA)
    {
        ……
    }
    EX0 = 1;         //处理完红外接收,使能中断0,退出中断0
}

仿真+程序.7z

54.18 KB, 下载次数: 30, 下载积分: 黑币 -5

控制效果视频.7z

15.71 MB, 下载次数: 13, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏6 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:673647 发表于 2024-7-16 07:35 | 只看该作者
不错,谢谢分享!
回复

使用道具 举报

板凳
ID:277550 发表于 2024-7-16 09:59 | 只看该作者
改得不错!


不许用花线,要用橡胶护套铜芯电缆线
回复

使用道具 举报

地板
ID:619259 发表于 2024-7-17 11:26 | 只看该作者
更正:程序中“sbit LED4 = P1^3;     //摇头,电机高速档(紫色线)”改为“sbit LED4 = P1^3;     //摇头电机(紫色线)”
回复

使用道具 举报

5#
ID:23844 发表于 2024-7-19 08:32 | 只看该作者
谢谢分享!
回复

使用道具 举报

6#
ID:38658 发表于 2024-7-22 14:58 | 只看该作者
其实你可以更换所有按键就搞定了
回复

使用道具 举报

7#
ID:619259 发表于 2024-7-22 20:39 | 只看该作者
xiayudhtfghy198 发表于 2024-7-22 14:58
其实你可以更换所有按键就搞定了

已经全部更换过按键,遥控器也取出电池,依然无规律自动开机。
回复

使用道具 举报

8#
ID:1123082 发表于 2024-7-25 17:04 | 只看该作者
折腾无止境!
回复

使用道具 举报

9#
ID:285380 发表于 2024-8-2 16:13 | 只看该作者
我去   这里个个都是人才   说话又好听
回复

使用道具 举报

10#
ID:815132 发表于 2024-8-5 15:49 | 只看该作者
回复

使用道具 举报

11#
ID:1075398 发表于 2024-8-11 13:54 | 只看该作者
请问,单片机直接接一电阻驱动可控硅程序要做怎么样的处理?我 改了一个,不成功,直接用高低电平好像不能控制可控硅
回复

使用道具 举报

12#
ID:127035 发表于 2024-8-31 20:10 | 只看该作者
你好!你分享的红外遥控风扇功能正常,就遥控器无法使用,用的是同款遥控器,检测键值是一样的,能否发一份正常代码给我
回复

使用道具 举报

13#
ID:619259 发表于 2024-9-2 08:44 | 只看该作者
伟民电子 发表于 2024-8-31 20:10
你好!你分享的红外遥控风扇功能正常,就遥控器无法使用,用的是同款遥控器,检测键值是一样的,能否发一份 ...

附件中的程序是完整的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表