蓝桥杯单片机第三届国赛题目-门禁系统
2021-05-24 21:42
99 查看
文章目录
题目
文件树
代码
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 <reg52.h> #include <intrins.h> #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
要点
- 在于io打开后定时关闭,这个问题需要自己总结一个写法,在比赛中很多时候需要你,打开蜂鸣器后,延时3s然后关闭蜂鸣器;
- 第二个是一个技巧,节省变量,比如这里我使用数码管的显示来判断当前输入是什么状态
- 使用指针来判断数据相同
- 使用此函数来返回数据的位数
比如:
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
- 连续写和连续读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(); }
注意
相关文章推荐
- 【蓝桥杯单片机的备赛旅行日记系列】之国赛决赛第三届门禁系统
- 蓝桥杯第四届单片机国赛--超声波测距报警实时时钟
- 第四届蓝桥杯单片机国赛试题及程序
- 第三届蓝桥杯JAVA组C组国赛题解
- 两道相似题目的思考(蓝桥杯 第三届第四题/第五届第三题)
- 2012年第三届蓝桥杯全国软件大赛c++预赛 题目及参考答案
- CCF题目:门禁系统
- 2012年第三届蓝桥杯(C/C++)预赛题目及个人答案(欢迎指正)
- 单片机STC12C5A60S2_RFID_RC522_OLED_门禁系统_菜单设计
- 蓝桥杯单片机第4届省赛_模拟智能灌溉系统
- 【蓝桥杯单片机的备赛旅行日记系列】之国赛决赛第五届多功能事件记录器
- 蓝桥杯单片机第三届初赛程序设计——“自动售水机”设计任务书
- 2012年第三届蓝桥杯全国软件大赛c++预赛 题目及参考答案
- 【蓝桥杯单片机的备赛旅行日记系列】之国赛决赛第四届超声波测距报警实时时钟电路
- 基于15单片机模拟智能灌溉系统——蓝桥杯
- 2012第三届蓝桥杯C语言本科决赛题目
- 第三届蓝桥杯JAVA组B组国赛题解
- 第四届“蓝桥杯”全国软件专业人才设计与创业大赛选拔赛C/C++本科A组(题目及代码)
- 蓝桥杯单片机独立按键扫描程序
- 第三届蓝桥杯预赛真题 Java高职第九题-- 密码发生器