T027基于51单片机的智能窗帘窗户控制系统proteus仿真原理图PCB

功能:
0.本系统采用单片机STC89C52作为系统的主控芯片
1.系统采用LCD1602液晶实时显示当前时间/窗帘状态/光照强度
2.系统具有四个功能按键,支持手动按键/定时/遥控三种模式控制窗帘
3.系统采用一个轻触按键模拟限位开关,步进电机模拟窗帘窗户的运动
4.采用DC002作为电源接口可直接输入5V给整个系统供电

原理图:
在这里插入图片描述

PCB :
在这里插入图片描述

主程序:

/*************************************************************
                        智能窗帘

补充说明:
***************************************************************/
#include "reg52.h"
#include "LCD1602.h"
#include "DS1302.h"
#include "28BYJ48.h"
#include "eeprom52.h"
#include "tlc0832.h"
#include "infrared.h"
#include "delay.h"

#define uchar unsigned char //宏定义
#define uint unsigned int

/*******************引脚定义*********************/
sbit KEY_MODE    = P3^3;   //设置键
sbit KEY_ADD     = P3^4;   //加值键
sbit KEY_SUB     = P3^6;   //减值键
sbit KEY_ENTER   = P3^5;   //确定键
sbit BUZZER      = P2^0;   //蜂鸣器

sbit SW1      = P1^3;   //全开 限位开关
/*******************变量定义*********************/
uchar light_up = 80;
uchar light_down = 30; //存储光强上、下限值
uchar set_f = 0;            //设置选择标记,=0非设置,=1设置年,=2设置月,=3设置日,=4设置时,=5设置分,=6设置秒
                            //              =7设置定时-时,=8设置定时-分,=9设置定时-开关,=10设置窗帘打开/关闭
                            //				=11设置光强上限,=12设置光强下限,=13设置校准窗帘位置

unsigned char dis[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
uchar num;   //计数变量
uchar ds[4] = {8, 30, 16, 20}; //定时控制开时、分、控制关时、分

uchar mode = 0; //模式标记。=0手动,=1定时,=2光控
uchar light;    //存储光强

uint moto_num = 0;                                        //记录窗帘位置
uchar motor_state = 0;                                     //窗帘状态,=0已经关闭,=1处于运转过程中,=2已经打开
bit moto_f = 0;                                           //标记当前控制状态,=0控制关,=1控制开
uchar code display_mode[3][3] = {"SD\0", "DS\0", "GK\0"}; //显示模式

void WriteData(void)
{
    SectorErase(0x2000);    //擦除扇区
    WriteByte(0x2000, ds[0]);  //写入【定时时间】数据保存
    WriteByte(0x2001, ds[1]); //写入【定时时间】数据保存存
    WriteByte(0x2002, ds[2]); //写入【定时时间】数据保存存
    WriteByte(0x2003, ds[3]); //写入【定时时间】数据保存存
    WriteByte(0x2004, light_up); //写入【光强上限值】数据保存
    WriteByte(0x2005, light_down); //写入【光强下限值】数据保存
    WriteByte(0x2006, mode); //写入【模式】数据保存
}

void ReadData(void)
{
    ds[0] = ReadByte(0x2000);      //读取存储的【定时时间】数据
    ds[1] = ReadByte(0x2001);      //读取存储的【定时时间】数据
    ds[2] = ReadByte(0x2002);      //读取存储的【定时时间】数据
    ds[3] = ReadByte(0x2003);      //读取存储的【定时时间】数据
    light_up = ReadByte(0x2004);   //读取存储的【光强上限值】数据
    light_down = ReadByte(0x2005); //读取存储的【光强下限值】数据
    mode = ReadByte(0x2006);       //读取存储的【模式】数据
}

/********************************************************
函数名称:void display(void)
函数作用:正常显示日期、时间、光强等函数
参数说明:
********************************************************/
void display(void)
{
    uint t[3];

    //显示时间
    LCD_DispOneChar(0, 1, dis[time[2] / 10]); //显示时【0:表示第1列,2:表示第2行,所有关于显示都一样】
    LCD_DispOneChar(1, 1, dis[time[2] % 10]);
    LCD_DispOneChar(2, 1, ':');
    LCD_DispOneChar(3, 1, dis[time[1] / 10]); //显示分【3:表示第4列,2:表示第2行,所有关于显示都一样】
    LCD_DispOneChar(4, 1, dis[time[1] % 10]);
    LCD_DispOneChar(5, 1, ':');
    LCD_DispOneChar(6, 1, dis[time[0] / 10]); //显示秒
    LCD_DispOneChar(7, 1, dis[time[0] % 10]);

    //显示日期
    LCD_DispOneChar(0, 0, dis[time[6] / 10]); //显示年
    LCD_DispOneChar(1, 0, dis[time[6] % 10]);
    LCD_DispOneChar(2, 0, '/');
    LCD_DispOneChar(3, 0, dis[time[4] / 10]); //显示月
    LCD_DispOneChar(4, 0, dis[time[4] % 10]);
    LCD_DispOneChar(5, 0, '/');
    LCD_DispOneChar(6, 0, dis[time[3] / 10]); //显示日
    LCD_DispOneChar(7, 0, dis[time[3] % 10]);

    //显示模式
    LCD_DispStr(9, 0, display_mode[mode]);

    //显示光强
    if (light > 99)
        LCD_DispOneChar(12, 0, dis[light / 100]);
    else
        LCD_DispOneChar(12, 0, ' ');
    LCD_DispOneChar(13, 0, dis[light % 100 / 10]);
    LCD_DispOneChar(14, 0, dis[light % 10]);
    LCD_DispOneChar(15, 0, '%');

    //光强控制
    if (mode == 2) //光控模式
    {
        if ((light >= light_up || light < light_down)) //判断实际光强是否【大于等于上限 或 小于下限值】、当前处于打开状态
        {
            moto_f = 0;     //标记当前控制窗帘关闭
            motor_state = 1; //标记窗帘处于运转过程中
        }
        else if ((light < light_up && light >= light_down)) //判断实际光强是否【大于等于下限值 并且 小于上限】、当前处于关闭状态
        {
            moto_f = 1;     //标记当前控制窗帘打开
            motor_state = 1; //标记窗帘处于运转过程中
        }
    }
    else if (mode == 1) //定时模式
    {
        t[0] = time[2] * 60 + time[1]; //当前时间
        t[1] = ds[0] * 60 + ds[1];     //窗帘开启时间点
        t[2] = ds[2] * 60 + ds[3];     //窗帘关闭时间点

        if (t[1] < t[2]) //0时 --> t[1] --> t[2] --> 24时
        {
            if (t[0] >= t[1] && t[0] <= t[2])
                moto_f = 1; //标记当前需要打开窗帘
            else
                moto_f = 0; //标记当前需要关闭窗帘
        }
        else //0时 --> t[2] --> t[1] --> 24时
        {
            if (t[0] >= t[1] || t[0] <= t[2])
                moto_f = 1; //标记当前需要打开窗帘
            else
                moto_f = 0; //标记当前需要关闭窗帘
        }
        motor_state = 1; //标记窗帘处于运转过程中
    }
    
    if (moto_f == 0 && motor_state != 0 && SW1 != 0) //控制关闭窗帘
    {
        if (moto_num == 0) //控制次数减到0时,表示窗户已经关闭完成
        {
            BYJ48 = BYJ48 & 0xf0; //关闭步进电机
            motor_state = 0;    //标记窗帘处于关闭状态
            LCD_DispStr(10, 1, "ZT:OFF");
        }
        else
        {
            motor_z();  //步进电机正转
            moto_num--; //控制次数-1
            LCD_DispStr(10, 1, "-->OFF");
        }
    }
    else if (moto_f == 1 && motor_state != 2 && SW1 != 0) //控制打开窗帘
    {
        if (moto_num >= 192) //控制次数加到192时,表示窗户已经打开完成
        {
            BYJ48 = BYJ48 & 0xf0; //关闭步进电机
            motor_state = 2;    //标记窗帘处于打开状态
            LCD_DispStr(10, 1, "ZT:ON ");
        }
        else
        {
            motor_f();  //步进电机反转
            moto_num++; //控制次数+1
            LCD_DispStr(10, 1, "-->ON ");
        }
    }
    else //窗户处于停止状态
    {
        BYJ48 = BYJ48 & 0xf0; //关闭步进电机
        if (motor_state == 0)
            LCD_DispStr(10, 1, "ZT:OFF");
        else if (motor_state == 2)
            LCD_DispStr(10, 1, "ZT:ON ");
    }
}
/********************************************************
函数名称:void display2(void)
函数作用:显示调整日期、时间函数
参数说明:
********************************************************/
void display2()
{
    num++;

    LCD_DispStr(1, 0, "Date:");
    LCD_DispStr(1, 1, "Time:");

    if (num % 2 == 0) //偶数次显示,奇数次不显示。这样就会有闪烁效果,可以清楚看到当前设置的是哪个值
    {
        LCD_DispOneChar(6, 0, dis[time[6] / 10]); //显示年
        LCD_DispOneChar(7, 0, dis[time[6] % 10]);
        LCD_DispOneChar(8, 0, '/');
        LCD_DispOneChar(9, 0, dis[time[4] / 10]); //显示月
        LCD_DispOneChar(10, 0, dis[time[4] % 10]);
        LCD_DispOneChar(11, 0, '/');
        LCD_DispOneChar(12, 0, dis[time[3] / 10]); //显示日
        LCD_DispOneChar(13, 0, dis[time[3] % 10]);

        LCD_DispOneChar(6, 1, dis[time[2] / 10]); //显示时
        LCD_DispOneChar(7, 1, dis[time[2] % 10]);
        LCD_DispOneChar(8, 1, ':');
        LCD_DispOneChar(9, 1, dis[time[1] / 10]); //显示分
        LCD_DispOneChar(10, 1, dis[time[1] % 10]);
        LCD_DispOneChar(11, 1, ':');
        LCD_DispOneChar(12, 1, dis[time[0] / 10]); //显示秒
        LCD_DispOneChar(13, 1, dis[time[0] % 10]);
    }
    else //奇数次不显示
    {
        switch (set_f) //根据当前设置的内容,对应位置闪烁
        {
        case 1:
            LCD_DispStr(6, 0, "  ");
            break;
        case 2:
            LCD_DispStr(9, 0, "  ");
            break;
        case 3:
            LCD_DispStr(12, 0, "  ");
            break;
        case 4:
            LCD_DispStr(6, 1, "  ");
            break;
        case 5:
            LCD_DispStr(9, 1, "  ");
            break;
        case 6:
            LCD_DispStr(12, 1, "  ");
            break;
        default:
            break;
        }
    }
}
/********************************************************
函数名称:void display3(void)
函数作用:显示调整定时时间函数
参数说明:
********************************************************/
void display3()
{
    num++;
    LCD_DispStr(0, 0, "Sets timer time:");
    LCD_DispStr(7, 1, "--");
    if (num % 2 == 0) //偶数次显示,奇数次不显示。这样就会有闪烁效果,可以清楚看到当前设置的是哪个值
    {
        LCD_DispOneChar(1, 1, dis[ds[0] / 10]); //显示定时开-时
        LCD_DispOneChar(2, 1, dis[ds[0] % 10]);
        LCD_DispOneChar(3, 1, ':');
        LCD_DispOneChar(4, 1, dis[ds[1] / 10]); //显示定时开-分
        LCD_DispOneChar(5, 1, dis[ds[1] % 10]);

        LCD_DispOneChar(10, 1, dis[ds[2] / 10]); //显示定时关-时
        LCD_DispOneChar(11, 1, dis[ds[2] % 10]);
        LCD_DispOneChar(12, 1, ':');
        LCD_DispOneChar(13, 1, dis[ds[3] / 10]); //显示定时关-分
        LCD_DispOneChar(14, 1, dis[ds[3] % 10]);
    }
    else //奇数次不显示
    {
        switch (set_f) //根据当前设置的内容,对应位置闪烁
        {
        case 7:
            LCD_DispStr(1, 1, "  ");
            break;
        case 8:
            LCD_DispStr(4, 1, "  ");
            break;
        case 9:
            LCD_DispStr(10, 1, "  ");
            break;
        case 10:
            LCD_DispStr(13, 1, "  ");
            break;
        default:
            break;
        }
    }
}
/********************************************************
函数名称:void display4(void)
函数作用:显示调整光强控制函数
参数说明:
********************************************************/
void display4(void)
{
    num++;

    LCD_DispStr(0, 0, "Light_Up  :");
    LCD_DispStr(0, 1, "Light_Down:");
    LCD_DispOneChar(15, 0, '%');
    LCD_DispOneChar(15, 1, '%');
    if (num % 2 == 0) //偶数次显示,奇数次不显示。这样就会有闪烁效果,可以清楚看到当前设置的是哪个值
    {
        LCD_DispOneChar(12, 0, dis[light_up / 100]); //显示光强上限值
        LCD_DispOneChar(13, 0, dis[light_up % 100 / 10]);
        LCD_DispOneChar(14, 0, dis[light_up % 10]);

        LCD_DispOneChar(12, 1, dis[light_down / 100]); //显示光强下限值
        LCD_DispOneChar(13, 1, dis[light_down % 100 / 10]);
        LCD_DispOneChar(14, 1, dis[light_down % 10]);
    }
    else //奇数次不显示
    {
        switch (set_f) //根据当前设置的内容,对应位置闪烁
        {
        case 11:
            LCD_DispStr(12, 0, "   ");
            break;
        case 12:
            LCD_DispStr(12, 1, "   ");
            break;
        default:
            break;
        }
    }
}
/********************************************************
函数名称:void KeyScan(void)
函数作用:按键查询处理函数
参数说明:
********************************************************/
void KeyScan(void)
{
    //设置键
    if (hw_data == 'B' || KEY_MODE == 0) //按键按下
    {
        DelayMs(50);                        //延时消抖
        if (hw_data == 'B' || KEY_MODE == 0) //再次确认按键按下
        {
            BUZZER = 0;
            DelayMs(130);
            BUZZER = 1;
            BYJ48 = BYJ48 & 0xf0; //关闭步进电机
            if (set_f == 6)    //日期、时间校准完
            {
                LCD_Clear(); //清除屏幕显示
                DelayMs(4);;        //延时等待全部清除完毕
                set_f = 13;              //跳到校准窗帘状态
            }
            else if (set_f == 0) //进入设置先清除屏幕,显示设置部分
            {
                Write_DS1302(WRITE_PROTECT, 0X00); //禁止DS1302写保护
                LCD_Clear();          //清除屏幕显示
                DelayMs(4);;                 //延时等待全部清除完毕
                switch (mode)                     //根据对应的模式,设置对应的参数
                {
                case 0:
                    set_f = 1;
                    break; //手动模式
                case 1:
                    set_f = 7;
                    break; //定时模式
                case 2:
                    set_f = 11;
                    break; //光控模式
                default:
                    break;
                }
            }
            else if (set_f == 10 || set_f == 12) //进入设置日期时间
            {
                LCD_Clear(); //清除屏幕显示
                DelayMs(4);;        //延时等待全部清除完毕
                set_f = 1;               //进入校准时间
            }
            else
                set_f++; //设置变量+1
            if (set_f > 12)
            {
                set_f = 0; //重置设置变量

                Write_DS1302(WRITE_MINUTE, (time[1] / 10) * 16 + time[1] % 10); //将设置好的时间写入DS1302
                Write_DS1302(WRITE_SECOND, (time[0] / 10) * 16 + time[0] % 10);

                WriteData();

                LCD_Clear(); //清除屏幕显示
                DelayMs(4);;        //延时等待全部清除完毕
            }
        }
        while (!KEY_MODE)
            ; //等待按键松开
    }
    //确定
    if (hw_data == '|' || KEY_ENTER == 0) //按键按下
    {
        DelayMs(50);                                        //延时消抖
        if ((hw_data == '|' || KEY_ENTER == 0) && set_f != 0) //再次确认按键按下
        {
            BUZZER = 0;
            DelayMs(130);
            BUZZER = 1;
            if (set_f < 7)
            {
                Write_DS1302(WRITE_MINUTE, (time[1] / 10) * 16 + time[1] % 10); //将设置好的时间写入DS1302
                Write_DS1302(WRITE_SECOND, (time[0] / 10) * 16 + time[0] % 10);
            }
            set_f = 0; //重置设置变量

            WriteData();

            LCD_Clear(); //清除屏幕显示
            DelayMs(4);;        //延时等待全部清除完毕
        }
        else if (KEY_ENTER == 0 && set_f == 0) //切换模式
        {
            mode++;              //模式变量+1
            if (mode >= 3)       //最大3个模式
                mode = 0;        //重新回到第1个模式
            if (motor_state == 1) //如果处于运转过程中
            {
                if (moto_f == 0) //控制步进电机关闭
                    motor_state = 0;
                else //控制步进电机打开
                    motor_state = 2;
            }
            WriteData();
        }
        while (!KEY_ENTER)
            ; //等待按键松开
    }

仿真演示视频:
https://www.bilibili.com/video/BV1me4y1p7ZY/

实物演示视频:
https://www.bilibili.com/video/BV1pP411u72g/

  • 1
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值