【Proteus仿真】【51单片机】教室灯光控制器设计

发布于:2025-09-13 ⋅ 阅读:(14) ⋅ 点赞:(0)


一、功能简介

本项目使用Proteus8仿真51单片机控制器,使用LCD1602液晶、DS1302时钟模块、人体红外感应模块、开关LED指示灯、继电器、PCF8591 ADC模块、光敏传感器、按键模块等。
主要功能:
系统运行后,LCD1602显示当前时间、光线强弱状态,光线强度、有无人、灯开关状态等。
如果检测光线强度大于上限值,视为白天,此时不管有无人,都不会打开电灯;
如果检测光线强度低于下限值,视为夜晚,此时检测有人,打开电灯,无人则延迟2秒熄灭;可通过K3键进入阈值设置模式,K3可切换时间、阈值上下限位置,K1和K2键调节,K4确认并返回主界面;当时间到达设定时间,则进入手动控制模式,此时可通过开关来打开和关闭电灯;当时间到达次日早上,则又进入自动控制模式。


二、软件设计

/*
作者:嗨小易(QQ技术交流群:570487280)

*/



//系统数据采集
void sys_data_get(void)
{
	while(1)
	{
		//获取时间
		ds1302_read_time();
		sys_ctrl.hour=(gDS1302_TIME[2]/16)*10+gDS1302_TIME[2]%16;
		sys_ctrl.min=(gDS1302_TIME[1]/16)*10+gDS1302_TIME[1]%16;
		sys_ctrl.sec=(gDS1302_TIME[0]/16)*10+gDS1302_TIME[0]%16;
		//读取光线值
		sys_ctrl.light=pcf8591_read_adcvalue(0);
		sys_ctrl.light=cal_map(sys_ctrl.light,0,255,0,100);
		//白天晚上状态获取
		if(sys_ctrl.light>sys_ctrl.setlight[1])sys_ctrl.dayflag=0;
		else if(sys_ctrl.light<sys_ctrl.setlight[0])sys_ctrl.dayflag=1; 
		
		//检测是否有人
		if(IRED==0)sys_ctrl.man=1;
		else sys_ctrl.man=0;

		break;
	}	
}

//系统数据显示
void sys_data_show(void)
{
	u8 buf[3];

	while(1)
	{
		//正常模式显示
		if(sys_ctrl.mode==0)
		{
			//时间显示
			buf[0]=gDS1302_TIME[2]/16+0x30;
			buf[1]=gDS1302_TIME[2]%16+0x30;
			buf[2]='\0';
			lcd1602_show_string(0,0,buf);
			buf[0]=gDS1302_TIME[1]/16+0x30;
			buf[1]=gDS1302_TIME[1]%16+0x30;
			buf[2]=':';
			lcd1602_show_string(3,0,buf);
			buf[0]=gDS1302_TIME[0]/16+0x30;
			buf[1]=gDS1302_TIME[0]%16+0x30;
			buf[2]='\0';
			lcd1602_show_string(6,0,buf);
			//光线强度显示
			lcd1602_show_nums(2,1,sys_ctrl.light,3,0);
			//白天夜晚状态显示
			if(sys_ctrl.dayflag==0)lcd1602_show_string(11,0,"day  ");
			else lcd1602_show_string(11,0,"night");
			//有无人状态显示
			if(sys_ctrl.man==0)lcd1602_show_string(8,1,"N");
			else lcd1602_show_string(8,1,"Y");
			//自动手动模式显示
			if(sys_ctrl.ctrl_flag==0)lcd1602_show_string(10,1,"Au");
			else lcd1602_show_string(10,1,"Sd");
			//电灯开关状态显示
			if(sys_ctrl.onoff==0)lcd1602_show_string(13,1,"OFF");
			else lcd1602_show_string(13,1," ON");
		}
		//设置模式显示
		else
		{
			//时间阈值
			lcd1602_show_nums(8,0,sys_ctrl.settime[0],2,0x80);
			lcd1602_show_nums(11,0,sys_ctrl.settime[1],2,0x80);
			lcd1602_show_nums(14,0,sys_ctrl.settime[2],2,0x80);	
			//光线阈值
			lcd1602_show_nums(8,1,sys_ctrl.setlight[0],2,0);
			lcd1602_show_nums(12,1,sys_ctrl.setlight[1],2,0);
			
			//对应位置闪烁
			switch(sys_ctrl.mode)
			{
				case 1://时
					lcd1602_show_string(8,0,"  ");
					delay_ms(50);
					lcd1602_show_nums(8,0,sys_ctrl.settime[0],2,0x80);	
					break;
				case 2://分
					lcd1602_show_string(11,0,"  ");
					delay_ms(50);
					lcd1602_show_nums(11,0,sys_ctrl.settime[1],2,0x80);	
					break;
				case 3://秒
					lcd1602_show_string(14,0,"  ");
					delay_ms(50);
					lcd1602_show_nums(14,0,sys_ctrl.settime[2],2,0x80);	
					break;
				case 4://光线下限
					lcd1602_show_string(8,1,"  ");
					delay_ms(50);
					lcd1602_show_nums(8,1,sys_ctrl.setlight[0],2,0);	
					break;
				case 5://光线上限
					lcd1602_show_string(12,1,"  ");
					delay_ms(50);
					lcd1602_show_nums(12,1,sys_ctrl.setlight[1],2,0);	
					break;
			}	
		}

		break;
	}
}

//系统数据设置
void sys_data_set(void)
{
	u8 key=0;
	static u8 oneflag=0;

	key=key_scan(0);
	//设置
	if(key==KEY3_PRESS)
	{
		sys_ctrl.mode++;
		if(sys_ctrl.mode>5)sys_ctrl.mode=1;
		if(oneflag==0)
		{
			oneflag=1;
			sys_parm_set_show();//系统参数设置界面显示
		}
	}
	//加
	else if(key==KEY1_PRESS)
	{
		switch(sys_ctrl.mode)
		{
			case 1://时
				sys_ctrl.settime[0]++;
				if(sys_ctrl.settime[0]>23)sys_ctrl.settime[0]=0;
				break;
			case 2://分
				sys_ctrl.settime[1]++;
				if(sys_ctrl.settime[1]>59)sys_ctrl.settime[1]=0;
				break;
			case 3://秒
				sys_ctrl.settime[2]++;
				if(sys_ctrl.settime[2]>59)sys_ctrl.settime[2]=0;
				break;
			case 4://光线下限
				sys_ctrl.setlight[0]++;
				if(sys_ctrl.setlight[0]>99)sys_ctrl.setlight[0]=0;
				break;
			case 5://光线上限
				sys_ctrl.setlight[1]++;
				if(sys_ctrl.setlight[1]>99)sys_ctrl.setlight[1]=0;
				break;
		}	
	}
	//减
	else if(key==KEY2_PRESS)
	{
		switch(sys_ctrl.mode)
		{
			case 1://时
				sys_ctrl.settime[0]--;
				if(sys_ctrl.settime[0]<0)sys_ctrl.settime[0]=23;
				break;
			case 2://分
				sys_ctrl.settime[1]--;
				if(sys_ctrl.settime[1]<0)sys_ctrl.settime[1]=59;
				break;
			case 3://秒
				sys_ctrl.settime[2]--;
				if(sys_ctrl.settime[2]<0)sys_ctrl.settime[2]=59;
				break;
			case 4://光线下限
				sys_ctrl.setlight[0]--;
				if(sys_ctrl.setlight[0]<0)sys_ctrl.setlight[0]=99;
				break;
			case 5://光线上限
				sys_ctrl.setlight[1]--;
				if(sys_ctrl.setlight[1]<0)sys_ctrl.setlight[1]=99;
				break;
		}	
	}
	//确定
	else if(key==KEY4_PRESS)
	{
		if(sys_ctrl.mode!=0)
		{
			sys_ctrl.mode=0;
			oneflag=0;
			sys_open_show();//系统开机界面显示
		}
	}		
}

//系统功能控制
void sys_fun_ctrl(void)
{
	//如果是深夜,且时间到达设定时间
	if(sys_ctrl.hour==sys_ctrl.settime[0])
	{
		if(sys_ctrl.min==sys_ctrl.settime[1])
		{
			if(sys_ctrl.sec==sys_ctrl.settime[2])
			{
				sys_ctrl.ctrl_flag=1;//转为手动	
			}	
		}		
	}
	if(sys_ctrl.ctrl_flag==1)
	{
		//如果到达白天,转为自动
		if(sys_ctrl.hour==6)
		{
			if(sys_ctrl.min==0)
			{
				if(sys_ctrl.sec==0)
				{
					sys_ctrl.ctrl_flag=0;//转为自动	
				}	
			}		
		}	
	}	
	
	//自动控制模式
	if(sys_ctrl.ctrl_flag==0)
	{
		//正常模式
		if(sys_ctrl.mode==0)
		{
			//光线大于上限阈值,白天
			if(sys_ctrl.dayflag==0)
			{
				LED=1;//关闭电灯		
			}
			//光线小于下限值,晚上
			else 
			{
				//如果感应到有人
				if(sys_ctrl.man==1)
				{
					delay_ms(100);
					if(sys_ctrl.man==1)
					{
						sys_ctrl.onoff=1;
						LED=0;//打开电灯	
					}
				}
				//如果人离开
				else
				{
					//电灯已打开
					if(sys_ctrl.onoff==1)
					{
						delay_ms(2000);
						LED=1;//关闭电灯
						sys_ctrl.onoff=0;	
					}		
				}	
			}
		}	
	}
	//手动控制模式
	else
	{
		//如果手动按下遥控或机械开关
		if(SWITCH==0)
		{
			LED=0;//打开电灯
			sys_ctrl.onoff=1;		
		}
		else
		{ 	
			LED=1;//关闭电灯
			sys_ctrl.onoff=0;	
		}	
	}		
}




三、实验现象

B站演示视频:https://space.bilibili.com/444388619

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

联系作者

视频地址:https://space.bilibili.com/444388619/video
专注于51单片机、STM32、国产32、DSP、Proteus、arduino、ESP32、物联网软件开发,PCB设计,视频分享,技术交流。


网站公告

今日签到

点亮在社区的每一天
去签到