我按照這個程序做出來的,總是輸入密碼錯誤,不知道是啥問題,麻煩大神幫看看是啥問題。
#include <reg52.h> #include <intrins.h> #define uchar unsigned char // 以后unsigned char就可以用uchar代替 #define uint unsigned int // 以后unsigned int 就可以用uint 代 sbit SDA_P = P2^1; // 定義了AT24C02的SCL引腳 sbit SCL_P = P2^0; // 定義了AT24C02的SDA引腳 sbit LcdEn_P = P2^5; // 1602液晶的EN管腳 sbit LcdRw_P = P2^6; // 1602液晶的RW管腳 sbit LcdRs_P = P2^7; // 1602液晶的RS管腳 sbit Beep_P = P3^3; // 蜂鳴器引腳 sbit Relay_P = P3^2; // 繼電器引腳 uchar ArrCodeBuff[6]; // 密碼輸入緩沖區 uchar ArrCodeUnlock[6]; // 解鎖密碼 uchar ArrCodeTemp[6]; // 臨時數組(修改密碼時會用到) uchar ArrCodeAdmin[6]={1,2,3,1,2,3}; // 管理員密碼 uchar row,column; // 液晶的當前行列坐標 uchar inputNum=0; // 輸入的密碼位數 uchar inputMode=1; // =1輸入解鎖密碼,=2輸入修改密碼1,=3輸入解鎖密碼2 uchar errTime=0; // 密碼輸入錯誤的次數 /*********************************************************/ // 毫秒級的延時函數,time是要延時的毫秒數 /*********************************************************/ void DelayMs(uint time) { uint i,j; for(i=0;i<time;i++) for(j=0;j<112;j++); } /*********************************************************/ // 延時6微秒 /*********************************************************/ void Delay6us() { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } /*********************************************************/ // 1602液晶寫命令函數,cmd就是要寫入的命令 /*********************************************************/ void LcdWriteCmd(uchar cmd) { LcdRs_P = 0; LcdRw_P = 0; LcdEn_P = 0; P0=cmd; DelayMs(2); LcdEn_P = 1; DelayMs(2); LcdEn_P = 0; } /*********************************************************/ // 1602液晶寫數據函數,dat就是要寫入的數據 /*********************************************************/ void LcdWriteData(uchar dat) { LcdRs_P = 1; LcdRw_P = 0; LcdEn_P = 0; P0=dat; DelayMs(2); LcdEn_P = 1; DelayMs(2); LcdEn_P = 0; } /*********************************************************/ // 1602液晶初始化函數 /*********************************************************/ void LcdInit() { LcdWriteCmd(0x38); // 16*2顯示,5*7點陣,8位數據口 LcdWriteCmd(0x0C); // 開顯示,不顯示光標 LcdWriteCmd(0x06); // 地址加1,當寫入數據后光標右移 LcdWriteCmd(0x01); // 清屏 } /*********************************************************/ // 液晶光標定位函數 /*********************************************************/ void LcdGotoXY(uchar y, uchar x) { // 第一行 if(y==0) LcdWriteCmd(0x80+x); // 第二行 if(y==1) LcdWriteCmd(0x80+0x40+x); row=y; column=x; } /*********************************************************/ // 液晶輸出字符串函數 /*********************************************************/ void LcdPrintStr(uchar *str) { while(*str!='\0') LcdWriteData(*str++); } /*********************************************************/ // IIC起始函數 /*********************************************************/ void IIcStart() { SDA_P=1; Delay6us(); SCL_P=1; Delay6us(); SDA_P=0; Delay6us(); } /*********************************************************/ // IIC終止函數 /*********************************************************/ void IIcStop() { SDA_P=0; Delay6us(); SCL_P=1; Delay6us(); SDA_P=1; Delay6us(); } /*********************************************************/ // IIC寫一個字節 /*********************************************************/ void IIcWriteByte(uchar dat) { uchar i; for(i=0;i<8;i++) { dat=dat<<1; SCL_P=0; Delay6us(); SDA_P=CY; Delay6us(); SCL_P=1; Delay6us(); } SCL_P=0; Delay6us(); SDA_P=1; Delay6us(); } /*********************************************************/ // IIC讀一個字節 /*********************************************************/ uchar IIcReadByte() { uchar i,temp,dat=0; SCL_P=0; Delay6us(); SDA_P=1; Delay6us(); for (i=0;i<8;i++) { SCL_P=1; Delay6us(); temp=SDA_P; Delay6us(); dat=(dat<<1)|temp; SCL_P=0; Delay6us(); } return(dat); } /*********************************************************/ // IIC總線響應 /*********************************************************/ void IIcRespons() { uchar i=0; SCL_P=1; Delay6us(); while((SDA_P==1)&&(i<250)) { i++; } SCL_P=0; Delay6us(); } /*********************************************************/ // IIC讀出數據 /*********************************************************/ uchar IIcReadDat(uchar addr) { uchar dat; IIcStart(); // 開始信號 IIcWriteByte(0xa0); // 寫芯片地址(寫) IIcRespons(); // 等待應答 IIcWriteByte(addr); // 寫內存地址(0-255) IIcRespons(); // 等待應答 IIcStart(); // 開始信號 IIcWriteByte(0xa1); // 寫芯片地址(讀) IIcRespons(); // 等待應答 dat=IIcReadByte(); // 讀取一個字節數據 IIcRespons(); // 等待應答 IIcStop(); // 結束信號 DelayMs(2); // 簡短延時 return dat; // 返回讀取到的數據 } /*********************************************************/ // IIC寫入數據 /*********************************************************/ void IIcWriteDat(uchar addr,uchar dat) { IIcStart(); // 開始信號 IIcWriteByte(0xa0); // 寫芯片地址(寫) IIcRespons(); // 等待應答 IIcWriteByte(addr); // 寫內存地址(0-255) IIcRespons(); // 等待應答 IIcWriteByte(dat); // 寫入數據 IIcRespons(); // 等待應答 IIcStop(); // 結束信號 DelayMs(2); // 簡短延時 } /********************************************************** 矩陣鍵盤掃描程序. 如果掃描到有按鍵按下,則返回按鍵值,返回值情況如下所示: ------------------------------------------------------------- | 第1列 第2列 第3列 第4列 | |第1行 1 2 3 12 | |第2行 4 5 6 13 | |第3行 7 8 9 14 | |第4行 10 0 11 15 | ------------------------------------------------------------ 如果掃描不到有按鍵按下,則返回99 **********************************************************/ uchar KeyScanf() { uchar ret,temp1,temp2; P1=0x0f; if(P1!=0x0f) { DelayMs(15); if(P1!=0x0f) { temp1=P1; // 判斷出是哪一行按鍵按下 P1=0xf0; DelayMs(5); temp2=P1; // 判斷出是哪一列按鍵被按下 ret=temp1|temp2; // 通過行和列的值,確定是哪個按鍵被按下 switch(ret) { case 0xe7: return 1; case 0xd7: return 2; case 0xb7: return 3; case 0x77: return 12; case 0xeb: return 4; case 0xdb: return 5; case 0xbb: return 6; case 0x7b: return 13; case 0xed: return 7; case 0xdd: return 8; case 0xbd: return 9; case 0x7d: return 14; case 0xee: return 10; case 0xde: return 0; case 0xbe: return 11; case 0x7e: return 15; } return ret; } } return 99; } /*********************************************************/ // 液晶顯示密碼 /*********************************************************/ void LcdPrintCode(uchar num) { LcdGotoXY(row,column); // 液晶顯示定位 LcdWriteData(num+0x30); // 顯示輸入的密碼 DelayMs(150); // 等待150毫秒 LcdGotoXY(row,column); // 重新回到剛剛的顯示位置 LcdWriteData('*'); // 顯示“*”替換剛剛顯示的數字 column++; // 液晶顯示光標的縱坐標加1 } /********************************************************/ // 蜂鳴器鳴叫 /*********************************************************/ void MingJiao(uint time) { Beep_P=0; // 蜂鳴器開始鳴叫 DelayMs(time); // 延時 Beep_P=1; // 蜂鳴器停止鳴叫 } /*********************************************************/ // 清除密碼輸入緩沖區的內容 /*********************************************************/ void ClearCodeBuff() { uchar i; for(i=0;i<6;i++) // 循環執行6次 { ArrCodeBuff=' '; // 每次清除一位密碼緩沖區 } inputNum=0; // 輸入的密碼位數為0 } /*********************************************************/ // 密碼輸入初始化 /*********************************************************/ void inputInit() { LcdGotoXY(0,0); // 光標定位 LcdPrintStr(" State:lock "); // 液晶第0行顯示" State:lock " LcdGotoXY(1,0); // 光標定位 LcdPrintStr("Password: "); LcdGotoXY(1,9); // 液晶第1行顯示"Password: " ClearCodeBuff(); // 清除密碼緩沖區 } /*********************************************************/ // 密碼初始化 /*********************************************************/ void CodeInit() { uchar dat,i; dat=IIcReadDat(10); if(dat!=88) // 如果是第一次使用AT24C02芯片 { IIcWriteDat(0,1); // 給AT24C02第0個內存寫入第一個密碼“1” IIcWriteDat(1,2); // 給AT24C02第1個內存寫入第二個密碼“2” IIcWriteDat(2,3); // 給AT24C02第2個內存寫入第三個密碼“3” IIcWriteDat(3,4); // 給AT24C02第3個內存寫入第四個密碼“4” IIcWriteDat(4,5); // 給AT24C02第4個內存寫入第五個密碼“5” IIcWriteDat(5,6); // 給AT24C02第5個內存寫入第六個密碼“6” IIcWriteDat(10,88); // 第10個內存寫入數字“88”,代表密碼初始化好了 } for(i=0;i<6;i++) // 從AT24C02讀取6個密碼,賦值給密碼數組ArrCode { ArrCodeUnlock=IIcReadDat(i); } } /*********************************************************/ // 主函數,程序從這里開始執行 /*********************************************************/ void main() { uchar i; // 臨時變量 uchar keyVal; // 按鍵掃描的返回值 uchar ArrCodeTemp[6]; // 臨時數組 LcdInit(); // 液晶初始化 inputInit(); // 密碼輸入初始化 CodeInit(); // 密碼初始化 while(1) { if(inputNum==6) // 如果輸入了6位密碼了 LcdWriteCmd(0x0c); // 關閉光標閃爍 else // 如果輸入不夠6位密碼 LcdWriteCmd(0x0f); // 開啟光標閃爍 keyVal=KeyScanf(); // 掃描按鍵是否有按鍵 if(keyVal!=99) // 如果有按鍵被按下了 { MingJiao(50); // 那么蜂鳴器鳴叫50毫秒 } /* 0-9 數字 */ if(keyVal<10) // 如果數字鍵被按下 { if(inputNum<6) // 如果輸入的密碼不到6位 { ArrCodeBuff[inputNum]=keyVal; // 給緩沖區加入一個新的密碼記錄 inputNum++; // inputNum加1,代表當前的密碼輸入多了一位 LcdPrintCode(keyVal); // 將輸入的密碼顯示出來 } while(KeyScanf()!=99); // 等待按鍵釋放 } /* 刪除一個密碼 */ if(keyVal==10) // 如果刪除鍵被按下 { if(inputNum>0) // 如果當前已經有輸入密碼了 { column--; // 光標退回上一個位置 LcdGotoXY(row,column); LcdWriteData(' '); // 顯示空格 LcdGotoXY(row,column); // 光標退回上一個位置 inputNum--; // inputNum減1,代表當前的密碼刪掉了一位 ArrCodeBuff[inputNum]=' '; // 清除一位密碼緩沖區 } while(KeyScanf()!=99); // 等待按鍵釋放 } /* 清除全部密碼 */ if(keyVal==11) // 如果取消鍵被按下 { ClearCodeBuff(); // 清除密碼緩沖區 if(inputMode==1) // 如果當前正在輸入解鎖密碼 { LcdGotoXY(1,0); // 光標定位 LcdPrintStr("Password: "); // 液晶第1行顯示“Password: ” LcdGotoXY(1,9); // 光標定位 } if(inputMode==2) // 如果當前正在輸入修改密碼1 { LcdGotoXY(0,0); // 光標定位 LcdPrintStr(" input1: "); // 液晶第0行顯示“input1: ” LcdGotoXY(0,8); // 光標定位 } if(inputMode==3) // 如果當前正在輸入修改密碼2 { LcdGotoXY(1,0); // 光標定位 LcdPrintStr(" input2: "); // 液晶第1行顯示“input1: ” LcdGotoXY(1,8); // 光標定位 } while(KeyScanf()!=99); // 等待按鍵釋放 } /* 手動關鎖 */ if(keyVal==12) { while(KeyScanf()!=99); // 等待按鍵釋放 } /* 取消密碼修改 */ if(keyVal==13) // 如果修改密碼按鍵被按下 { if((inputMode==2)||(inputMode==3)) // 如果當前正在輸入修改密碼 { inputInit(); // 輸入初始化(退出修改) Relay_P=1; // 繼電器閉合 inputMode=1; // 改為輸入解鎖密碼模式 } while(KeyScanf()!=99); } /* 管理員密碼 */ if(keyVal==14) { for(i=0;i<6;i++) { if(ArrCodeBuff!=ArrCodeAdmin) break; } if(i<6) { LcdGotoXY(1,0); LcdPrintStr(" ERROR "); MingJiao(5000); } else { LcdGotoXY(1,0); LcdPrintStr("Password Init OK"); MingJiao(3000); IIcWriteDat(10,' '); CodeInit(); } inputInit(); } /* 確認按鍵 */ if(keyVal==15) // 如果確定鍵被按下 { /*解鎖密碼*/ if(inputMode==1) // 如果當前正在輸入解鎖密碼 { for(i=0;i<6;i++) // 把密碼緩沖區的內容和解鎖密碼進行6次比較 { if(ArrCodeBuff!=ArrCodeUnlock) break; } if(i<6) // 如果密碼錯誤 { errTime++; // 錯誤次數加1 LcdGotoXY(1,0); // 光標定位 LcdPrintStr(" ERROR "); // 第1行顯示" ERROR " LcdGotoXY(1,11); // 光標定位 LcdWriteData(errTime+0x30); // 顯示錯誤的次數 LcdWriteCmd(0x0c); // 關閉光標閃爍 MingJiao(3000); // 蜂鳴器鳴叫3秒 if(errTime==3) // 如果錯誤了3次 { LcdGotoXY(1,0); // 光標定位 LcdPrintStr("Password:lock "); // 第1行顯示"Password:locd errTime=0; // 密碼錯誤次數清零 DelayMs(60000); // 延時60秒 } } else // 如果密碼正確 { errTime=0; // 密碼錯誤次數清零 Relay_P=0; // 打開繼電器 LcdGotoXY(0,0); // 光標定位 LcdPrintStr(" State:open "); // 第0行顯示" State:open " LcdGotoXY(1,0); // 光標定位 LcdPrintStr(" "); // 第1行顯示" " for(i=0;i<100;i++) // 進行10秒等待,執行100次循環 { keyVal=KeyScanf(); // 掃描按鍵 DelayMs(100); // 等待100毫秒 if(keyVal==12) // 如果手動關鎖按鍵被按下 break; // 退出for循環,結束開始等待 if(keyVal==13) // 如果按下修改密碼鍵 { LcdGotoXY(0,0); // 光標定位 LcdPrintStr(" input1: ");// 第0行顯示" input1: " LcdGotoXY(1,0); // 光標定位 LcdPrintStr(" input2: ");// 第1行顯示" input2: " LcdGotoXY(0,8); // 光標定位 inputMode=2; // 切換密碼輸入模式 ClearCodeBuff(); // 清除密碼緩沖區 while(KeyScanf()!=99); // 等待按鍵釋放 break; // 退出for循環,進入密碼修改 } } } if(inputMode==1) // 如果當前處于輸入解鎖密碼狀態 { Relay_P=1; // 閉合繼電器 inputInit(); // 密碼輸入初始化 } } /*修改密碼1*/ else if(inputMode==2) // 如果當前正在輸入修改密碼1 { for(i=0;i<6;i++) // 將輸入的密碼暫時存入ArrCodeTemp數組 { ArrCodeTemp=ArrCodeBuff; } LcdGotoXY(1,8); // 光標定位 inputMode=3; // 改為輸入 修改密碼2 ClearCodeBuff(); // 清除密碼緩沖區 while(KeyScanf()!=99); // 等待按鍵釋放 } /*修改密碼2*/ else { for(i=0;i<6;i++) // 將2次輸入的密碼進行比較 { if(ArrCodeBuff!=ArrCodeTemp) break; } if(i<6) // 密碼修改錯誤 { LcdGotoXY(0,0); // 光標定位 LcdPrintStr("Password Modify "); // 第0行顯示"Password Modify " LcdGotoXY(1,0); // 光標定位 LcdPrintStr("-----failed-----"); // 第1行顯示"-----failed-----" MingJiao(3000); // 蜂鳴器鳴叫3秒 } else // 密碼修改成功 { LcdGotoXY(0,0); // 光標定位 LcdPrintStr("Password Modify "); // 第0行顯示"Password Modify " LcdGotoXY(1,0); // 光標定位 LcdPrintStr("---Successful---"); // 第1行顯示"---Successful---" MingJiao(2000); // 蜂鳴器鳴叫2秒 for(i=0;i<6;i++) { IIcWriteDat(i,ArrCodeTemp);// 將新的密碼存入EEPROM芯片 ArrCodeUnlock=ArrCodeTemp;// 將新的密碼存入密碼數組 } } Relay_P=1; // 繼電器閉合 inputMode=1; // 改為輸入解鎖密碼模式 for(i=0;i<6;i++) // 清空修改密碼緩沖區 { ArrCodeTemp=' '; } inputInit(); // 輸入初始化 while(KeyScanf()!=99); // 等待按鍵釋放 } } } }
|