51hei.png (967.06 KB, 下載次數: 50)
下載附件
2023-5-21 01:12 上傳
51hei.png (122.2 KB, 下載次數: 45)
下載附件
2023-5-21 01:14 上傳
單片機源程序如下:
- /*****************************************************************
-
- 名稱:51單片機密碼鎖
- 說明:1、開鎖:輸入6位密碼加#號,密碼正確報警“滴......”顯示OK并開鎖,
- 不正確聲音提示“滴...滴”顯示ERROR,重新輸入密碼,五次輸入不正確,
- 報警滴...滴滴、鎖機10分鐘。
- 2、更改密碼:輸入管理員密碼090564加#號,報警“滴....”,顯示
- NEW Password,輸入6位新密碼加#號,報警“滴......”,已修改開鎖密碼。
- 密碼存儲于單片機內部EEPROM中,可有3459.4560萬種密碼。
- 器件:使用STC90C58R單片機,利用P2口、4x4鍵盤做鍵盤掃描口,12M晶體
- 晶振:12MHZ
- 時間:2020.12.18
- ******************************************************************/
- #include<stc90c.h>
- #include<intrins.h>
- #include "string.h"
- #define uchar unsigned char
- #define uint unsigned int
- #define WaitTime 0x01
- #define RdCommand 0x01
- #define PrgCommand 0x02
- #define EraseCommand 0x03
- #define open 0
- #define clok 1
- /*
- sfr ISP_DATA = 0xe2; //聲明特殊功能寄存器//stc90c.h中已聲明過,這里不需在聲明
- sfr ISP_ADDRH = 0xe3;
- sfr ISP_ADDRL = 0xe4;
- sfr ISP_CMD = 0xe5;
- sfr ISP_TRIG = 0xe6;
- sfr ISP_CONTR = 0xe7;*/
- sfr MDT_CONTR=0xe1;
- sbit lcdrw=P3^6;
- sbit lcdrs=P3^5;
- sbit lcden=P3^4;
- sbit dula=P2^6;
- sbit wela=P2^7;
- sbit scl=P2^1;
- sbit sda=P2^0;
- sbit FM=P2^3;
- sbit lock=P1^0; //開關鎖
- sbit lcd_led=P1^1; //開關LCD背景燈
- sbit P_25=P2^5;
- void read_busy();
- void lcdrw_dat(unsigned char dat); //寫數據
- void check_k(); //檢測確認鍵(k12)是否按下
- void lcdrw_com(unsigned char com);
- uchar code table[]="0123456789 *#ABCD";
- uchar code table1[]=" Password";
- uchar code table3[]=" OK";
- uchar code table6[]=" New Password";
- uchar code error[]=" ERROR";
- uchar table4[6];
- uchar table_open_password[6]={0x01,0x02,0x03,0x04,0x05,0x06};//開鎖密碼
- uchar table_update_password[6]={0x0,0x9,0x0,0x05,0x06,0x04};//改密碼密碼
- // 0 9 0 5 6 4
- uchar num,numl,i,a,b=0;//
- uint t=0,t1=0;
- uchar key_num;
- bit flag=0,flag1=0,flag2=0,flag3=0;
- void delayms(uint xms)
- {
- uint i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- void yanshi500us(uint x)
- {
- uchar y;
-
- for(x;x>0;x--)
- for(y=240;y>0;y--);
- }
- void FM_3()
- {
- FM=0;
- delayms(100);
- FM=1;
- delayms(100);
- FM=0;
- delayms(100);
- FM=1;
- delayms(100);
- FM=0;
- delayms(100);
- FM=1;
- }
- void FM_2()
- {
- FM=0;
- delayms(100);
- FM=1;
- delayms(100);
- FM=0;
- delayms(100);
- FM=1;
- }
- void FM_1() // 按鍵時短響一聲
- {
- FM=0;
- delayms(100);
- FM=1;
- }
- void FM_11() // ok時長響一聲
- {
- FM=0;
- delayms(500);
- FM=1;
- }
- void xianshi_password()
- {
- for(i=0;i<12;i++)
- {
- lcdrw_dat(table1[i]);
- }
- }
- void xianshi_ok()
- {
- for(i=0;i<3;i++)
- {
- lcdrw_dat(table3[i]);
- }
- }
- void xianshi_New_Password()
- {
- for(i=0;i<14;i++)
- {
- lcdrw_dat(table6[i]);
- }
- }
- void xiansh_error()
- {
- for(i=0;i<10;i++)
- {
- lcdrw_dat(error[i]);
- }
- }
- //==================以下是內部EEPROM操作================
- /*******************打開ISP/ISA功能*********************/
- void ISP_IAP_enable()
- {
- EA=0;
- ISP_CONTR=ISP_CONTR & 0x18; //ISP_CONTR復位
- ISP_CONTR=ISP_CONTR | WaitTime; //設置等待時間
- ISP_CONTR=ISP_CONTR | 0x80; //允許讀/寫/擦除
- }
- /*********************關閉ISP/ISA功能*******************/
- void ISP_IAP_disable()
- {
- ISP_CONTR=ISP_CONTR & 0x7f; //禁止讀/寫/擦除
- // ISP_TRIG=0x00;
- EA=1;
- }
- /*******************讀/寫/擦除的觸發代碼*****************/
- void ISPgoon()
- {
- ISP_IAP_enable(); //打開ISP/ISA功能
- ISP_TRIG=0x46; //寫入0x46;0xb9;使命令生效
- ISP_TRIG=0xb9;
- _nop_ ();
- }
- /***********************讀字節***************************/
- uchar byte_read(uint byte_addr)
- {
- ISP_ADDRH=(uchar)(byte_addr>>8); //設置讀字節地址
- ISP_ADDRL=(uchar)(byte_addr & 0x00ff);
- ISP_CMD=ISP_CMD & 0xf8; //清除低三位
- ISP_CMD=ISP_CMD | RdCommand; //讀命令0x01
- ISPgoon(); //開始讀
- ISP_IAP_disable(); //關閉IAP功能
- return(ISP_DATA); //返回讀出的數據
- }
- /*********************扇區擦除***********************/
- void SectorErase(uint Sector_addr)
- {
- ISP_ADDRH=(uchar)(Sector_addr>>8); //設置要擦除扇區地址
- ISP_ADDRL=0x00;
- ISP_CMD=ISP_CMD & 0xf8; //清除低三位
- ISP_CMD=ISP_CMD | EraseCommand; //刪除命令0x03
- ISPgoon(); //開始刪除
- ISP_IAP_disable(); //關閉IAP功能
- }
- /************************字節寫*************************/
- void byte_write(uint byte_addr,uchar original_data)
- {
- ISP_ADDRH=(uchar)(byte_addr>>8); //取地址高八位
- ISP_ADDRL=(uchar)(byte_addr&0x00ff);//取地址低八位
- ISP_CMD=ISP_CMD & 0xf8; //清零低三位
- ISP_CMD=ISP_CMD | PrgCommand; //寫命令0x02
- ISP_DATA=original_data; //數據放入ISP_DATA
- ISPgoon(); //開始寫入
- ISP_IAP_disable(); //關閉IAP功能
- }
- //================以下是LCD操作=========================
- void read_busy() //LCD1602 忙等待
- {
- lcdrs = 0;
- lcdrw = 1;
- lcden = 1;
- P0 = 0xff;
- while (P0&0x80);
- lcden = 0;
- }
-
- void lcdrw_com(unsigned char com) //寫命令
- {
- read_busy();
- lcdrw=0;
- lcdrs=0;
- P0=com;
- yanshi500us(1);
- lcden=1;
- yanshi500us(1);
- lcden=0;
- // lcdrs=1;
- yanshi500us(10);
- }
-
- void lcdrw_dat(unsigned char dat) //寫數據
- {
- read_busy();
- lcdrw=0;
- lcdrs=1;
- P0=dat;
- yanshi500us(1);
- lcden=1;
- yanshi500us(1);
- lcden=0;
- // lcdrs=1;
- yanshi500us(10);
- }
-
- void lcdinit()
- {
- P0=0x0;
- dula=1;
- dula=0;
- P0=0xff;
- wela=1;
- wela=0;
-
- yanshi500us(30);
- lcdrw_com(0x38); //設置16*2屏顯,5*7點陣,8位數據接口
- yanshi500us(10);
- lcdrw_com(0x38);
- yanshi500us(10);
- lcdrw_com(0x38);
- yanshi500us(10);
- lcdrw_com(0x08); //關閉顯示
- lcdrw_com(0x01); //清屏
- lcdrw_com(0x06); //讀寫一個字符后指針加一光標加一
- lcdrw_com(0x0c); //開顯示,顯示光標,光標閃爍
- xianshi_password();
- }
-
- //==================鍵盤掃描=========================
-
- void keyscan()
- {
- uchar num1,num2,a1;
- if(flag==0)
- {
- P2=0x0f;
- delayms(1); //延時一下使IO口穩定
- {
- if(P2!=0x0f)
- {
- delayms(50);
- if(P2!=0x0f)
- {
- num1=P2;
- P2=0xf0; //反轉P2口
- delayms(1); //延時一下使IO口穩定
- num2=P2;
- delayms(50);
- while((P2!=0xf0));
- a1=num1 | num2;
- lcd_led=0; //開LCD背景燈
- EA=0;
- t1=200; //設置定時器定時10秒
- t=0;
- EA=1;
- TR0 = 1; //開定時器
- switch(a1)
- {
- case 0xee: key_num =1; break; //1
- case 0xde: key_num =2; break; //2
- case 0xbe: key_num =3; break; //3
- case 0x7e: key_num =13; break; //A
- case 0xed: key_num =4; break; //4
- case 0xdd: key_num =5; break; //5
- case 0xbd: key_num =6; break; //6
- case 0x7d: key_num =14; break; //B
- case 0xeb: key_num =7; break; //7
- case 0xdb: key_num =8; break; //8
- case 0xbb: key_num =9; break; //9
- case 0x7b: key_num =15; break; //C
- case 0xe7: key_num =11; break; //*
- case 0xd7: key_num =0; break; //0
- case 0xb7: key_num =12; break; //#
- case 0x77: key_num =16; break; //D
- }
-
- if(b==0)
- {
- lcdrw_com(0x01); //lcd清零
- }
- if(key_num!=12)
- {
- table4[b]=key_num;
- FM_1();
- if(flag2==1) //標識位為1,可寫入新密碼
- {
- lcdrw_dat(table[key_num]); //顯示輸入密碼
- if(b==5)
- {
- flag3=1; //flag3=1寫新密碼結束
- flag2=0;
- }
- }
- else
- lcdrw_dat('*'); //顯示*號
- }
- b++; //按鍵次數
- if(b==6)
- {
- b=0;
- }
- }
- }
- }
- }
- }
- /*================判斷確認鍵是否按下=========================
- 如果確認鍵(#)按下,再判斷密碼是否正確(是開鎖密碼還是
- 修改密碼的密)若正確即開鎖或修改密碼,不正確返回 。
- //==========================================================*/
- void check_k() //檢測是否#鍵按下
- {
- if(key_num==12)
- {
- if(flag3==1) //標識flag3為1,新密碼更新完畢
- {
- delayms(100);
- lcdrw_com(0x01); //清屏
- FM_11();
- xianshi_ok(); //顯示ok
- delayms(1000);
- lcdrw_com(0x01); //清屏
- xianshi_password(); //顯示password
- SectorErase(0x8000); //擦除EEPROM扇區
- for(i=0;i<6;i++)
- {
- table_open_password[i]=table4[i]; //向 table_open_password[]寫入新密
-
- byte_write((0x8000+i),table4[i]); //向 EEPROM 寫入新密碼
- }
- b=0;
- flag3=0; //新密碼更新完畢,標識flag3復位
- key_num=0; //封鎖check_k函數
- table4[5]=0xff; //更改密碼后將輸入的密碼打亂
- }
- else if((memcmp(table4, table_open_password, 6))==0)//開鎖密碼正確(本句是數組比較語句)
- {
- flag=1; //屏蔽鍵盤,不允許輸入
- xianshi_ok(); //顯示ok
- lock=open; //開鎖
- FM_11();
- lock=clok; //關鎖
- table4[5]=0xff; //開完鎖后將輸入的密碼打亂
- delayms(1500);
- lcdrw_com(0x01); //清屏
- xianshi_password(); //顯示password
-
- a=0;
- flag=0; //打開鍵盤,允許輸入
- key_num=0; //封鎖check_k函數
- b=0;
- }
- else if((memcmp(table4, table_update_password, 6))==0)//修改密碼的密碼正確(本句是數組比較語句)
- {
- flag=1; //屏蔽鍵盤,不允許輸入
- xianshi_New_Password(); //顯示New Password
- FM_11();
- flag2=1; //標識位置1,可以輸入新密碼
- // SectorErase(0x8000); //擦除EEPROM扇區
- key_num=0; //封鎖check_k函數
- b=0;
- table4[5]=0xff; //將輸入密碼打亂
- flag=0; //打開鍵盤,允許輸入
- }
- else //如果密碼錯誤
- {
- flag=1;
- lcdrw_com(0x01); //清屏
- xiansh_error(); //顯示錯誤
- if(a==4) //密碼輸錯5次
- {
- FM_3();
- // flag=1;
- TR0=0;
- EA=0;
- t1=12000; //設置定時器定時10分鐘
- t=0;
- EA=1;
- TR0=1;
- }
- else
- {
- FM_2();
- delayms(500);
- lcdrw_com(0x01); //清屏
- xianshi_password(); //顯示password
- delayms(10);
- flag=0;
- }
- key_num=0; //封鎖check_k函數
- b=0;
- a++; //密碼錯誤次數
- }
- // P3=0xff; //進入掉電模式前讓p3口為高電位
- // PCON |=0x02; //進入掉電模式
- }
- }
- //================定時器T0設置===================
- void Timer0Init(void) //5ms@12.000MHz
- {
- TMOD = 0x01;
- // TL0 = 0xB0; //設置定時初值 12MHZ
- // TH0 = 0x3C; //設置定時初值
- TL0 = (65536-50000)%256;
- TH0 = (65536-50000)/256;
- ET0 = 1; //清除TF0標志
- TR0 = 0;
- EA=1; //定時器0開始計時
- }
- //================定時器T0=====================
- void T0_time() interrupt 1
- {
- TL0 = (65536-50000)%256;
- TH0 = (65536-50000)/256;
- t++;
- if(t>=200) //定時10秒
- {
- P_25=1; //因為鍵盤掃描程序等待時P2口為0x0f關閉了U3,這里打開U3
- lcd_led=1; //關LCD背景燈
- P_25=0; //關閉U3,如果鍵盤單獨一個P口在不需要
- }
- if(t>=t1)
- {
- b=0;
- lcdrw_com(0x01); //清屏
- xianshi_password(); //顯示password
- t=0;
- a=0;
- flag=0;
- flag2=0;
- flag3=0;
- table4[5]=0xff; //將上次輸入的密碼打亂
- TR0=0;
- }
- }
- /************外部中斷1函數****************
- *
- *
- void EX1_int() //外部中斷1初始化 *
- { *
- IT1=1; *
- EA=1; *
- EX1=1; *
- } *
- *
- void exint() interrupt 2 //外部中斷 *
- { *
- PCON &=0xfd; //進入掉電模式 *
- } *
- *********************************************/
- //===============主函數===================
- void main()
- {
- MDT_CONTR=0x35; //啟動看門狗
- a=b=flag=flag1=flag2=flag3=0;
- lcdinit();
- Timer0Init();
- // EX1_int(); //掉電模式
-
- for(i=0;i<6;i++)
- {
- table_open_password[i]=byte_read(0x8000+i);
- //上電時將EEPROM中的密碼取出放入table_open_password[]
- }
-
- while(1)
- {
- keyscan();
- check_k();
- MDT_CONTR=0x35; // 喂狗
- }
- }
復制代碼
|