标题:
单片机智能窗户程序与Proteus仿真设计 光敏电阻自动控制与时间控制
[打印本页]
作者:
不负初心蚂蚁
时间:
2022-12-10 16:33
标题:
单片机智能窗户程序与Proteus仿真设计 光敏电阻自动控制与时间控制
整个系统以AT89C52单片机为核心器件,配合电阻电容晶振等器件,构成单片机的最小系统。其它个模块围绕着单片机最小系统展开。其中包括,显示设备使用1602液晶,可以同时显示年、月、日、时、分、控制模式、光照强度等基本信息;时钟模块采用DS1302芯片,初始化之后,就会开始运行计算时间,单片机只需进行时间信息的读取即可;光照检测电路采用光敏电阻和模数转换芯片ADC0832,将模拟量数字化并显示出来;窗帘使用步进电机进行代替模拟,同时配有一个LED灯用来指示窗帘当前的开关状态;本设计还有5个按键作为操作输入设备,可以对当前时间进行调整设置和设置窗帘开关时间和光控阈值等;最后是供电采用常用的USB 5V进行供电。智能窗帘控制系统具有以下几个基本功能:
(1)手动控制:该功能是根据用户的需求通过按键进行窗帘的开关,此功能可以使窗帘的开闭处于任何一种状态;
(2)光照自动控制:系统可以根据用户设定的光照强度值通过感光器采集光照自动开光窗帘;
(3)时间控制:此功能是根据用户设定的时间一次性开关窗帘。
(4)可以通过按键是上面三种控制模式循环切换。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.gif
(188.59 KB, 下载次数: 18)
下载附件
2022-12-12 03:33 上传
单片机源程序如下:
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char // 以后unsigned char就可以用uchar代替
#define uint unsigned int // 以后unsigned int 就可以用uint 代替
sbit ADC_CS = P1^6; // ADC0832的CS引脚
sbit ADC_CLK = P1^7; // ADC0832的CLK引脚
sbit ADC_DAT = P3^2; // ADC0832的DI/DO引脚
sbit SCK_P = P1^0; // 时钟芯片DS1302的SCK管脚
sbit SDA_P = P1^1; // 时钟芯片DS1302的SDA管脚
sbit RST_P = P1^2; // 时钟芯片DS1302的RST管脚
sbit LcdRs_P = P1^3; // 1602液晶的RS管脚
sbit LcdRw_P = P1^4; // 1602液晶的RW管脚
sbit LcdEn_P = P1^5; // 1602液晶的EN管脚
sbit KeyMode_P = P3^3; // 模式切换
sbit KeySet_P = P3^4; // 设置时间按键
sbit KeySet2_P = P3^5; // 设置时间模式的开关时间和光照控制强度
sbit KeyDown_P = P3^6; // 减按键
sbit KeyUp_P = P3^7; // 加按键
sbit Led_P = P2^0; // 指示灯
uchar gMode=1; // 1是手动模式,2是时间自动模式,3是亮度自动模式
uchar OpenHour = 18; // 开启窗帘的小时
uchar OpenMinute = 20; // 开启窗帘的分钟
uchar CloseHour = 10; // 关闭窗帘的小时
uchar CloseMinute = 30; // 关闭窗帘的分钟
uchar gLight = 40; // 窗帘开关的阈值
uchar code Clock[]={0x10,0x90,0x80,0xc0}; // 步进电机顺时针旋转数组
uchar code AntiClock[]={0x80,0x90,0x10,0x30}; // 步进电机逆时针旋转数组
uchar code Clock1[]={0x10,0x90,0x80,0xc0};
uchar TimeBuff[7]={17,9,1,6,18,30,40}; // 时间数组,默认2017年9月1日,星期五,18:30:40
// TimeBuff[0] 代表年份,范围00-99
// TimeBuff[1] 代表月份,范围1-12
// TimeBuff[2] 代表日期,范围1-31
// TimeBuff[3] 代表星期,范围1-7
// TimeBuff[4] 代表小时,范围00-23
// TimeBuff[5] 代表分钟,范围00-59
// TimeBuff[6] 代表秒钟,范围00-59
/*********************************************************/
// 按键扫描(设置当前时间)
/*********************************************************/
void KeyScanf1()
{
if(KeySet_P==0)
{
LcdGotoXY(0,13); // 显示秒钟的冒号
LcdWriteData(':');
LcdWriteCmd(0x0f); // 启动光标闪烁
LcdGotoXY(0,3); // 定位光标到年份闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整年份 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[0]>0) // 判断年份是否大于0
TimeBuff[0]--; // 是的话就减去1
LcdGotoXY(0,2); // 光标定位到年份的位置
LcdPrintNum(TimeBuff[0]); // 刷新显示改变后的年份
LcdGotoXY(0,3); // 定位光标到年份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[0]<99) // 判断年份是否小于99
TimeBuff[0]++; // 是的话就加上1
LcdGotoXY(0,2); // 光标定位到年份的位置
LcdPrintNum(TimeBuff[0]); // 刷新显示改变后的年份
LcdGotoXY(0,3); // 定位光标到年份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,6); // 定位光标到月份闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整月份 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[1]>1) // 判断月份是否大于1
TimeBuff[1]--; // 是的话就减去1
LcdGotoXY(0,5); // 光标定位到月份的位置
LcdPrintNum(TimeBuff[1]); // 刷新显示改变后的月份
LcdGotoXY(0,6); // 定位光标到月份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[1]<12) // 判断月份是否小于12
TimeBuff[1]++; // 是的话就加上1
LcdGotoXY(0,5); // 光标定位到月份的位置
LcdPrintNum(TimeBuff[1]); // 刷新显示改变后的月份
LcdGotoXY(0,6); // 定位光标到月份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,9); // 定位光标到日期闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整日期 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[2]>1) // 判断日期是否大于1
TimeBuff[2]--; // 是的话就减去1
LcdGotoXY(0,8); // 光标定位到日期的位置
LcdPrintNum(TimeBuff[2]); // 刷新显示改变后的日期
LcdGotoXY(0,9); // 定位光标到日期闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[2]<31) // 判断日期是否小于31
TimeBuff[2]++; // 是的话就加上1
LcdGotoXY(0,8); // 光标定位到日期的位置
LcdPrintNum(TimeBuff[2]); // 刷新显示改变后的日期
LcdGotoXY(0,9); // 定位光标到日期闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,12); // 定位光标到小时闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整小时 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[4]>0) // 判断小时是否大于0
TimeBuff[4]--; // 是的话就减去1
LcdGotoXY(0,11); // 光标定位到小时的位置
LcdPrintNum(TimeBuff[4]); // 刷新显示改变后的小时
LcdGotoXY(0,12); // 定位光标到小时闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[4]<23) // 判断小时是否小于23
TimeBuff[4]++; // 是的话就加上1
LcdGotoXY(0,11); // 光标定位到小时的位置
LcdPrintNum(TimeBuff[4]); // 刷新显示改变后的小时
LcdGotoXY(0,12); // 定位光标到小时闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,15); // 定位光标到分钟闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整分钟 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[5]>0) // 判断分钟是否大于0
TimeBuff[5]--; // 是的话就减去1
LcdGotoXY(0,14); // 光标定位到分钟的位置
LcdPrintNum(TimeBuff[5]); // 刷新显示改变后的分钟
LcdGotoXY(0,15); // 定位光标到分钟闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[5]<59) // 判断分钟是否小于59
TimeBuff[5]++; // 是的话就加上1
LcdGotoXY(0,14); // 光标定位到分钟的位置
LcdPrintNum(TimeBuff[5]); // 刷新显示改变后的分钟
LcdGotoXY(0,15); // 定位光标到分钟闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
/* 退出前的设置 */
LcdWriteCmd(0x0C); // 关闭光标闪烁
DS1302_Write_Time(); // 把新设置的时间值存入DS1302芯片
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
}
}
/*********************************************************/
// 按键扫描(设置窗帘的动作)
/*********************************************************/
void KeyScanf2()
{
if(KeySet2_P==0)
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" OpenTime : "); // 显示第1行内容
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("CloseTime : "); // 显示第2行内容
LcdGotoXY(0,10); // 光标定位
LcdPrintNum(OpenHour); // 显示开启窗帘的小时
LcdGotoXY(0,13); // 光标定位
LcdPrintNum(OpenMinute); // 显示开启窗帘的分钟
LcdGotoXY(1,10); // 光标定位
LcdPrintNum(CloseHour); // 显示关闭窗帘的小时
LcdGotoXY(1,13); // 光标定位
LcdPrintNum(CloseMinute); // 显示关闭窗帘的分钟
LcdWriteCmd(0x0f); // 启动光标闪烁
LcdGotoXY(0,11); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整开启的小时 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(OpenHour>0) // 判断小时是否大于0
OpenHour--; // 是的话就减去1
LcdGotoXY(0,10); // 光标定位
LcdPrintNum(OpenHour); // 刷新显示改变后的小时
LcdGotoXY(0,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(OpenHour<23) // 判断小时是否小于23
OpenHour++; // 是的话就加上1
LcdGotoXY(0,10); // 光标定位
LcdPrintNum(OpenHour); // 刷新显示改变后的小时
LcdGotoXY(0,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
LcdGotoXY(0,14); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整开启的分钟 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(OpenMinute>0) // 判断分钟是否大于0
OpenMinute--; // 是的话就减去1
LcdGotoXY(0,13); // 光标定位
LcdPrintNum(OpenMinute); // 刷新显示改变后的分钟
LcdGotoXY(0,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(OpenMinute<59) // 判断分钟是否小于59
OpenMinute++; // 是的话就加上1
LcdGotoXY(0,13); // 光标定位
LcdPrintNum(OpenMinute); // 刷新显示改变后的分钟
LcdGotoXY(0,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
LcdGotoXY(1,11); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整关闭的小时 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(CloseHour>0) // 判断小时是否大于0
CloseHour--; // 是的话就减去1
LcdGotoXY(1,10); // 光标定位
LcdPrintNum(CloseHour); // 刷新显示改变后的小时
LcdGotoXY(1,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(CloseHour<23) // 判断小时是否小于23
CloseHour++; // 是的话就加上1
LcdGotoXY(1,10); // 光标定位
LcdPrintNum(CloseHour); // 刷新显示改变后的小时
LcdGotoXY(1,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
LcdGotoXY(1,14); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整关闭的分钟 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(CloseMinute>0) // 判断分钟是否大于0
CloseMinute--; // 是的话就减去1
LcdGotoXY(1,13); // 光标定位
LcdPrintNum(CloseMinute); // 刷新显示改变后的分钟
LcdGotoXY(1,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(CloseMinute<59) // 判断分钟是否小于59
CloseMinute++; // 是的话就加上1
LcdGotoXY(1,13); // 光标定位
LcdPrintNum(CloseMinute); // 刷新显示改变后的分钟
LcdGotoXY(1,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 光照强度的设置 */
LcdWriteCmd(0x0C); // 关闭光标闪烁
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" Light Set "); // 显示第1行内容
LcdGotoXY(1,0); // 光标定位
LcdPrintStr(" "); // 显示第2行内容
LcdGotoXY(1,7); // 光标定位
LcdPrintNum(gLight); // 显示窗帘的光线控制强度阈值
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(gLight>0) // 判断光线阈值是否大于0
gLight--; // 是的话就减去1
LcdGotoXY(1,7); // 光标定位
LcdPrintNum(gLight); // 刷新显示改变后的光线阈值
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(gLight<99) // 判断光线阈值是否小于59
gLight++; // 是的话就加上1
LcdGotoXY(1,7); // 光标定位
LcdPrintNum(gLight); // 刷新显示改变后的光线阈值
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
/* 退出前的设置 */
LcdShowInit(); // 液晶显示内容初始化
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
}
}
/*********************************************************/
// 按键扫描(模式切换)
/*********************************************************/
void KeyScanf3()
{
if(KeyMode_P==0)
{
gMode++; // 切换到下一模式
if(gMode==4) // 如果到尽头了
gMode=1; // 回到第一种模式
LcdGotoXY(1,0); // 光标定位
LcdPrintMode(gMode); // 显示模式
DelayMs(10); // 去除按键按下的抖动
while(!KeyMode_P); // 等待按键是否
DelayMs(10); // 去除按键松开的抖动
}
}
/*********************************************************/
// 开窗
/*********************************************************/
void Open()
{
uint i;
for(i=0;i<4;i++)
{
P2=Clock[i];
DelayMs(250);
}
Led_P=0;
}
/*********************************************************/
// 关窗
/*********************************************************/
void Close()
{
uint i;
for(i=0;i<4;i++)
{
P2=AntiClock[i];
DelayMs(250);
}
Led_P=1;
}
/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
uchar light;
LcdInit(); // 执行液晶初始化
DS1302_Init(); // 时钟芯片的初始化
LcdShowInit(); // 液晶显示内容的初始化
if(DS1302_Read_Byte(0x81)>=128) // 判断时钟芯片是否正在运行
{
DS1302_Write_Time(); // 如果没有,则初始化一个时间
}
while(1)
{
DS1302_Read_Time(); // 获取当前时钟芯片的时间,存在数组time_buf中
FlashTime(); // 刷新时间显示
light=Get_ADC0832(); // 读取光照强度
light=light/2.5; // 缩小光照检测结果(在0-99)
if(light>99) // 如果大于99
light=99; // 则依然保持99
LcdGotoXY(1,14); // 光标定位
LcdPrintNum(light); // 显示光照强度
KeyScanf1(); // 按键扫描(时间的设置)
KeyScanf2(); // 按键扫描(阈值的设置)
KeyScanf3(); // 按键扫描(模式切换)
/*手动控制模式*/
if(gMode==1)
{
if(KeyDown_P==0) // 如果关窗帘键按下了
{
if(Led_P==0) // 如果窗帘当前是打开的
{
Close(); // 则关闭窗帘
}
}
if(KeyUp_P==0) // 如果开窗帘键按下了
{
if(Led_P==1) // 如果窗帘当前是关闭的
{
Open(); // 则打开窗帘
}
}
}
/*时间控制模式*/
if(gMode==2)
{
if((TimeBuff[4]==CloseHour)&&(TimeBuff[5]==CloseMinute)&&(TimeBuff[6]==0)) // 如果到了关窗帘的时间
{
if(Led_P==0) // 如果窗帘当前是打开的
{
Close(); // 则关闭窗帘
}
}
if((TimeBuff[4]==OpenHour)&&(TimeBuff[5]==OpenMinute)&&(TimeBuff[6]==0)) // 如果到了开窗帘的时间
{
if(Led_P==1) // 如果窗帘当前是关闭的
{
Open(); // 则打开窗帘
}
}
}
/*光线控制模式*/
if(gMode==3)
{
if(light<gLight) // 当前光线小于设置的阈值
{
if(Led_P==0) // 如果窗帘当前是打开的
{
Close(); // 则关闭窗帘
}
}
else // 当前光线大于或等于设置的阈值
{
if(Led_P==1) // 如果窗帘当前是关闭的
{
Open(); // 则打开窗帘
}
}
}
DelayMs(100); // 延时0.1秒
}
}
复制代码
所有资料51hei附件下载:
仿真程序.7z
(89.02 KB, 下载次数: 57)
2022-12-12 03:37 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
heicad
时间:
2022-12-12 03:42
好资料,51黑有你更精彩!!!
作者:
gemxie
时间:
2025-1-15 11:00
好资料,51黑有你更精彩!!!
作者:
allen98
时间:
2025-3-21 10:41
感谢up的资料,学习了
作者:
allen98
时间:
2025-3-21 10:41
感谢UP的资料,学习了哦
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1