基于51单片机的智能台灯设计

发布于:2024-04-23 ⋅ 阅读:(19) ⋅ 点赞:(0)

基于51单片机的智能台灯

(程序+PCB+原理图+设计报告)

功能介绍

具体功能:

1.光敏电阻感应光亮,将信息处理给单片机,根据环境亮度调节亮度;

2.使用E18- D80NK红外接近传感器,靠的太近,蜂鸣器会提醒报警;

3.使用HC-SR501人体红外传感器,光亮不够且检测到人体时台灯自动亮;

4.LED驱动电路采用3路串联、每路4颗的LED灯,可手动调节台灯亮度;

5.可以设定学习时间;

6.检测无人时(30秒)台灯自动熄灭 ,时间可调;

/*************************************************
* 名称 : 智能调光台灯

* 功能 : (1)亮度不够且有人靠近时台灯自动亮;
            (2)靠的太近会提醒坐姿不正(蜂鸣器)
            (3)附近无人时台灯自动熄灭(30秒)  时间可调
            (4)根据环境亮度调节等亮度
            (5)可手动调节台灯亮度
             (6)设定学习时间
***********************************************************************/
//头函数
#include <reg52.h>																								   
#include <ADC0809.H>

//宏定义
#define uint unsigned int
#define uchar unsigned char
#define DUAN P0				  //数码管段位

																											
unsigned char code tab[]={0xa0,0xbb,0x62,0x2a,0x39,0x2c,0x24,0xba,0x20,0x28,0xff};       //0-9的显示码表      gc.debfa	 
unsigned char code tab_dian[]={0x80,0x9b,0x42,0x0a,0x19,0x0c,0x04,0x9a,0x00,0x08,0xdf};  //带点0-9的显示码表  	 
uchar pdata tt[51];		    //定义空数组用于AD0809取平均值

uchar scale=20,rsd_sec;		//定义占空比比例,热释电计时秒变量
char min,sec;				//定义计时分秒

//位定义
bit bdata flag_auto,		//自动切换标志位
          ss,				//闪烁标志位
		  flag_bs,			//报警位标志位
		  flag_rsd,			//热释电动作标志位
		  flag_jiejin=1;    //接近传感器标志位

uchar flag_set=0;			//设置变量:0 正常  1 调分  2 调秒
uchar lum;					//ad0809读出值

//函数声明
void delay(uchar i);

//管脚声明
sbit LED = P3^4;	//PWM输出
sbit change= P2^3;	//自动模式切换按键
sbit set = P2^2;	//设置按键
sbit add = P2^1;	//加按键
sbit sub = P2^0;	//减按键
sbit rsd = P3^6;    //热释电
sbit jiejin=P3^5;   //接近开关
sbit buzz=P3^7;

sbit W0=P2^7;		//数码管位端
sbit W1=P2^6;
sbit W2=P2^5;
sbit W3=P2^4;

/**********************************************************************
* 名称 : display();
* 功能 : 数码管显示
* 输入 : 无
* 输出 : 无
***********************************************************************/	  
void display()
{
	if(flag_set==0)			   //正常模式下
	{
		DUAN=tab[min/10];	   //送入段码,秒数高位
		W0=0;				   //打开位地址
		delay(1);			   //小延时
		W0=1;				   //关闭位地址
		DUAN=tab_dian[min%10]; //送入段码,秒数低位
		W1=0;
		delay(1);
		W1=1;
		DUAN=tab[sec/10];	   //送入段码,分钟数高位
		W2=0;
		delay(1);
		W2=1;
		DUAN=tab[sec%10];	   //送入段码,分钟数高位
		W3=0;
		delay(1);
		W3=1;
	}
	else if(flag_set==1)	   //设置模式下闪烁相应位
	{
		if(ss==1)			   //闪烁标志  ss=1 正常显示
		{
			DUAN=~tab[min/10];
			W0=0;
			delay(1);
			W0=1;
			DUAN=~tab_dian[min%10];
			W1=0;
			delay(1);
			W1=1;
		}
		else				   //闪烁标志  ss=0 熄灭相应位 达到闪烁效果	 ss在定时器里500ms取反一次
		{
			DUAN=~tab[10];	   //
			W0=0;
			delay(1);
			W0=1;
			DUAN=~tab_dian[10];
			W1=0;
			delay(1);
			W1=1;
		}
		DUAN=~tab[sec/10];
		W2=0;
		delay(1);
		W2=1;
		DUAN=~tab[sec%10];
		W3=0;
		delay(1);
		W3=1;
	}
	else
	{
		
		DUAN=~tab[min/10];
		W0=0;
		delay(1);
		W0=1;
		DUAN=~tab_dian[min%10];
		W1=0;
		delay(1);
		W1=1;
		if(ss==1)
		{
			DUAN=~tab[sec/10];
			W2=0;
			delay(1);
			W2=1;
			DUAN=~tab[sec%10];
			W3=0;
			delay(1);
			W3=1;
		}
		else
		{
			DUAN=~tab[10];
			W2=0;
			delay(1);
			W2=1;
			DUAN=~tab[10];
			W3=0;
			delay(1);
			W3=1;
		}
	}
}

/**********************************************************************
* 名称 : KEY();
* 功能 : 按键控制
* 输入 : 无
* 输出 : 无
***********************************************************************/
void KEY()
{
	uint lum_mean,lum_all;
	uchar b,c;
	if(change==0)				  //自动切换按键按下
	{
		delay(10);				  //去抖
		if(change==0)			  //再次判断按键按下
		{
			buzz=0;				  //蜂鸣器鸣响
			flag_auto=!flag_auto; //自动模式标志位取反
			if(flag_auto==1)	  //当切换到手动模式时  首先将LED发光比例PWM设置在50%
			scale=20;
			
		}
		while(!change) display();buzz=1; //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
	}
	if(jiejin==0&&flag_jiejin==1) //接近传感器检测到障碍时  开启报警
	{
		buzz=0;
		flag_jiejin=0;
	}
	if(jiejin!=flag_jiejin)	      //接近传感器检测不到障碍时  关闭报警
	{
		buzz=1;
		flag_jiejin=1;
	}
	if(set==0)				      //设置键按下时
	{
		delay(10);
		if(set==0)
		{
			buzz=0;
			flag_set++;			  //设置变量++
			if(flag_set==3)		  //加到3时回复回正常模式
			flag_set=0;
			flag_bs=0;			  //按下设置 关闭报警
			
		}
		while(!set) display(); buzz=1;//等待按键释放  松开按键后关闭蜂鸣器、刷新显示
	}
	if(flag_set==1)					  //加键按键只有在设置状态(flag_set!=0)时按下才有效	  调分
	{								 
		if(add==0)					  //加按键按下时
		{
			delay(10);				  //消抖
			if(add==0)
			{
				buzz=0;				  //蜂鸣器响
				min++;				  //分++
				if(min>=60)
				min=0;
				
			}
			while(!add) display(); buzz=1;	 //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		if(sub==0)					  //减按键按下时
		{
			delay(10);				  //消抖
			if(sub==0)
			{
				buzz=0;				  //蜂鸣器响
				min--;				  //分--
				if(min>0)
				min=59;
				
			}
			while(!sub) display(); buzz=1;	 //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
	}
	if(flag_set==2)					//调秒
	{								
		if(add==0)					//加键按下
		{						
			delay(10);				//消抖
			if(add==0)
			{
				buzz=0;				//蜂鸣器响
				sec++;				//秒++
				if(sec>=60)
				sec=0;
				
			}
			while(!add) display(); buzz=1;	  //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		if(sub==0)					 //减键按下
		{
			delay(10);
			if(sub==0)				 //消抖
			{
				buzz=0;				 //蜂鸣器响
				sec--;				 //秒--
				if(sec<0)
				sec=59;
				
			}
			while(!sub) display();	buzz=1;	  //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		while(!sub);
	}
		
	if(flag_auto==0)					//自动模式
	{
		if(flag_rsd==1)					//且有人在范围内时	环境发光强度控制灯光变化
		{
			for(b=0;b<49;b++) 			//将空数组tt[]内数值整体左移一位
			{
				tt[b]=tt[b+1];			//将后一数值放到前一位置
			}
			tt[49]=ADC0809();			//将读出的ad0809数值放入tt[49]
			for(c=0;c<50;c++)			//将tt[]内数值相加
			{
				lum_all=lum_all+tt[c];
			}
			lum_mean=lum_all/50;		//将总数/50取出平均值
//			lum_all=0;					//将总数清零
				
			if(lum_mean<=30) scale=1;			   //判断取出平均值大小  小于30  发光强度0%
			else if(lum_mean>=150) scale=41;	   //大于150  发光强度100%
			else scale=((lum_mean-30)/3)+1;		   //其他值时将其计算得到发光强度 (计算目的是为了得到一个1-41之间的数值 控制灯光变化)
		}
		else
		scale=1;					 //没有人在范围内时 将灯光亮度调至0%
	}
	else						  	 //手动模式下
	{
		if(flag_set==0)				 //正常模式下
		{
			if(add==0)				 //加键按下
			{
				delay(10);
				if(add==0)
				{
				//	buzz=0;           //蜂鸣器响
					scale++;		  //灯光比例++
					if(scale>=41)
					scale=41;
					display();
				}
			//	while(!add) display();	buzz=1;
			}
			if(sub==0)				  //减键按下时
			{
				delay(10);
				if(sub==0)
				{
				//	buzz=0;			   //蜂鸣器响
					scale--;		   //灯光比例--
					if(scale>1)
					scale=1;
					display();
				}
		//		while(!sub) display(); buzz=1;
			}
		}
	}
}

/**********************************************************************
* 名称 : init();
* 功能 : 初始化定时器
* 输入 : 无
* 输出 : 无
***********************************************************************/

void init()
{
	TMOD=0x11;	   //工作方式1
	TH1=0x3c;
	TL1=0xb0;	   //T1赋初值50ms
	TH0=0xff;
	TL0=0xe7;	   //T0赋初值25us	  
	ET0=1;
	ET1=1;		   //打开中断允许开关
	EA=1;		   //中断总开关
	TR0=1;		   //开定时器0 开关
	TR1=0;		   //关定时器0 开关
}

/**********************************************************************
* 名称 : main();
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
	init();		  //调用初始化函数
	flag_auto=1;  //初始化手动模式
	rsd=0;		  //热释电引脚置低(有信号时时高电平)
	delay(500);	  //延时500ms后开机

	while(1)	  //大循环
	{
		KEY();		 //调用按键函数
		display();	 //调用显示函数
	}
}

/**********************************************************************
* 名称 : delay();
* 功能 : 延时函数:大约1ms
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay(uchar i)
{
  uchar j,k; 
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}

/**********************************************************************
* 名称 : void time0() interrupt 1
* 功能 : 定时器T0 中断服务函数:PWM脉冲发生函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void time0() interrupt 1
{
	uchar n;
	TH0=0xff;
	TL0=0xe7;		 //重新赋初值
	n++;			 //每25us  n++
	if(n>scale)		 //n<设置比例时,打开灯
	{
		LED=1;
	}
	else if(n<=scale)//n大于等于设置比例时 关闭灯
	{
		LED=0;
	}
	if(n==40)		 //n==40  :25us*40=1ms   1kHZ
	{
		n=0;		 //n=0
	}
	else ;	
}

/**********************************************************************
* 名称 : void time1() interrupt 3
* 功能 : 定时器T1 中断服务函数:计时和闪烁控制	  红外热释
* 输入 : 无
* 输出 : 无
***********************************************************************/
void time1() interrupt 3
{
	uchar m;
	TH1=0x3c;
	TL1=0xb0;		 //重新赋初值
	m++;			 //50ms  m++
	if((m==10||m==20)&&flag_set!=0)	  //每过500ms  并且 在设置状态时 
	{
		ss=!ss;						  //闪烁变量取反
	}
	if(m==20)						  //到达1s时
	{
		m=0;						  //m=0
		if(rsd==0)					  //热释电无信号时
		rsd_sec++;					  //热释电计时秒++
		if(rsd_sec<=30&&rsd==1)		  //热释电计时秒小于等于30 并且 热释电有信号时
		{
			rsd_sec=0;				  //将热释电秒清零
			flag_rsd=1;				  //标志位置1 控制AD0809采集数值 调节灯光亮度
		}
		else if(rsd_sec>30&&rsd==0)	  //热释电计时秒大于30 并且 热释电无信号时
		{
			flag_rsd=0;				  //标志位置0 停止ad0809转换 关闭灯光
			rsd_sec=0;				  //热释电计时秒清零
		}
		if(flag_set==0&&flag_bs==0&&((min+sec)!=0))		 //正常模式下&&未报警&&定时时间不为零时
		{
			sec--;
			if(sec<0)									 //定时秒--  小于0时
			{
				sec=59;									 //复位到59秒
				min--;									 //分--
			}
			if(min<=0&&sec==0)							 //分和秒都减到零时
			{
				min=0;
				flag_bs=1;
				buzz=0;									 //蜂鸣器报警提示时间到
			}
		}
//		else buzz=1;	
	}	
}

硬件设计

使用元器件:

单片机:STC89C52;

(注意:单片机是通用的,无论51还是52、无论stc还是at都一样,引脚功能都一样。程序也是一样的。)

LED;蜂鸣器;

三极管;电阻;

6*6轻触开关;

7*7自锁开关;

3.6寸数码管;

人体感应模块;

红外接近传感器;

导线:若干;

结构图:

设计资料

01 原理图

本系统原理图采用Altium Designer19设计,具体如图!

02 程序

本设计使用软件keil5版本编程设计,资料里有安装教程,无需担心!具体如图!

03 设计报告

三千字设计报告,具体如下!

04 设计资料

        资料获取请关注同名公众号,全部资料包括程序(含注释)、PCB电路图、AD原理图、设计报告、任务书、元件清单、结构图等。具体内容如下,全网最全! !

点赞分享一起学习成长。