新人第一篇帖子,基于51單片機的門禁系統(實驗),內附proteus作圖以及ds1302和1602程。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
無標題.png (205.87 KB, 下載次數: 68)
下載附件
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
2018-8-29 23:07 上傳
單片機原程序如下: - #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, 下載次數: 47)
2018-8-29 23:12 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|