基于51单片机的教室照明灯人数计数系统proteus仿真原理图PCB

功能:
0.本系统采用STC89C52作为单片机
1.LCD1602液晶实时显示当前时间/温度/教室人数
2.自动模式下,在工作时间内(1824时),当环境黑暗时,根据进入教室的人数开启14盏灯,其余时候灯光关闭
3.手动模式下,可通过按键开启灯光
4.按键可设置当前时间/工作模式/工作时间
5.采用DC002作为电源接口可直接输入5V给整个系统供电

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

PCB :
在这里插入图片描述

主程序:

#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int

uchar time_data[7];
uchar code write_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80};       //数据的地址
uchar code read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};

uchar code table1[]="C: 00|2000/00/00";
uchar code table2[]="T: 00|00:00:00 0";
uchar code table3[]="                ";			 //清屏内容
uchar code table4[]="  Set Real Time ";
uchar code table5[]="  Set Open Time ";
uchar code table6[]="   Start Time:  ";
uchar code table7[]="    00:00:00    ";
uchar code table8[]="    End Time:   ";
uchar code table9[]="Date: 2000/00/00";
uchar code table0[]="Time: 00:00:00 0";

bit Adjust;			  //调节标志位,=1表示进入调节模式,=0是正常模式
bit Auto_flg;		  //自动模式标志位,=1表示手动模式,=0是自动模式
sbit rs=P2^7;		  //LCD1602
// sbit rw=P1^1; 		  //LCD1602
sbit e=P2^6;		  //LCD1602
sbit sck=P2^0;		  //时钟端口
sbit io=P2^1;		  //时钟端口
sbit rst=P2^2;		  //时钟端口
sbit SELT =P1^6;	  //选择键
sbit ENTER=P1^7;	  //确认键
sbit UP   =P3^0;	  //加键
sbit DOWN =P3^1;	  //减键
sbit MODE =P3^2;	  //切换按键接口
sbit SWITCH=P3^3;	  //手动开关
sbit AUTO_LED=P2^4;	  //自动模式灯接口
sbit HAND_LED=P2^3;	  //手动灯接口
sbit LAMP1=P3^4;	  //灯接口
sbit LAMP2=P3^5;	  //灯接口
sbit LAMP3=P3^6;	  //灯接口
sbit LAMP4=P3^7;	  //灯接口
sbit LIGHT1=P1^0;	  //光线检测端口
sbit IN1=P1^1;
sbit OUT1=P1^2;
sbit DQ=P1^5;		  //温度数据口
uchar Select_num;	  //选择按键按下次数
uchar Enter_num;	  //确认按键按下次数
uchar Switch_num;	  //手动开关按键按下次数
float Year,Month,Day,Hour,Minute,Second;			//时间设置值
uchar Week;		
float Hour_H,Minute_H,Second_H;  					//设置开始时间
float Hour_L,Minute_L,Second_L;  					//设置结束时间
int Value1;											//人数
uchar IN1_flag=0;
uchar OUT1_flag=0;
uint Count;           //T0定时器中断计数次数
uchar Miao;

int temperature;									//全局变量 温度

void read_rtc();

/**************************************************LCD1602显示*******************************************************************/
void delay1(uint z)			  //延时函数
{
	uint x,y;
	for(x=z;x>0;x--)
		for(y=10;y>0;y--);
}

void write_com(uchar com)			 //写指令函数
{
	//rw=0;
	delay1(5);
	rs=0;
	delay1(5);
	e=1;
	delay1(5);
	P0=com;
	delay1(5);
	e=0;
	delay1(5);	
}

void write_date(uchar date)			//写数据函数
{									
	//rw=0;
	delay1(5);
	rs=1;
	delay1(5);
	e=1;
	delay1(5);
	P0=date;
	delay1(5);
	e=0;
	delay1(5);	
}

void init()						    //初始化函数
{	
	uchar num;
	Year=17;
	Month=1;
	Day=1;
	Hour=15;
	Minute=30;
	Second=50;
	Week=1;
	Hour_H=22;
	Minute_H=0;
	Second_H=0;
	Hour_L=18;
	Minute_L=0;
	Second_L=0;
	e=0;						    // 时序表e初始为0
	write_com(0x38);		        //设置16*2显示,5*7点阵,8位数据接口
	write_com(0x0c);				//设置光标
	write_com(0x06);				//光标自动加1,光标输入方式
	write_com(0x01);				//清屏
	write_com(0x80);				//设置初始显示位置
	for(num=0;num<16;num++)
	{
		write_date(table1[num]);
		delay1(5);
	}
	write_com(0x80+0x40);
	for(num=0;num<16;num++)
	{
		write_date(table2[num]);
		delay1(5);
	}					  
}

void SetTime_dispaly(uchar add,uchar dat)	 //第一个:参数的地址,第二个:参数的内容
{
	uchar shi,ge;
	shi=dat/10;							//把十位提取出来
	ge=dat%10;							//把个位提取出来
	write_com(add);			   	 		//要写的地址
	write_date(0x30+shi);				//十位的内容   1602字符库
	write_date(0x30+ge);				//个位的内容   1602字符库
}

void Week_dispaly(uchar add,uchar dat)	//第一个:参数的地址,第二个:参数的内容
{
	write_com(add);						//要写的地址
	if (dat == 0)
    {
        write_date(0x30+7);				//十位的内容   1602字符库
    }
    else
    {
        write_date(0x30+dat);				//十位的内容   1602字符库
    }
    
}
void Date_dispaly(uchar add,uchar dat)	 //第一个:参数的地址,第二个:参数的内容
{
	uchar shi,ge;
	shi=dat/16;							//把十位提取出来
	ge=dat%16;							//把个位提取出来
	write_com(add+3);			   	 	//要写的地址
	write_date(0x30+shi);				//十位的内容   1602字符库
	write_date(0x30+ge);				//个位的内容   1602字符库				   
}

void LCD_Clean(uchar i)					//液晶屏清除显示
{
	uchar num;
	if(i==1)
	{
		write_com(0x80);				//设置初始显示位置
		for(num=0;num<16;num++)			//显示第一行内容
		{
			write_date(table3[num]);
			delay1(1);
		}
	}
	if(i==2)
	{
		write_com(0x80+0x40);
		for(num=0;num<16;num++)			//显示第二行内容
		{
			write_date(table3[num]);
			delay1(1);
		}
	}
}

void LCD_Display_String(unsigned char line,unsigned char *string)
{ 										//液晶屏显示内容,把要显示的内容写到对应的位置
	unsigned char i;
	unsigned char address=0;
	if(line==1)
	{
		address=0x80;	 				//0X80是第1行的第1个位置  ,0x81第2位
	}
	else if(line==2)
	{
		address=0x80+0x40;  			//0X80+0x40是第2行的第1个位置  ,0X80+0x40+1是第2行第2位
	}
	
	for(i=0;i<16;i++)
	{
		write_com(address);
		write_date(string[i]);
		address++;
	} 
}
/**********************************DS1302时钟***************************************/
void Time_Display(void)
{
	read_rtc();
	Date_dispaly(0x80+0x40+9,time_data[6]);  //显示秒
	Date_dispaly(0x80+0x40+6,time_data[5]);	 //显示分
	Date_dispaly(0x80+0x40+3,time_data[4]);	 //显示时
	Date_dispaly(0x80+11,time_data[3]);		 //显示日
	Date_dispaly(0x80+8,time_data[2]);		 //显示月
	Week_dispaly(0x80+0x40+15,time_data[1]-1); //显示周
	Date_dispaly(0x80+5,time_data[0]);		 //显示年
					   //	Year/10*16+Year%10
	Hour=time_data[4]/16*10+time_data[4]%16;;
	Minute=time_data[5]/16*10+time_data[5]%16;;
	Second=time_data[6]/16*10+time_data[6]%16;;
}


void write_ds1302_byte(uchar dat)
{
	uchar i;
	for(i=0;i<8;i++)
	{
		sck=0;
		io=dat&0x01;					   //准备数据,从最低位开始
		dat=dat>>1;
		sck=1;
	}
}

void write_ds1302(uchar add,uchar dat)
{
	rst=0;
	_nop_();  						//CPU原地踏步
	sck=0;
	_nop_();
	rst=1;
	_nop_();
	write_ds1302_byte(add);		    //传地址
	write_ds1302_byte(dat);		    //传数据
	rst=0;     						//不受其他影响
	_nop_();
	io=1;						   //释放
	sck=1;
}

uchar read_ds1302(uchar add)
{
	uchar i,value;
	rst=0;
	_nop_();  //CPU原地踏步
	sck=0;
	_nop_();
	rst=1;
	_nop_();
	write_ds1302_byte(add);
	for(i=0;i<8;i++)
	{
		value=value>>1;
		sck=0;
		if(io)
		value=value|0x80;
		sck=1;
	}
	rst=0;
	_nop_();
	sck=0;
	_nop_();
	sck=1;
	io=1;
	return value;
}

void set_rtc()			          //设置时间
{
	uchar i,j;
	for(i=0;i<7;i++)			 //转换BCD码
	{
		j=time_data[i]/10;
		time_data[i]=time_data[i]%10;
		time_data[i]=time_data[i]+j*16;
	}
	write_ds1302(0x8e,0x00);	  //去除写保护
	for(i=0;i<7;i++)
	{
		write_ds1302(write_add[i],time_data[i]);
	}
	write_ds1302(0x8e,0x80);      //加写保护
}

void read_rtc()
{
	uchar i;
	for(i=0;i<7;i++)
	{
		time_data[i]=read_ds1302(read_add[i]);	//最终读出来的数 16进制
	}
    Year=time_data[0]/16*10+time_data[0]%16;
	Month=time_data[2]/16*10+time_data[2]%16;
	Day=time_data[3]/16*10+time_data[3]%16;
	Hour=time_data[4]/16*10+time_data[4]%16;
	Minute=time_data[5]/16*10+time_data[5]%16;
	Second=time_data[6]/16*10+time_data[6]%16;
	Week=time_data[1]/16*10+time_data[1]%16-1;
    if (Week == 0)
    {
        Week = 7;
    }
}

/*************************************************按键****************************************************************/
void Keyscan(void)
{
	if(SELT==0)
	{
		delay1(2);
		if(SELT==0)
		{
			while(!SELT);
			Select_num++;					//选择键按下一次
			Adjust=1;						//进入调节模式			
		}
		if(Select_num==1)
		{
			LCD_Clean(1);
			LCD_Clean(2);
			LCD_Display_String(1,table4);
			LCD_Display_String(2,table5);
			write_com(0x80+0);				//写 >>
			write_date(0x3e);
			write_com(0x80+1);				//写 >>
			write_date(0x3e);
			Enter_num=0;
		}
		if(Select_num==2)
		{
			LCD_Clean(1);
			LCD_Clean(2);
			LCD_Display_String(1,table4);
			LCD_Display_String(2,table5);
			write_com(0x80+0x40+0);				//写 >>
			write_date(0x3e);
			write_com(0x80+0x40+1);				//写 >>
			write_date(0x3e);
			Enter_num=0;
		}
		if(Select_num==3)
		{
			LCD_Clean(1);
			LCD_Clean(2);
			LCD_Display_String(1,table1);
			LCD_Display_String(2,table2);
			Select_num=0;
			Enter_num=0;					
			Adjust=0;
		}
		write_com(0x0c);									//光标不再闪烁
		Enter_num=0;
	}
	
	if(ENTER==0)
	{
		delay1(2);
		if(ENTER==0)
		{
			while(!ENTER);
			Enter_num++;
		}
		if(Select_num==1)					//设置实时时间
		{
			if(Enter_num==1)
			{
				LCD_Clean(1);
				LCD_Clean(2);
				LCD_Display_String(1,table9);
				LCD_Display_String(2,table0);
				SetTime_dispaly(0x80+8,Year);
				SetTime_dispaly(0x80+11,Month);
				SetTime_dispaly(0x80+14,Day);
				SetTime_dispaly(0x80+0x40+6,Hour);
				SetTime_dispaly(0x80+0x40+9,Minute);
				SetTime_dispaly(0x80+0x40+12,Second);
				Week_dispaly(0x80+0x40+15,Week);
				write_com(0x80+8);			//光标闪烁地址,停留在年的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==2)
			{
				write_com(0x80+11);			//光标闪烁地址,停留在月的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==3)
			{
				write_com(0x80+14);			//光标闪烁地址,停留在日的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==4)
			{
				write_com(0x80+0x40+6);		//光标闪烁地址,停留在时的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==5)
			{
				write_com(0x80+0x40+9);		//光标闪烁地址,停留在分的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==6)
			{
				write_com(0x80+0x40+12);	//光标闪烁地址,停留在秒的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==7)
			{
				write_com(0x80+0x40+15);	//光标闪烁地址,停留在星期的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==8)
			{
				Enter_num=0;
				write_com(0x0c);			//光标不再闪烁
				LCD_Clean(1);
				LCD_Clean(2);
				LCD_Display_String(1,table1);
				LCD_Display_String(2,table2);
				time_data[0]=Year;///10*16+Year%10;
				time_data[1]=Week+1;///10*16+Week%10;
				time_data[2]=Month;///10*16+Month%10;
				time_data[3]=Day;///10*16+Day%10;
				time_data[4]=Hour;///10*16+Hour%10;
				time_data[5]=Minute;///10*16+Minute%10;
				time_data[6]=Second;///10*16+Second%10;
				set_rtc();					 //设置时间
				Select_num=0;
				Adjust=0;
			}
		}

		if(Select_num==2)					//设置开关锁时间
		{
			if(Enter_num==1)
			{
				LCD_Clean(1);
				LCD_Clean(2);
				LCD_Display_String(1,table6);
				LCD_Display_String(2,table7);
				SetTime_dispaly(0x80+0x40+4,Hour_L);
				SetTime_dispaly(0x80+0x40+7,Minute_L);
				SetTime_dispaly(0x80+0x40+10,Second_L);
				write_com(0x80+0x40+4);		//光标闪烁地址,停留在时的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==2)
			{
				write_com(0x80+0x40+7);		//光标闪烁地址,停留在分的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==3)
			{
				write_com(0x80+0x40+10);	//光标闪烁地址,停留在秒的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==4)
			{
				write_com(0x0c);			//光标不再闪烁
				LCD_Clean(1);
				LCD_Clean(2);
				LCD_Display_String(1,table8);
				LCD_Display_String(2,table7);	
				SetTime_dispaly(0x80+0x40+4,Hour_H);
				SetTime_dispaly(0x80+0x40+7,Minute_H);
				SetTime_dispaly(0x80+0x40+10,Second_H);
				write_com(0x80+0x40+4);		//光标闪烁地址,停留在时的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==5)
			{
				write_com(0x80+0x40+7);		//光标闪烁地址,停留在分的位置上					
				write_com(0x0f);			//光标闪烁
			}
			if(Enter_num==6)
			{
				write_com(0x80+0x40+10);	//光标闪烁地址,停留在秒的位置上					
				write_com(0x0f);			//光标闪烁
			}		
			if(Enter_num==7)
			{
				Enter_num=0;
				write_com(0x0c);			//光标不再闪烁
				LCD_Clean(1);
				LCD_Clean(2);
				LCD_Display_String(1,table1);
				LCD_Display_String(2,table2);
				Select_num=0;
				Adjust=0;
			}
		}

	}

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值