非常適合單片機新手,需要可來下載。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
04、修改密碼.jpg (215.47 KB, 下載次數: 92)
下載附件
2019-6-29 17:42 上傳
03、密碼輸入錯誤.jpg (215.74 KB, 下載次數: 80)
下載附件
2019-6-29 17:42 上傳
2、輸入密碼狀態.jpg (214.99 KB, 下載次數: 82)
下載附件
2019-6-29 17:42 上傳
01、未上電.jpg (211.09 KB, 下載次數: 89)
下載附件
2019-6-29 17:42 上傳
單片機源程序如下(代碼注釋非常詳細):
- #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[i]=' '; // 每次清除一位密碼緩沖區
- }
- 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); // 給AT24C02第10個內存寫入數字“88”,代表密碼初始化好了
- }
- for(i=0;i<6;i++) // 從AT24C02讀取6個密碼,賦值給密碼數組ArrCode
- {
- ArrCodeUnlock[i]=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; // 給ArrCodeBuff緩沖區加入一個新的密碼記錄
- 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[i]!=ArrCodeAdmin[i])
- 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[i]!=ArrCodeUnlock[i])
- 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[i]=ArrCodeBuff[i];
- }
- LcdGotoXY(1,8); // 光標定位
- inputMode=3; // 改為輸入 修改密碼2
- ClearCodeBuff(); // 清除密碼緩沖區
- while(KeyScanf()!=99); // 等待按鍵釋放
- }
-
- /*修改密碼2*/
- else
- {
- for(i=0;i<6;i++) // 將2次輸入的密碼進行比較
- {
- if(ArrCodeBuff[i]!=ArrCodeTemp[i])
- 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[i]); // 將新的密碼存入EEPROM芯片
- ArrCodeUnlock[i]=ArrCodeTemp[i]; // 將新的密碼存入解鎖密碼數組
- }
- }
- Relay_P=1; // 繼電器閉合
- inputMode=1; // 改為輸入解鎖密碼模式
- for(i=0;i<6;i++) // 清空修改密碼緩沖區
- {
- ArrCodeTemp[i]=' ';
- }
- inputInit(); // 輸入初始化
- while(KeyScanf()!=99); // 等待按鍵釋放
- }
- }
- }
- }
-
復制代碼
所有資料51hei提供下載:
07、單片機程序(先解壓,后查看).rar
(294.84 KB, 下載次數: 92)
2019-6-29 17:30 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
08、電路圖(原理圖和PCB圖).rar
(317.92 KB, 下載次數: 57)
2019-6-29 17:30 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
09、仿真圖.rar
(896.85 KB, 下載次數: 98)
2019-6-29 17:30 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|