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