51單片機-密碼鎖仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (17.52 KB, 下載次數: 87)
下載附件
2018-12-25 01:56 上傳
0.png (12.66 KB, 下載次數: 80)
下載附件
2018-12-25 01:56 上傳
單片機源程序如下:
- #include <reg51.h> // 包含51單片機寄存器定義的頭文件
- #include <intrins.h> //包含_nop_()函數定義的頭文件
- #include<string.h>
- #include <12864.h>
- #include<KEYPAD4_3.h>
- #define N 8
- #define NOP5() {_nop_();_nop_();_nop_();_nop_();_nop_();} // 執行5個空操作,延時5微秒
- unsigned char readerror=0; //讀取成功為0,否則為1
- unsigned char writeerror=0; //寫入成功為0,否則為1
- unsigned char Rbuff[10]={0};
- unsigned char Wbuff[10]="0000";
- sbit SDA=P2^7; //將串行數據總線SDA位定義在為P3.4引腳
- sbit SCL=P2^6; //將串行時鐘總線SDA位定義在為P3.3引腳
- sbit led = P2^0;
- u8 str[]="123456789*0#";
- u8 s[10]={0};
- /*****************************************************
- 函數功能:延時若干毫秒
- 入口參數:n
- *****************************************************/
- void delay_ms(unsigned int n)
- {
- unsigned int i,j;
- for(i=0;i<n;i++)
- for(j=0;j<110;j++);
- }
- /***************************************************
- 函數功能:開始數據傳送
- ***************************************************/
- void start()
- // 開始位
- {
- SDA = 1; //SDA初始化為高電平“1”
- SCL = 1; //開始數據傳送時,要求SCL為高電平“1”
- NOP5();
- SDA = 0; //SDA的下降沿被認為是開始信號
- NOP5();
- SCL = 0; //SCL為低電平時,SDA上數據才允許變化(即允許以后的數據傳遞)
- }
- /***************************************************
- 函數功能:結束數據傳送
- ***************************************************/
- void stop()
- // 停止位
- {
- SDA = 0; //SDA初始化為低電平“0” _n
- SCL = 1; //結束數據傳送時,要求SCL為高電平“1”
- NOP5();
- SDA = 1; //SDA的上升沿被認為是結束信號
- NOP5();
- }
- /***************************************************
- 函數功能:發送應答/非應答信號
- ***************************************************/
- void Send_Ack(bit ack)
- //ack=0表示應答;ack=1表示非應答
- {
- SCL = 0; //拉低SCL為輸出數據到SDA做準備
- SDA = ack; //輸出ack到SDA,表示應答/不應答
- SCL = 1;
- NOP5(); //NOP5()>4us
- SCL = 0; //SCL從0-1-0為一個完整的時鐘周期
- SDA=1;//釋放總線
- }
- /***************************************************
- 函數功能:查詢/接收應答信號
- ***************************************************/
- unsigned char Rec_Ack(void)
- //返回值為0表示應答,為1表示非應答
- {unsigned char i,ack;
- SCL=0; //拉低SCL為輸出數據到SDA做準備
- SDA = 1; //釋放總線,讓從設備能輸出數據到SDA
- SCL=1;
- while((SDA==1)&&(i<250)) i++;
- /*等待從設備發送應答信號,若為0,表示應答,循環結束;若為1,可能是從機還未將信號送上來,循環延時到i>250,若仍為1,此時才認為是未應答*/
- ack=SDA;
- SCL = 0;//SCL從0-1-0為一個完整的時鐘周期
- SDA=1; //釋放總線
- return(ack);
- }
- /***************************************************
- 函數功能:從AT24Cxx讀取數據
- 出口參數:recbyte
- ***************************************************/
- unsigned char ReadData()
- // 從AT24Cxx中讀取一個字節數據到MCU
- {
- unsigned char i;
- unsigned char recbyte; //儲存從AT24Cxx中讀出的數據
- SCL=0; //拉低SCL為從設備輸出數據到SDA做準備
- SDA=1; //釋放總線
- for(i = 0; i < 8; i++)
- {
- SCL = 1; //SCL置為高電平
- NOP5();
- recbyte=(recbyte<<1)|SDA; //讀SDA
- SCL=0; //SCL從0-1-0為一個完整的時鐘周期
- }
- SDA=1;
- return(recbyte); //返回所讀數據
- }
- /***************************************************
- 函數功能:向AT24Cxx的當前地址寫入數據
- 入口參數:sendbyte (儲存待寫入的數據)
- ***************************************************/
- //在調用此數據寫入函數前需首先調用開始函數start(),所以SCL=0
- void WriteData(unsigned char sendbyte)
- {
- unsigned char i;
- for(i = 0; i < 8; i++) // 循環移入8個位
- {
- sendbyte<<=1; //左移時最低位補0,最高位移入PSW的CY位
- SDA=CY; //輸出數據到SDA
- SCL = 1; //在SCL的上升沿將數據寫入AT24Cxx
- NOP5();
- SCL = 0; //將SCL重新置為低電平,以在SCL線形成傳送數據所需的8個脈沖
- }
- SDA = 1; // 發送設備(主機)應在時鐘脈沖的高電平期間(SCL=1)釋放SDA線,
- }
- /***************************************************
- 函數功能:向AT24Cxx中的指定地址寫入數據
- 入口參數:add (儲存指定的地址);dat(儲存待寫入的數據)
- ***************************************************/
- void WriteRom(unsigned char add, unsigned char dat[],unsigned char j)
- // 將數組里的j個字節的數據寫入到起始地址為addr處的連續區域中
- { unsigned char flag=0,k=0,i=3;//i為允許最大重寫次數,若出現i次操作失效后,則函數中止操作,并返回
- while(i--)
- {start(); //開始數據傳遞
- WriteData(0xa0); //選擇要操作的AT24Cxx芯片,并告知要對其寫入數據,器件地址以及寫入操作為1010 0000B(0xa0)
- if(Rec_Ack()) continue;
- WriteData(add); //寫入器件內部地址
- if(Rec_Ack()) continue;
- while(j--)
- {WriteData(dat[k++]); //向當前地址(上面指定的地址)寫入數據
- if(!Rec_Ack()) continue;
- flag=1;
- break;
- }
- if(flag) continue;/*能不能改成:if(j>=0) continue? (j>=0意味著數據未寫完,即出現了未應答,要重寫)*/
- break;
- }
- stop(); //停止數據傳遞
- if(i<0) writeerror=1;
- }
- /***************************************************
- 函數功能:從AT24Cxx中的指定地址讀取數據
- 入口參數:set_addr
- 出口參數:x
- ***************************************************/
- void ReadRom(unsigned char set_addr,unsigned char dat[],unsigned char j)
- // 在指定地址開始連續讀取j個字節,并將數據存放到數組中
- { unsigned char i=3,k=0;//i為允許最大重讀次數,若出現i次操作失效后,則函數中止操作,并返回
- while(i--)
- { start(); //開始數據傳遞
- WriteData(0xa0); //選擇要操作的AT24Cxx芯片,并告知要對其寫入數據,器件地址以及寫入操作為1010 0000B(0xa0)
- if(Rec_Ack()) continue;
- WriteData(set_addr); //寫入指定地址
- if(Rec_Ack()) continue;
- start();//調啟動總線函數
- WriteData(0xa1); //選擇器件要操作的AT24Cxx芯片,并告知要對其讀取數據,器件地址以及讀取操作為1010 0001B(0xa1)
- if(Rec_Ack()) continue;//如果操作失敗,就退出
- while(--j)
- { dat[k++]=ReadData();
- Send_Ack(0);
- }//接收前j-1個字節,并應答
- dat[k++]=ReadData();//接收最后一個字節
- Send_Ack(1);//向從設備發出非應答信號,結束數據傳輸
- break;
- }
- stop();
- if(i<0) readerror=1;
- }
- //密碼錯誤時
- void mimacuowu(){
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("密碼錯誤!");
- lcd12864_pos(1,0);
- LCD12864disp("請重新輸入!");
- delay_ms(1000);
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("請輸入密碼:");
- lcd12864_pos(1,0);
- }
- //密碼正確時
- u8 zhengque(){
- u8 key;
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("開鎖成功!");
- lcd12864_pos(1,0);
- LCD12864disp("是否修改密碼?");
- lcd12864_pos(2,0);
- LCD12864disp("1:是,2:否");
- lcd12864_pos(3,0);
- while(1){
- key=keypad4_3();
- if(key==0 || key==1){
- if(key==0) LCD12864disp("1");
- else LCD12864disp("2");
- delay_ms(1000);
- return key;
- }
- }
- }
- //改密碼
- void gai(){
- u8 key,a=0;
- u8 s1[10]={0};
- u8 s2[10]={0};
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("請輸入密碼:");
- lcd12864_pos(1,0);
- while(1){
- key=keypad4_3();
- if(key<12)
- {
- if(key==9) LCD12864_backspace();
- if(key==11) break;
- if(key!=9 && key!=11){s1[a++]=str[key]; LCD12864disp("*");}
- }
- }
- lcd12864_pos(2,0);
- LCD12864disp("再次輸入密碼:");
- lcd12864_pos(3,0);
- a=0;
- while(1){
- key=keypad4_3();
- if(key<12)
- {
- if(key==9) LCD12864_backspace();
- if(key==11) break;
- if(key!=9 && key!=11){s2[a++]=str[key]; LCD12864disp("*");}
- }
- }
- if(strcmp(s1,s2)==0){
- SDA = 1; //I2C初始化:SDA=1,SCL=1,使主從設備處于空閑狀態
- SCL = 1;
- memset(Rbuff,0,sizeof(s)); //再次初始化數組
- strcpy(Rbuff,s2);
- //WriteRom(0x32,s2,10); //向起始地址為“0x32”的連續區域中寫入數組Wbuff中的5個數據
- //ReadRom(0x32,Rbuff,10); //從起始地址為“0x32”的連續區域中讀取5個數據到數組Rbuff中
-
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("密碼修改成功");
- delay_ms(2000);
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("請輸入密碼:");
- lcd12864_pos(1,0);
- }
- else
- {
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("兩次輸入不一致");
- lcd12864_pos(1,0);
- LCD12864disp("密碼修改失敗");
- delay_ms(2000);
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("請輸入密碼:");
- lcd12864_pos(1,0);
- }
- }
- /***************************************************
- 函數功能:主函數
- ***************************************************/
- void main()
- {
- int a=0,flage=1;
- unsigned char i=0;
- u8 key,f;
- SDA = 1; //I2C初始化:SDA=1,SCL=1,使主從設備處于空閑狀態
- SCL = 1;
- //led = 1;
- WriteRom(0x32,Wbuff,10); //向起始地址為“0x32”的連續區域中寫入數組Wbuff中的5個數據
- ReadRom(0x32,Rbuff,10); //從起始地址為“0x32”的連續區域中讀取5個數據到數組Rbuff中
-
- //初始化
- /*while(i<N)
- { P1=Rbuff[i];
- delaynms(1000);
- i++; //將讀出的數據送P1口顯示
- }*/
-
- lcd12864_init();
- lcd12864_pos(0,0);
- //lcd_wcmd(0x01);
- LCD12864disp("請輸入密碼:");
- lcd12864_pos(1,0);
- while(1)
- {
- key=keypad4_3();
- if(key<12){ if(key==9) {LCD12864_backspace();} //刪除
- if(key==11) //密碼確認
- {
-
- if(strcmp(Rbuff,s)==0) flage=0; //正確
- else flage=1; //錯誤
- if(flage==0)
- {
- led=0; //燈亮
- f=zhengque();
- if(f==0){
-
- gai();
- }
- if(f==1){
- lcd_wcmd(0x01);
- lcd12864_pos(0,0);
- LCD12864disp("請輸入密碼:");
- lcd12864_pos(1,0);
- }
- led = 1; //燈滅
- a=0;
- memset(s,0,sizeof(s)); //再次初始化數組
- }
- else
- {
- mimacuowu();
- a=0;
- memset(s,0,sizeof(s)); //再次初始化數組
- }
- }
- if(key!=9 && key!=11) {s[a++]=str[key]; LCD12864disp("*");}
- }
- }
- }
復制代碼
所有資料51hei提供下載:
密碼鎖.zip
(295.89 KB, 下載次數: 233)
2018-12-4 20:06 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|