蓝桥杯单片机第三届国赛题目-门禁系统

文章目录

  • 题目
  • 文件树
  • 代码
    • init.c
    • main.c
    • ds1302.c
    • iic.c
    • type.h
    • ds1302.h
    • iic.h
  • 要点

题目

文件树

蓝桥杯单片机第三届国赛题目-门禁系统_第1张图片

代码

init.c

#include "init.h"

code uchar table[][4] = {
     0, 1, 1, 1,
						 1, 0, 1, 1,
	                     1, 1, 0, 1,  
						 1, 1, 1, 0};
extern uchar buffer[8];
extern uint distance;
void SL(uchar _device, uchar _data){
     
	P0 = _data; SEL(_device);
}

void Timer1Init(void)		//2毫秒@12.000MHz
{
     
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x40;		//设置定时初值
	TH1 = 0xA2;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;
	EA = 1;
}

uchar GetKey(){
     
	uchar i;
	C1 = 1; C2 = 1; C3 = 1; C4 = 1;
	for(i = 0; i < 4; i++){
     
		R1 = table[i][0]; R2 = table[i][1];
		R3 = table[i][2]; R4 = table[i][3];
		if(C1 == 0) return 1 + i*4;
		if(C2 == 0) return 2 + i*4;
		if(C3 == 0) return 3 + i*4;
		if(C4 == 0) return 4 + i*4;
	}
	return 0;
}
uchar FR(float _data, uchar _dig){
     
	uint m = 1;
	while(_dig--){
     
		m = m * 10;
	}
	return (uint)_data/m%10;
}
void Bf(uchar _0, uchar _1, uchar _2, uchar _3,
								uchar _4, uchar _5, uchar _6, uchar _7){
     
	buffer[0] = _0; buffer[1] = _1; buffer[2] = _2; buffer[3] = _3;
	buffer[4] = _4; buffer[5] = _5; buffer[6] = _6; buffer[7] = _7;
}
								
void TimeRun(t_delay* time){
     
	if(time->cnt++ < time->max);
	else{
     
		time->cnt = 0;
		time->ok = 1;
	}
}

void Delay14us()		//@12.000MHz
{
     
	unsigned char i;

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

void Sonic_Start(){
     
	uchar cnt = 10;
	while(cnt--){
     
		ST = 1;
		Delay14us();
		ST = 0;
		Delay14us();
	}
}
void Sonic(){
     
	uint time;
	CH = 0; CL = 0; CR = 1;
	Sonic_Start();
	while((SR) && (CF == 0));
	CR = 0;
	if(CF){
     CF = 0; distance = 9999;}
	else{
     
		time = ((uint)CH<<8) | CL;
		distance = time*0.017/12;
	}
}
uchar Check(uchar* p1, uchar* p2){
     
	uchar i;
	for(i = 0; i < 6; i++){
     
		if(*p1 != *p2){
     return 0;}
		else{
     
			p1++; p2++;
		}
	}
	return 1;
}
void Copy(uchar* p1, uchar* p2){
     
	uchar i;
	for(i = 0; i < 6; i++){
     
		*p2 = *p1;
		p1++; p2++;
	}
}

main.c

#include "init.h"
code uchar CA[] = {
     0xc0, 0xf9, 0xa4, 0xb0, 0x99,\
				   0x92, 0x82, 0xf8, 0x80, 0x90,\
				   0xff, 0xbf
};
uchar buffer[] = {
     F_SEP, F_SEP, F_C, F_C, F_C, F_C, F_C, F_C};
uchar curDig = 0;
code enum{
     LED = 4, EXT, SEL, CODE};
code uchar clear[] = {
     F_C, F_C, F_C, F_C, F_C, F_C};
enum{
     KS_GT, KS_AS, KS_WA}keyState = KS_GT;
uchar key, tmpKey, keyCnt;
t_delay delay_200 = {
     200 ,0, 0};
t_delay delay_500 = {
     500 ,0, 0};
t_delay delay_Beep = {
     1500 ,0, 0};
t_delay delay_Relay = {
     2500 ,0, 0};
uint distance;
uchar time[3];
enum{
     S_AUTO, S_CODE}gloSta = S_CODE;
uchar sonicEnable = 0;
uchar codeCnt = 0;
uchar errorCnt = 0;
bit codeOk = 0;
bit beepEnable = 0; 
bit relayEnable = 0;
uchar codedata[] = {
     6,5,4,3,2,1};


void Timer1Hanle() interrupt 3{
     
	SL(CODE, 0xff); SL(SEL, 1 << curDig); SL(CODE, CA[buffer[curDig]]);
	curDig = (curDig + 1)%8;
	switch(keyState){
     
		case KS_GT:
			    keyCnt = 0;tmpKey = GetKey();keyState = KS_AS;
		break;
		
		case KS_AS:
				if(keyCnt++ < 10);
				else if(tmpKey == GetKey()){
     
					if(tmpKey != key){
     
						key = tmpKey;keyState = KS_WA;
					}
					else{
     
						keyState = KS_GT;
					}
				}
				else{
     
					keyState = KS_GT;
				}
		break;
	}
	TimeRun(&delay_200);
	TimeRun(&delay_500);
	if(delay_Beep.ok == -1)
	TimeRun(&delay_Beep);
	if(delay_Relay.ok == -1)
	TimeRun(&delay_Relay);
}

void Sensor(){
     
	if(delay_200.ok){
     
		delay_200.ok = 0;
		if(sonicEnable)
			Sonic();
			//如果小于30cm并且继电器没有开启并且在自动门模式则开启继电器
			if((distance < 30) && (delay_Relay.ok != -1) && (gloSta == S_AUTO)){
     
				RLON;
				delay_Relay.ok = -1;
			}
		DS1302_Read();
		//通过时间判断处于哪个模式
		if((time[0] == 0) && (time[1] == 0) && time[2] == 7){
     
			gloSta = S_AUTO;
			sonicEnable = 1;
		}
		if((time[0] == 0) && (time[1] == 0) && time[2] == 22){
     
			gloSta = S_CODE;
			sonicEnable = 0;
		}
		//如果是自动模式,则显示时间
		if(gloSta == S_AUTO){
     
		Bf(FR(time[2],1),FR(time[2],0),F_SEP,
		   FR(time[1],1),FR(time[1],0),F_SEP,
		   FR(time[0],1),FR(time[0],0));
		}
	}
	if(delay_Beep.ok == 1){
     
		delay_Beep.ok = 0;
		BPOFF;RLOFF;
	}	
	if(delay_Relay.ok == 1){
     
		delay_Relay.ok = 0;
		RLOFF;
	}		
}
void main(){
     
		BPOFF; RLOFF;
		SL(LED, 0xff);
		Timer1Init();
		CMOD |= 0x08;
		DS1302_init(06, 59, 00);
		CODE_Read(0, &codedata[0]);
  while(1){
     
			Sensor();
			if(keyState == KS_WA){
     
				//如果是手动密码模式
				if(gloSta == S_CODE){
     
					//如果按键处于0-9之间
					if(key < 11 && key > 0){
     
						//如果小于六位,则每次将按键值显示,并且按键计数+1
						if(codeCnt < 6){
     
							buffer[codeCnt+2] = key - 1;
							codeCnt++;
						}	
					}
					//设置按键
					else if(key == 11){
     
						if(WAITINPUT){
     
							//进入输入旧密码界面
							Copy(&clear[0],&buffer[2]);
							buffer[0] = F_C;
							codeCnt = 0;
							errorCnt = 0;
						}
					}
					//如果是确认按键
					else if(key == 15){
     
						//如果是等待输入,则确认按键是确认当前输入密码
						if(WAITINPUT){
     
							//检查密码是否正确
							if(Check(&buffer[2], &codedata[0])){
     
								//如果正确,打开继电器
								RLON;
								delay_Relay.ok = -1;
								errorCnt = 0;
							}
							//如果错误
							else{
     
									//如果错误次数小于3,错误次数+1
									if(errorCnt < 3){
     
										errorCnt++;
									}
									//否则响起蜂鸣器
									else{
     
										errorCnt = 0;
										BPON;RLOFF;
										delay_Beep.ok = 1;
								}
							}
						}
						//如果是输入旧密码界面
						else if(OLDCODE){
     
							//检查密码是否正确
							if(Check(&buffer[2], &codedata[0])){
     
								//如果正确,进入输入新密码状态
									buffer[0] = F_SEP;buffer[1] = F_C;
									codeCnt = 0;
									errorCnt = 0;
							}
							//如果错误
							else{
     
									//如果错误次数小于3,错误次数+1
									if(errorCnt < 3){
     
										errorCnt++;
									}
									//否则响起蜂鸣器,!并且退出修改密码功能
									else{
     
										errorCnt = 0;
										BPON;RLOFF;
										delay_Beep.ok = 1;
										buffer[0] = F_SEP;buffer[1] = F_SEP;
										codeCnt = 0;
								}
							}
						}
						//如果是输入新密码界面
						else if(NEWCODE){
     
							//检查密码是否为6位
							if(codeCnt == 6){
     
								Copy(&buffer[2], &codedata[0]);
								buffer[0] = F_SEP;buffer[1] = F_SEP;
								codeCnt = 0;
								errorCnt = 0;
							//这里我发现写一次有问题,我就重复写三次了
								CODE_Write(0,&codedata[0]);
								CODE_Write(0,&codedata[0]);
								CODE_Write(0,&codedata[0]);
							}
						}
						//不管哪种情况按下确认按键后,都会清空密码
							Copy(&clear[0], &buffer[2]);
							codeCnt = 0;
						}
					//复位按键
					else if(key == 12){
     
						uchar defaultcode[] = {
     6,5,4,3,2,1};
						Copy(&defaultcode[0], &codedata[0]);
					//这里我发现写一次有问题,我就重复写三次了
						CODE_Write(0,&codedata[0]);
						CODE_Write(0,&codedata[0]);
						CODE_Write(0,&codedata[0]);
					}
					//退出按键
					else if(key == 16){
     
						if((OLDCODE) || (NEWCODE)){
     
							errorCnt = 0;
							buffer[0] = F_SEP;buffer[1] = F_SEP;
							codeCnt = 0;
							Copy(&clear[0],&buffer[2]);
						}
					}
				}
				keyState = KS_GT;
			}
		}
}

ds1302.c

/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include 
#include 
#include "type.h"
sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位												
extern uchar time[3];
void Write_Ds1302(unsigned  char temp) 
{
     
	unsigned char i;
	for (i=0;i<8;i++)     	
	{
      
		SCK=0;
		SDA=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
     
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}
uchar Read(){
     
	 unsigned char i,temp=0x00;
 	for (i=0;i<8;i++){
     		
			SCK=0;
			temp>>=1;	
			if(SDA)
				temp|=0x80;	
				SCK=1;
	}
	return (temp);		
}
void DS1302_init(uchar _h, uchar _m, uchar _s){
     
	uchar i;
	_h = (_h/10%10 << 4) | _h%10;
	_m = (_m/10%10 << 4) | _m%10;
	_s = (_s/10%10 << 4) | _s%10;
	Write_Ds1302_Byte(0x8e, 0);
	RST=0;	_nop_();
	SCK=0;	_nop_();
	RST=1; 	_nop_();
	Write_Ds1302(0xbe);
	Write_Ds1302(_s);	
	Write_Ds1302(_m);	
	Write_Ds1302(_h);	
	for(i = 0; i < 5; i++){
     
		Write_Ds1302(0);	
	}
	RST=0;
	Write_Ds1302_Byte(0x8e, 0x80);
}
void DS1302_Read(){
     
		Write_Ds1302_Byte(0x8e, 0);
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(0xbf);
  time[0] = Read();
		time[1] = Read();
		time[2] = Read();
		time[0] = (time[0] >> 4)*10 + (time[0] & 0x0f);
		time[1] = (time[1] >> 4)*10 + (time[1] & 0x0f);
		time[2] = (time[2] >> 4)*10 + (time[2] & 0x0f);
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
		SCK=1;	_nop_();
		SDA=0;	_nop_();
		SDA=1;	_nop_();
		Write_Ds1302_Byte(0x8e, 0x80);
}

iic.c

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"
#include "type.h"
#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
uint IICVal;
//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
     
    do{
     _nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
     
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
     
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
     
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
     
    bit ackbit;
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
     
    unsigned char i;

    for(i=0; i<8; i++)
    {
     
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
     
    unsigned char i, da;
    for(i=0; i<8; i++)
    {
        
					SCL = 1;
					IIC_Delay(DELAY_TIME);
					da <<= 1;
					if(SDA) da |= 1;
					SCL = 0;
					IIC_Delay(DELAY_TIME);
    }
    return da;    
}
void Delay1ms()		//@12.000MHz
{
     
	unsigned char i, j;

	i = 47;
	j = 174;
	do
	{
     
		while (--j);
	} while (--i);
}

void CODE_Write(uchar _addr, uchar* _data){
     
	uchar i = 6;
	IIC_Start();
	IIC_SendByte(0xA0);
	IIC_WaitAck();
	IIC_SendByte(_addr*6);
	IIC_WaitAck();
	while(i--){
     
		IIC_SendByte(*_data);
		_data++;
		IIC_WaitAck();
	}
	IIC_Stop();
	//加个延时很重要
	Delay1ms();
}
void CODE_Read(uchar _addr, uchar *_des){
     
	uchar i = 6;
	IIC_Start();
	IIC_SendByte(0xA0);
	IIC_WaitAck();
	IIC_SendByte(_addr*6);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0xA1);
	IIC_WaitAck();
	while(i--){
     
		*_des = IIC_RecByte();
		_des++;
		IIC_SendAck(0);
	}
	IIC_Stop();
}

type.h

#ifndef _TYPE_H
#define _TYPE_H
#define uchar unsigned char
#define uint unsigned int
#endif

ds1302.h

#ifndef __DS1302_H
#define __DS1302_H

void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
void DS1302_Read();
void DS1302_init(uchar _h, uchar _m, uchar _s);
#endif

iic.h

#ifndef _IIC_H
#define _IIC_H
extern uint IICVal;
void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 
void IIC_Write(uchar _addr, uint _data);
void IIC_Read(uchar _addr);
void CODE_Write(uchar _addr, uchar* _data);
void CODE_Read(uchar _addr, uchar *_des);
#endif

要点

  1. 在于io打开后定时关闭,这个问题需要自己总结一个写法,在比赛中很多时候需要你,打开蜂鸣器后,延时3s然后关闭蜂鸣器;
  2. 第二个是一个技巧,节省变量,比如这里我使用数码管的显示来判断当前输入是什么状态
    在这里插入图片描述
  3. 使用指针来判断数据相同
    蓝桥杯单片机第三届国赛题目-门禁系统_第2张图片
  4. 使用此函数来返回数据的位数
    蓝桥杯单片机第三届国赛题目-门禁系统_第3张图片
    比如:
uchar a = 123;
FR(a,2)就等于1
FR(a,1)就等于2
FR(a,0)就等于3
//这里输入类型_data标识为float是为了适应uchar , uint以及float三种变量,它们都可以通过这一个函数来进行位数的返回
float a = 456.22;
FR(a,2)就等于4
FR(a,1)就等于5
FR(a,0)就等于6
  1. 连续写和连续读iic
void CODE_Write(uchar _addr, uchar* _data){
     
	uchar i = 6;
	IIC_Start();
	IIC_SendByte(0xA0);
	IIC_WaitAck();
	IIC_SendByte(_addr*6);
	IIC_WaitAck();
	while(i--){
     
		IIC_SendByte(*_data);
		_data++;
		IIC_WaitAck();
	}
	IIC_Stop();
	//加个延时很重要
	Delay1ms();
}
void CODE_Read(uchar _addr, uchar *_des){
     
	uchar i = 6;
	IIC_Start();
	IIC_SendByte(0xA0);
	IIC_WaitAck();
	IIC_SendByte(_addr*6);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0xA1);
	IIC_WaitAck();
	while(i--){
     
		*_des = IIC_RecByte();
		_des++;
		IIC_SendAck(0);
	}
	IIC_Stop();
}

注意
蓝桥杯单片机第三届国赛题目-门禁系统_第4张图片

你可能感兴趣的:(蓝桥杯单片机,蓝桥杯,单片机,第三届国赛,门禁系统)