新人第一篇帖子,基于51单片机的门禁系统(实验),内附proteus作图以及ds1302和1602程。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机原程序如下: - #include<reg51.h>
- /********位定义*********/
- sbit io=P1^5; //ds1302的串行数据I/O口
- sbit clk=P1^6; //ds1302的时钟口
- sbit rst=P1^7; //ds1302的复位口
- sbit acc0=ACC^0; //移位时的第0位
- sbit acc7=ACC^7; //移位时用的第7位
- sbit busy=P0^7; //lcd 忙标志位
- sbit rs=P2^0; //lcd 数据状态位
- sbit rw=P2^1; //lcd 读写控件位
- sbit re=P2^2; //lcd 使能位
- sbit menu=P3^0; //菜单
- sbit inc=P3^1; //加一
- sbit dec=P3^2; //减一
- sbit quit=P3^3; //退出
- /************全局变量***********/
- unsigned char sec,min,hour,day,month,week,year; //秒,分,时,日,月,星期,年
- unsigned char newsec,newmin,newhour,newday,newmonth,newweek,newyear; //重写数据用的秒,分,时——
- unsigned char bksec,bkmin,bkhour,bkweek,bkday,bkmonth,bkyear,down,count; //闪烁标志位
- unsigned char flag,daflag; // 加减标志位,时间日期标志位
- unsigned char timete[8],timede[10]; //分别存放,时分秒;年月日
- unsigned char week1[3]="SUN"; //星期日
- unsigned char week2[3]="MON"; // 一
- unsigned char week3[3]="TUE"; // 二
- unsigned char week4[3]="WED"; // 三
- unsigned char week5[3]="THU"; // 四
- unsigned char week6[3]="FRI"; // 五
- unsigned char week7[3]="SAT"; // 六
- unsigned char name[]="Wulai"; //制作者(本人)的名字
- /************函数申明***************/
- void delay(unsigned char ms); //延时
- void writebyte(unsigned char wdat); //写一字节到ds1302
- unsigned char readbyte(); //从ds1302中读一字节
- unsigned char readdat(unsigned char raddr); //读ds1302某地址数据
- void writedat(unsigned char waddr,unsigned char x); //写数据到ds1302的某地址
- void ifprotect(flag); //是否写允许
- void timebuf(); //时间缓冲区
- void checkbusy(); //测试lcd忙碌状态
- void wrcom(unsigned char com); //写指令到lcd
- void wrdat(unsigned char dat); //写数据到lcd
- void lcdinit(); //lcd初始化
- void scanmenu(); //menu扫描
- void funcmenu(); //menu功能
- void scaninc(); //扫描加能函数
- void scandec(); //扫描减一函数
- void scanquit(); //扫描退出函数
- void funcinc(); //加一功能函数
- void funcdec(); //减一功能函数
- void funcquit(); //退出功能函数
- void turn_sub(unsigned char newval,unsigned char newbk,unsigned char newaddr); //调时子函数
- void sub_buf(unsigned char subk,unsigned char bfte,unsigned char fda); //时间缓冲子函数
- void sub_week(unsigned char num); //显示星期子函数
- /**********************ds1302函数部分***************************/
- void delay(unsigned char ms) //延时函数
- {
- unsigned char i;
- unsigned char m=4;
- while(ms--)
- {
- for(i=0;i<5;i++)
- {
- do
- {}while(m--);
- }
- }
- }
- void writebyte(unsigned char wdat) //写一字节到ds1302
- {
- unsigned char i;
- ACC=wdat;
- for(i=8;i>0;i--)
- {
- io=acc0; //从最低位开始传送
- clk=1; //产生一个边沿 在写指令时供产生上升沿,在写数据时供产生紧挨着的下降沿
- clk=0;
- ACC>>=1;
- }
- }
- unsigned char readbyte() //从ds1302中读一字节
- {
- unsigned char i1;
- for(i1=8;i1>0;i1--)
- {
- ACC>>=1; //保证最低位传送至最低位
- acc7=io; //从最低位开始传送
- clk=1; //产生一个边沿 在读数据时供产生上升沿
- clk=0;
- }
- return(ACC);
- }
- unsigned char readdat(unsigned char raddr) //读ds1302某地址数据
- {
- unsigned char value;
- rst=0; //在读写前何证rst为低电平
- clk=0;
- rst=1; //在读写期间保证rst为高电平 且只有在clk为低 电平时才能变为高电平
- writebyte(raddr);
- value=readbyte();
- rst=0; //读写完毕后保证rst为低,clk为高
- clk=1;
- return(value);
- }
- /*******写数据到ds1302的某地址********/
- void writedat(unsigned char waddr,unsigned char x)
- {
- rst=0;
- clk=0;
- rst=1;
- writebyte(waddr);
- writebyte(x);
- rst=0;
- clk=1;
- }
- /********是否写保护********/
- void ifprotect(flag)
- {
- if(flag) //flag=1时禁止写入
- writedat(0x8e,0x10);
- else //flag=0时允许写入
- writedat(0x8e,0x00);
- }
- void readtime() //读时间
- {
- unsigned char time;
- time=readdat(0x81); //读秒
- sec=((time&0x70)>>4)*10+(time&0x0f); //将bcd码转换成十进制数
- time=readdat(0x83); //读分
- min=((time&0x70)>>4)*10+(time&0x0f);
- time=readdat(0x85); //读时
- hour=((time&0x70)>>4)*10+(time&0x0f);
- time=readdat(0x87); //读日
- day=((time&0x70)>>4)*10+(time&0x0f);
- time=readdat(0x89); //读月
- month=((time&0x70)>>4)*10+(time&0x0f);
- time=readdat(0x8d); //读年
- year=(time>>4)*10+(time&0x0f);
- time=readdat(0x8b); //读星期
- week=time&0x07;
- }
- /****************时间缓冲子函数*************************/
- void sub_buf(unsigned char subk,unsigned char bfte,unsigned char fda)
- {
- if(subk<=1) //判断是否正常显示
- {
- if(daflag==1) //判断是日间还是日期
- {
- timete[fda]=bfte%10+48;
- timete[fda+1]=bfte/10+48;
- }
- else
- {
- timede[fda]=bfte%10+48;
- timede[fda+1]=bfte/10+48;
- }
- }
- else //显示空
- {
- if(daflag==1) //判断是时间还是日期
- {
- timete[fda]=0x02;
- timete[fda+1]=0x02;
- }
- else
- {
- timede[fda]=0x02;
- timede[fda+1]=0x02;
- }
- }
- }
- void timebuf() //时间缓冲区
- {
- readtime(); //调用读时间函数
- daflag=1;
- sub_buf(bksec,sec,0); //调用时间缓冲子函数
- timete[2]=':';
- sub_buf(bkmin,min,3);
- timete[5]=':';
- sub_buf(bkhour,hour,6);
- daflag=0;
- sub_buf(bkday,day,0);
- timede[2]='-';
- sub_buf(bkmonth,month,3);
- timede[5]='-';
- if(bkyear<=1)
- {
- timede[6]=year%10+48; //年
- timede[7]=year/10+48;
- timede[8]=48;
- timede[9]=50;
- }
- else
- {
- timede[6]=0x02;
- timede[7]=0x02;
- timede[8]=0x02;
- timede[9]=0x02;
- }
- }
- /**************************lm016l显示器函数部分****************************/
- void checkbusy() // 测试lcd忙碌状态
- {
- do
- {
- P0=0xff;
- rs=0;
- rw=1;
- re=0;
- busy=P0&0x80;
- re=1;
- }while(busy==1);
- }
- void wrcom(unsigned char com) //写指令到lcd
- {
- P0=com;
- rs=0;
- rw=0;
- re=0;
- checkbusy();
- re=1;
- }
- void wrdat(unsigned char dat) //写数据到lcd
- {
- P0=dat;
- rs=1;
- rw=0;
- re=0;
- checkbusy();
- re=1;
- }
- void lcdinit() // lcd初始化
- {
- wrcom(0x02); //光标、画面回home位,AC=0
- wrcom(0x0c); //显示开,光标不闪不显
- wrcom(0x06); //对数据读写后,ac自动加1,且屏不动
- wrcom(0x38); //允许双行显示
- }
- void display() //显示
- {
- unsigned char i2,i3,i5;
- timebuf();
- wrcom(0x80); //在第一行显示时,分,秒
- for(i2=10;i2>0;i2--)
- wrdat(timede[i2-1]);
- wrcom(0xc0); //在第二行显示年月日
- for(i3=8;i3>0;i3--)
- wrdat(timete[i3-1]);
- switch(week) //第一行显示星期
- {
- case 1:sub_week(1);break;
- case 2:sub_week(2);break;
- case 3:sub_week(3);break;
- case 4:sub_week(4);break;
- case 5:sub_week(5);break;
- case 6:sub_week(6);break;
- case 7:sub_week(7);break;
- }
- for(i5=0;i5<5;i5++) //显示作者名字
- {
- wrcom(0xca+i5);
- wrdat(name[i5]);
- }
- }
- void sub_week(unsigned char num) //显示星期子函数
- {
- unsigned char i4;
- for(i4=0;i4<3;i4++)
- {
- if(bkweek<=1) //判断是否正常显示
- {
- wrcom(0x8c+i4);
- switch(num)
- {
- case 1:wrdat(week1[i4]); break;
- case 2:wrdat(week2[i4]); break;
- case 3:wrdat(week3[i4]); break;
- case 4:wrdat(week4[i4]); break;
- case 5:wrdat(week5[i4]); break;
- case 6:wrdat(week6[i4]); break;
- case 7:wrdat(week7[i4]); break;
- }
- }
- else //显示空
- {
- wrcom(0x8c+i4);
- wrdat(0x02);
- }
- }
- }
- /******************* 键盘部分的函数*****************************************/
- /***********调时子函数********************/
- void turn_sub(unsigned char newval,unsigned char newbk,unsigned char newaddr)
- {
- newval=readdat(newaddr); //读取当前时间
- newval=((newval&0x70)>>4)*10+(newval&0x0f); //将bcd码转换成十进制
- if(flag==1) //判断是加一还是减一
- newval++;
- else
- newval--;
- switch(count)
- {
- case 1: if(newval>59) newval=0;break;
- case 2: if(newval>59) newval=0;break;
- case 3: if(newval>23) newval=0;break;
- case 5: if(newval>31) newval=0;break;
- case 6: if(newval>12) newval=0;break;
- case 7: if(newval>79) newval=0;break;
- default:break;
- }
- ifprotect(0);
- writedat((newaddr-1),((newval/10)<<4)|(newval%10)); //将新数据写入寄存器
- ifprotect(1);
- newbk++; //修改过程中数值也要闪烁
- if(newbk>3)
- newbk=0;
- display(); //将修改后的值显示出来
- }
- void scanmenu() //menu扫描
- {
- if(menu==0) //判断menu键是否按下
- {
- delay(1); //延时消抖(实际中延时要比此长一般约10ms)
- if(menu==0) //再次判断menu键是否按下
- {
- down=1; //menu键按下则置其标志位为1
- while(menu!=1); //等待按键松开
- count++; //记录menu按下的次数
- if(count>7)
- count=1;
- ifprotect(0); //按下menu键后禁止ds1302工作
- sec=readdat(0x81);
- writedat(0x80,0x80|sec);
- ifprotect(1);
- }
- }
- }
- void funcmenu() //menu键功能函数
- {
- switch(count)
- {
- case 1:{scaninc();scandec(); //每按一次目录键对inc,dec键进行一次扫描
- do //根据count的计数来判断对那一值进行修改,并保证这一值闪烁
- { bkyear=1;
- bksec++;
- if(bksec>3)
- bksec=0;
- }while(count!=1);
- scanquit(); //每按一次目录键对quit键进行一次扫描
- display(); //退出时正常显示
- }break;
- case 2:{scaninc();scandec();
- do
- {
- bksec=1; //保证退出上一值的闪烁后,让其正常显示
- bkmin++;
- if(bkmin>3)
- bkmin=0;
- }while(count!=2);
- scanquit();
- display();
- }break;
- case 3:{scaninc();scandec();
- do
- {
- bkmin=1;
- bkhour++;
- if(bkhour>3)
- bkhour=0;
- }while(count!=3);
- display();
- scanquit();
- }break;
- case 4:{scaninc();scandec();
- do
- {
- bkhour=1;
- bkweek++;
- if(bkweek>3)
- bkweek=0;
- }while(count!=4);
- display();
- scanquit();
- }break;
- case 5:{scaninc();scandec();
- do
- {
- bkweek=1;
- bkday++;
- if(bkday>3)
- bkday=0;
- }while(count!=5);
- display();
- scanquit();
- }break;
- case 6:{scaninc();scandec();
- do
- {
- bkday=1;
- bkmonth++;
- if(bkmonth>3)
- bkmonth=0;
- }while(count!=6);
- display();
- scanquit();
- }break;
- case 7:{scaninc();scandec();
- do
- {
- bkmonth=1;
- bkyear++;
- if(bkyear>3)
- bkyear=0;
- }while(count!=7);
- display();
- scanquit();
- }break;
- default: break;
- }
- }
- void scaninc() //扫描inc按键
- {
- if(inc!=1) //判断inc键是否按下
- { //延时消拌再次判断
- delay(1);
- if(inc!=1)
- while(inc!=1); //等待按键松开
- flag=1;
- funcinc(); //调用inc功能函数
- }
- }
- void scandec() //扫描dec键
- {
- if(dec!=1)
- {
- delay(1);
- if(dec!=1)
- while(dec!=1);
- flag=0;
- funcdec();
- }
- }
- void scanquit() //扫描quit键
- {
- if(quit!=1)
- {
- delay(1);
- if(quit!=1)
- while(quit!=1);
- funcquit();
- }
- }
- void funcinc() //inc功能 键
- {
- switch(count)
- {
- case 1:do{ //对秒进行修改
- turn_sub(newsec,bksec,0x81);
- sec=readdat(0x81);
- ifprotect(0); //禁止ds1302工作
- writedat(0x80,0x80|sec);
- ifprotect(1);
- }while(count!=1);break;
- case 2:do{ //对分进行修改
- turn_sub(newmin,bkmin,0x83);
- }while(count!=2);break;
- case 3:{
- turn_sub(newhour,bkhour,0x85);
- }while(count!=3);break;
- case 4:do{
- newweek=readdat(0x8b);
- newweek++;
- if(newweek>7)
- newweek=1;
- ifprotect(0);
- writedat(0x8a,newweek);
- ifprotect(1);
- bkweek++;
- if(bkweek>3)
- bkweek=0;
- display();
- }while(count!=4);break;
- case 5:do{
- turn_sub(newday,bkday,0x87);
- }while(count!=5);break;
- case 6:do{
- turn_sub(newmonth,bkmonth,0x89);
- }while(count!=6);break;
- case 7:do{
- turn_sub(newyear,bkyear,0x8d);
- }while(count!=7);break;
- default: break;
- }
- }
- void funcdec() //dec按键功能函数
- {
- switch(count)
- {
- case 1:do{
- turn_sub(newsec,bksec,0x81);
- sec=readdat(0x81);
- ifprotect(0);
- writedat(0x80,0x80|sec);
- ifprotect(1);
- }while(count!=1);break;
- case 2:do{
- turn_sub(newmin,bkmin,0x83);
- }while(count!=2);break;
- case 3:do{
- turn_sub(newhour,bkhour,0x85);
- }while(count!=3);break;
- case 4:do{
- newweek=readdat(0x8b);
- newweek--;
- if(newweek<1)
- newweek=7;
- ifprotect(0);
- writedat(0x8a,0x00|newweek);
- ifprotect(1);
- bkweek++;
- if(bkweek>3)
- bkweek=0;
- display();
- }while(count!=4);break;
- case 5:do{
- turn_sub(newday,bkday,0x87);
- }while(count!=5);break;
- case 6:do{
- turn_sub(newmonth,bkmonth,0x89);
- }while(count!=6);break;
- case 7:do{
- turn_sub(newyear,bkyear,0x8d);
- }while(count!=7);break;
- default: break;
- }
- }
- void funcquit() //quit按键功能函数
- {
- bksec=1; //保证退出后正常显示
- bkmin=1;
- bkhour=1;
- bkweek=1;
- bkday=1;
- bkmonth=1;
- bkyear=1;
- count=0; //退出后menu按键次数复位
- down=0; //退出后menu按下标志位复位
- sec=readdat(0x81);
- sec=((sec&0x70)>>4)*10+(sec&0x0f);
- ifprotect(0);
- writedat(0x80,(((sec&0x7f)/10)<<4)|(sec%10)); //保存当前秒并允许ds1302工作
- ifprotect(1);
- }
- void main()
- {
- lcdinit(); //lcd初始化
- down=0;
- count=0;
- while(1)
- {
- scanmenu(); //扫描menu键是否按下
- if(down==1) //若按下进入调时模式
- funcmenu();
- display(); //若没按下正常显示
- delay(18);
- }
- }
复制代码
全部资料51hei下载地址:
小门系统.rar
(6.71 MB, 下载次数: 46)
|