功能:
0.本系统采用STM32F103RCT6作为单片机
1.LCD1602液晶实时显示当前时间/窗帘状态/光照强度
2.支持手动按键/定时/光强检测三种模式控制窗帘
3.'设置’键进入设置界面
4.默认状态下’确定’键可切换模式
5.设置界面’确定’为确定
6.支持掉电保存
7.采用DC002作为电源接口可直接输入5V给整个系统供电
原理图:
PCB :
主程序:文章来源:https://www.toymoban.com/news/detail-505757.html
/*************************************************************
智能窗帘
补充说明:
***************************************************************/
#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/read/cv20281890 出处:bilibili
实物演示视频:
https://www.bilibili.com/video/BV1PV4y1L7nH/文章来源地址https://www.toymoban.com/news/detail-505757.html
到了这里,关于基于STM32单片机的智能家居窗户窗帘控制系统红外遥控proteus仿真原理图PCB的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!