蓝桥杯单片机第三届国赛:门禁系统

本次使用到的模块大概有:超声波测距、EEPROM读和写、时钟DS1302、矩阵键盘、数码管显示

这一届国赛感觉不是特别难,但是还是有几点需要注意:

        1.不要把超声波程序写在中断里面。如果把超声波程序写在中断里面的话,可能就不会及时的检测到溢出标志,在我开始验证代码的时候出现的现象是最后一个数码管闪烁,然后把超声波写在主函数里面就解决了问题。

        2.程序里面经常调用的代码,写在函数里面,会大大减少代码量和重复代码,并且利于检查以及代码美观。如写EEPROM和读EEPROM可以专门写在函数里面,在我们要修改的时候直接调用函数传递一个参数进去就行了,也比如我们在输入密码的时候,计算密码这一重复的工作,可以直接写在函数里面,这样我们在检测到按键的时候,就可以直接调用函数,不需要每一次都在里面计算。


本次用到的模块:

    超声波测距:

  超声波测距发射8个脉冲函数以及延时13us函数

void Delay13us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 33;
	while (--i);
}
void sonic_send(void)
{
	u8 i = 8;
	while( i-- )
	{
		TX = 1;
		Delay13us();
		TX = 0;
		Delay13us();
	}
}

超声波函数:

TR0 = 0;
sonic_send();
TR0 = 1;
while(RX == 1 && TF0 == 0 );
TR0 = 0;
if(TF0 == 1)
{
	TF0 = 0;
	distance = 999;
}
else
{
	distance = TH0;
	distance = (distance<<8)|TL0;
	distance = (u16)(distance*0.00153718);
}
TH0 = 0;
TL0 = 0;

DS1302初始化时间以及读取时间函数:

void DS1302_INIT(void)
{
	unsigned char i,add = 0x80;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i = 0;i < 7 ; i++)
	{
		Write_Ds1302_Byte(add,Time[i]);
		add += 2;
	}
	Write_Ds1302_Byte(0x8e,0x80);
}
void DS1302_GET(void)
{
	unsigned char i,add = 0x81;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i = 0;i < 7 ; i++)
	{
		Time[i] = Read_Ds1302_Byte(add);
		add += 2;
	}
	Write_Ds1302_Byte(0x8e,0x80);
}

写EEPROM函数和读EEPROM函数

void Write_AT24C02(unsigned char add,unsigned char dat)
{
	IIC_Start();
	IIC_SendByte(0XA0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}
unsigned char Read_AT24C02(unsigned char add)
{
	unsigned char temp;
	IIC_Start();
	IIC_SendByte(0XA0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0XA1);
	IIC_WaitAck();
	temp = IIC_RecByte();
	IIC_WaitAck();
	
	return temp;
}

完整代码:

#include <STC15F2K60S2.h>
#include <intrins.h>
#include "iic.h"
#include "ds1302.h"

#define u8 unsigned char
#define u16 unsigned int
	
u8 code LED[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
u8 KEY_TEMP,KEY = 0XFF;
u8 Digcom = 0, Digbuf[] = {1,2,3,4,10,10,10,10};
sbit RX = P1^1;
sbit TX = P1^0;
u16 distance = 999,T = 0,T_GATE = 0,password = 0;
u8 Tmeasure = 0,intr = 0,shezhi = 0,error = 0;
bit flag = 0,KEY_FLAG = 0,GATE_FLAG = 0;
bit flag1 = 0,flag2 = 0,flag3 = 0,flag4 = 0,zidong = 1;
u8 yi = 10,er = 10,san = 11,si = 11,wu = 11,liu = 11,qi = 11,ba = 11;
u16 DELAY_TIME;
extern u8 Time[];

void Delay13us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 33;
	while (--i);
}

void delay_ms(u16 ms)
{
	u16 i,j;
	for(i = ms; i>0 ; i--)
		for(j = 845; j > 0 ; j--);
}
void INIT(void)
{
	P2 |= 0X80;
	P2 &= 0X9F;
	P0 = 0XFF;
	
	P2 |= 0XA0;
	P2 &= 0XBF;
	P0 = 0X00;
	
	P2 |= 0XC0;
	P2 &= 0XDF;
	P0 = 0XFF;
	P2 |= 0XE0;
	P2 &= 0XFF;
	P0 = 0XFF;
}
void Relay_ON(void)
{
	P2 |= 0XA0;
	P2 &= 0XBF;
	P0 = 0X10;
}
void OFF(void)	//关掉蜂鸣器和继电器
{
	P2 |= 0XA0;
	P2 &= 0XBF;
	P0 = 0X00;
}
void Buzz_ON(void)
{
	P2 |= 0XA0;
	P2 &= 0XBF;
	P0 = 0X40;
}
void Get_Password(u8 temp)
{
	if(intr <= 6)password = password*10 + temp;
	
	if(intr == 1) san = temp;
	else if(intr == 2)	si = temp;
	else if(intr == 3)	wu = temp;
	else if(intr == 4)	liu = temp;
	else if(intr == 5)	qi = temp;
	else if(intr == 6)	ba = temp;
}
u16 Read_Password()
{
	u16 temp;
	temp = Read_AT24C02(0XA0);
	temp = temp*100;
	temp += Read_AT24C02(0XA1);
	temp = temp*100;
	temp += Read_AT24C02(0XA2);
	return temp;
}
void Write_Password(u16 temp)
{
	Write_AT24C02(0XA0,temp/10000);delay_ms(5);
	Write_AT24C02(0XA1,temp/100%100);delay_ms(5);
	Write_AT24C02(0XA2,temp%100);delay_ms(5);
}
void KEY_KBD(void)
{
	u16 temp;	//暂时存储当前的密码
	bit zhengque  = 0;
	P3 = 0X7F;P44 = 0;P42 = 1;
	KEY_TEMP = P3 & 0X0F;
	if(KEY_TEMP != 0x0f && flag1 == 0 && zidong == 0) 
	{
		delay_ms(5);
		KEY_TEMP = P3&0X0F;
		if(KEY_TEMP != 0x0f)
		{
			flag1 = 1;
			KEY_TEMP = P3;
			switch(KEY_TEMP)
			{
				case 0x7E:intr++;Get_Password(0);break;
				case 0x7D:intr++;Get_Password(4);break;
				case 0x7B:intr++;Get_Password(8);break;
//				case 0x77:intr++;	qi = 0;ba = 4;break;
			}
		}
	}
	else if(KEY_TEMP == 0x0f && flag1)
	{
		delay_ms(5);
		KEY_TEMP = P3 & 0X0F;
		if(KEY_TEMP == 0x0f)
		{
			flag1 = 0;
		}
	}
	
	P3 = 0XbF;P44 = 1;P42 = 0;
	KEY_TEMP = P3 & 0X0F;
	if(KEY_TEMP != 0x0f && flag2 == 0 && zidong == 0) 
	{
		delay_ms(5);
		KEY_TEMP = P3&0X0F;
		if(KEY_TEMP != 0x0f)
		{
			flag2 = 1;
			KEY_TEMP = P3;
			switch(KEY_TEMP)
			{
				case 0xbE:intr++;Get_Password(1);break;
				case 0xbD:intr++;Get_Password(5);break;
				case 0xbB:intr++;Get_Password(9);break;
//				case 0xb7:qi = 0;ba = 8;break;
			}
		}
	}
	else if(KEY_TEMP == 0x0f && flag2)
	{
		delay_ms(5);
		KEY_TEMP = P3 & 0X0F;
		if(KEY_TEMP == 0x0f)
		{
			flag2 = 0;
		}
	}
	
	P3 = 0XdF;P42 = 1;P44 = 1;
	KEY_TEMP = P3 & 0X0F;
	if(KEY_TEMP != 0x0f && flag3 == 0 && zidong == 0) 
	{
		delay_ms(5);
		KEY_TEMP = P3&0X0F;
		if(KEY_TEMP != 0x0f)
		{
			flag3 = 1;
			KEY_TEMP = P3;
			switch(KEY_TEMP)
			{
				case 0xDE:intr++;Get_Password(2);break;
				case 0xDD:intr++;Get_Password(6);break;
				case 0xDB:	//设置按键
					if(shezhi == 0)shezhi = 1;
					yi = 11;er = 10;san = 11;si = 11;
					wu = 11;liu = 11;qi = 11;ba = 11;
					break;	
				case 0xD7:				//确认按键
					if(shezhi == 0 || shezhi == 1)
					{
						temp = Read_Password();
						if(password == temp) 	//密码正确并且不是设置状态打开继电器
						{
							error = 0;
							zhengque = 1;
							DELAY_TIME = 5000;
							GATE_FLAG = 1;
							Relay_ON();	//打开继电器
							T_GATE = 0;	//从头开始计时5s
						}
						else if(password != temp)		//密码不正确,蜂鸣器报警三秒
						{
							if(++error == 3)
							{
								error = 0;
								DELAY_TIME = 3000;
								GATE_FLAG = 1;
								Buzz_ON();	//打开继电器
								T_GATE = 0;	//从头开始计时3s
							}
						}
					}
					else if(shezhi == 2)
					{
						Write_Password(password);
						
					}
					
					if(shezhi == 0 || shezhi == 2)//密码输入完成,显示密码初始界面
					{
						yi = 10;er = 10;san = 11;si = 11;
						wu = 11;liu = 11;qi = 11;ba = 11;
						if(shezhi == 2)shezhi = 0 ;
					}
					else if(shezhi == 1 && zhengque)
					{
						yi = 10;er = 11;san = 11;si = 11;
						wu = 11;liu = 11;qi = 11;ba = 11;
						shezhi = 2;
					}
					else if(shezhi == 1 && zhengque == 0)
					{
						yi = 11;er = 10;san = 11;si = 11;
						wu = 11;liu = 11;qi = 11;ba = 11;
					}
					password = 0;
					intr = 0;
					break;	//确认按键,表示当前输入完成
			}
		}
	}
	else if(KEY_TEMP == 0x0f && flag3)
	{
		delay_ms(5);
		KEY_TEMP = P3 & 0X0F;
		if(KEY_TEMP == 0x0f)
		{
			flag3 = 0;
		}
	}
	
	P3 = 0XeF;P42 = 1;P44 = 1;
	KEY_TEMP = P3 & 0X0F;
	if(KEY_TEMP != 0x0f && flag4 == 0 && zidong == 0) 
	{
		delay_ms(5);
		KEY_TEMP = P3 & 0X0F;
		if(KEY_TEMP != 0x0f)
		{
			flag4 = 1;
			KEY_TEMP = P3;
			switch(KEY_TEMP)
			{
				case 0xEE:intr++;Get_Password(3);break;
				case 0xED:intr++;Get_Password(7);break;
				case 0xEB:		//复位按键,恢复初始密码654321
					Write_Password(654321);
					intr = 0;
					password = 0;
					break;
				case 0xE7:		//退出按键,显示输入密码状态
					yi = 10;er = 10;san = 11;si = 11;
					wu = 11;liu = 11;qi = 11;ba = 11;
					intr = 0;
					shezhi = 0;
					password = 0;
					break;
			}
		}
	}
	else if(KEY_TEMP == 0x0f && flag4)
	{
		delay_ms(5);
		KEY_TEMP = P3 & 0X0F;
		if(KEY_TEMP == 0x0f)
		{
			flag4 = 0;
		}
	}
}

void sonic_send(void)
{
	u8 i = 8;
	while( i-- )
	{
		TX = 1;
		Delay13us();
		TX = 0;
		Delay13us();
	}
}
void Timer2Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0xCD;		//设置定时初值
	T2H = 0xD4;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	IE2 |= 0X04;
	EA = 1;
}
void timer2(void)interrupt 12
{
//数码管动态显示
	P2 |= 0XC0;
	P2 &= 0XDF;
	P0 = (0X01<<Digcom);
	P2 |= 0xE0;
	P2 &= 0XFF;
	P0 = LED[Digbuf[Digcom]];
	if(++Digcom == 8)	Digcom = 0;
//超声波测距(200毫秒一次)
	if(++Tmeasure == 200 && zidong)	//只有在自动的工作状态下才检测距离
	{
		Tmeasure = 0;
		flag = 1;
	}
//继电器打开5s
	if(++T_GATE == DELAY_TIME && GATE_FLAG)
	{
		GATE_FLAG = 0;
		T_GATE = 0;
		OFF();	//关掉蜂鸣器和继电器
	}
}
void Timer0Init(void)
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x00;		//设置定时初值
	TF0 = 0;		//清除TF0标志
//	TR0 = 1;		//定时器0开始计时
}

void main()
{
	u8 temp;
//初始化外设、定时器、时钟
	INIT();
	Timer2Init();
	Timer0Init();
	DS1302_INIT();
//把初始密码写进EEPROM里面
	Write_Password(654321);
	while(1)
	{
//读取时间		
		DS1302_GET();
		temp = Time[2]/16;
		temp = temp*10 + (Time[2]%16);
		if( temp>=7 && temp < 22 )	zidong = 1;
			else zidong = 0;
//判断工作状态		
		if(zidong)
		{
			Digbuf[0] = Time[2]/16;	Digbuf[1] = Time[2]%16;
			Digbuf[2] = 10;					Digbuf[3] = Time[1]/16;
			Digbuf[4] = Time[1]%16;	Digbuf[5] = 10;
			Digbuf[6] = Time[0]/16;	Digbuf[7] = Time[0]%16;
			if(distance < 30 && GATE_FLAG == 0)		//自动工作状态下,如果距离小于30厘米
			{
				DELAY_TIME = 5000;
				GATE_FLAG = 1;
				Relay_ON();	//打开继电器
				T_GATE = 0;	//从头开始计时5s
			}
			if(flag)
			{	
				flag = 0;
				TR0 = 0;
				sonic_send();
				TR0 = 1;
				while(RX == 1 && TF0 == 0 );
				TR0 = 0;
				if(TF0 == 1)
				{
					TF0 = 0;
					distance = 999;
				}
				else
				{
					distance = TH0;
					distance = (distance<<8)|TL0;
					distance = (u16)(distance*0.00153718);
				}
				TH0 = 0;
				TL0 = 0;
			}
		}
		else
		{
			Digbuf[0] = yi;	Digbuf[1] = er;
			Digbuf[2] = san;	Digbuf[3] = si;
			Digbuf[4] = wu;	Digbuf[5] = liu;
			Digbuf[6] = qi;	Digbuf[7] = ba;
		}
		KEY_KBD();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43715171/article/details/105323533