摘 要:本設計提出了一種電子密碼鎖的設計方法。本系統由STC89C52單片機系統、4×4矩陣鍵盤、LCD1602顯示和報警系統等組成,具有設置、修改六位用戶密碼、超次報警、超次鎖定、密碼錯誤報警等功能。本系統成本低廉,功能實用。
第一章 緒論
1.1 課題背景和意義隨著電子技術和計算機技術的飛速發展,單片機性能不斷完善,性能價格比顯著提高,技術日趨完善。由于單片機具有體積小、重量輕、價格便宜、功耗低、控制功能強及運算速度快等特點,因而在國民經濟建設、軍事及家用電器等各個領域均得到了廣泛的應用。本設計利用單片機及附加電子元器件實現數據采集和控制算法,來完成某一實際功能。
隨著人們生活水平的提高和安全意識的加強,對安全的要求也就越來越高。鎖自古以來就是把守護門的鐵將軍,人們對它要求甚高,既要安全可靠的防盜,又要使用方便,這也是制鎖者長期以來研制的主題。隨著電子技術的發展,各類電子產品應運而生,電子密碼鎖就是其中之一。電子鎖是通過鍵盤輸入一組密碼完成開鎖過程。研究這種鎖的初衷,就是為提高鎖的安全性。由于電子鎖的密鑰量(密碼量)極大,可以與機械鎖配合使用,并且可以避免因鑰匙被仿制而留下安全隱患。電子鎖只需記住一組密碼,無需攜帶金屬鑰匙,免除了人們攜帶金屬鑰匙的煩惱,而被越來越多的人所欣賞。電子鎖的種類繁多,例如數碼鎖,指紋鎖,磁卡鎖,IC卡鎖,生物鎖等。但較實用的還是按鍵式電子密碼鎖。
20世紀80年代后,隨著電子鎖專用集成電路的出現,電子鎖的體積縮小,可靠性提高,成本較高,是適合使用在安全性要求較高的場合,且需要有電源提供能量,使用還局限在一定范圍,難以普及,所以對它的研究一直沒有明顯進展。
目前,在西方發達國家,電子密碼鎖技術相對先進,種類齊全,電子密碼鎖已被廣泛應用于智能門禁系統中,通過多種更加安全,更加可靠的技術實現大門的管理。國內的不少企業也引進了世界上先進的技術,發展前景非?捎^。希望通過不斷的努力,使電子密碼鎖在我國也能得到廣泛應用。
1.2 電子密碼鎖發展趨勢 電子密碼鎖應用于金融業,其根本的作用是“授權”,即被“授權”的人才可以存取錢、物。廣義上講,金融業的“授權”主要包括以下三種層次的內容:1、授予保管權,如使用保管箱、保險箱和保險柜;2、授予出入權,如出入金庫、運鈔車和保管室;3、授予流通權,如自動存取款。目前,金融行業電子密碼鎖的應用主要集中在前兩個層面上。下面將介紹幾種在金融行業中使用較多的電子密碼鎖以及它們的技術發展方向。當然,以上所說的授權技術再高超,都必須由精良的“鎖具”擔當承載結構部件,實現開啟、閉鎖的功能,而且承擔實體防護作用,抵抗住或盡量延遲破壞行為,讓電子密碼鎖“軟、硬不吃”。一般情況下,鎖具防盜的關鍵是鎖身外殼、閉鎖的部件的強度、鎖止型式、配合間隙和布局。提高電子密碼鎖之防護能力的必然途徑是報警,在金融業的許多場所有人值守、有電視監控,具有報警功能,可以綜合物理防范和人力防范兩種作用。報警的前提是具備探測功能,根據電子密碼鎖的使用場所和防護要求,可選擇多種多樣的探測手段。在中國的城市金融業中,實現聯網報警已經成為對各金融網點的基本要求。根據國內外的實踐經驗,金融業實行安全防范風險等級很有必要,即依據使用的防盜報警器材的性能、安裝布局和人員值守狀況等,可以評估被防護物或區域的防護能力,得出風險等級,其中,電子密碼鎖的性能至關重要。
由于數字、字符、圖形圖像、人體生物特征和時間等要素均可成為鑰匙的電子信息,組合使用這些信息能夠使電子密碼鎖獲得高度的保密性,如防范森嚴的金庫,需要使用復合信息密碼的電子密碼鎖,這樣對盜賊而言是“道高一尺、魔高一丈”。組合使用信息也能夠使電子密碼鎖獲得無窮擴展的可能,使產品多樣化,對用戶而言是“千挑百選、自得其所”。
圖1.1 總體框圖
工作過程
- 按鍵設置6位密碼,輸入密碼,通過單片機判斷,若密碼正確,通過則鎖打開,顯示open!
- 首次使用時輸入:131420,對密碼進行初始化,當顯示:initpassword,證明密碼初始化完成,此時的密碼為:000000。
第二章 設計思想
(1)本設計為了防止密碼被竊取要求在輸入密碼時在LCD屏幕上顯示*號。
(2)設計開鎖密碼位六位密碼的電子密碼鎖。
(3)能夠LCD顯示在密碼正確時顯示open!,密碼錯誤時顯示ERROR,輸入密碼時顯示initpassword。
(4)實現輸入密碼錯誤超過限定的三次電子密碼鎖定。
(5)4×4的矩陣鍵盤其中包括0-9的數字鍵和A-D的功能鍵
(6)本產品具備報警功能,當輸入密碼錯誤時蜂鳴器響并且LED燈亮。
- (7)密碼可以由用戶自己修改設定(只支持6位密碼),修改密碼之前必須再次輸入密碼,在輸入新密碼時候需要二次確認,以防止誤操作
-
第三章 系統的硬件設計
3.1硬件支持
3.1.1 STC89C52RC 單片機介紹
STC89C52是一種低功耗、高性能CMOS8位微控制器,具有 8K 在系統可編程Flash 存儲器。在單芯片上,擁有靈巧的8 位CPU 和在系統可編程Flash,使得STC89C51為眾多嵌入式控制應用系統提供高靈活、超有效的解決方案。 具有以下標準功能: 8k字節Flash,512字節RAM, 32 位I/O 口線,看門狗定時器,內置8KB EEPROM,MAX810復位電路,三個16 位 定時器/計數器,一個6向量2級中斷結構,全雙工串行口。另外 STC89X51 可降至0Hz 靜態邏輯操作,支持2種軟件可選擇節電模式?臻e模式下,CPU 停止工作,允許RAM、定時器/計數器、串口、中斷繼續工作。掉電保護方式下,RAM內容被保存,振蕩器被凍結,單片機一切工作停止,直到下一個中斷或硬件復位為止。最高運作頻率35Mhz,6T/12T可選。

圖3-1 STC89C52單片機引腳圖
主要特性如下:
(1) 增強型 8051 單片機,6 時鐘/機器周期和 12 時鐘/機器周期可以任 意選擇,指令代碼完全兼容傳統 8051.
(2)工作電壓:5.5V~3.3V(5V 單片機)/3.8V~2.0V(3V 單片機)
(3) 工作頻率范圍:0~40MHz,相當于普通 8051 的 0~80MHz,實際工 作頻率可達 48MHz
(4) 用戶應用程序空間為 8K 字節
(5) 片上集成 512 字節 RAM
(6) 通用 I/O 口 (32 個) 復位后為: , P1/P2/P3/P4 是準雙向口/弱上拉, P0 口是漏極開路輸出,作為總線擴展用時,不用加上拉電阻,作為 I/O 口用時,需加上拉電阻。
(7)ISP(在系統可編程)/IAP(在應用可編程) ,無需專用編程器,無 需專用仿真器,可通過串口(RxD/P3.0,TxD/P3.1)直接下載用戶程 序,數秒即可完成一片
(8)具有 EEPROM 功能
(9)具有看門狗功能
(10)共 3 個 16 位定時器/計數器。即定時器 T0、T1、T2
(11)外部中斷 4 路,下降沿中斷或低電平觸發電路,Power Down 模式可 由外部中斷低電平觸發中斷方式喚醒
(12)通用異步串行口(UART) ,還可用定時器軟件實現多個 UART
(13) 工作溫度范圍:-40~+85℃(工業級)/0~75℃(商業級)
(14) PDIP 封裝
3.1.2液晶顯示LCD1602的介紹(1)LM1602字符型模塊的性能重量輕:<100g;
體積。<11mm 厚;
功耗低:10—15mW;
顯示內容:192 種字符(5×7 點字型);
32 種字符(5×10 點字型);
可自編8(5×7)或許(5×10)種字符;
指令功能強:可組合成各種輸入、顯示、移位方式以滿足不同的要求;
接口簡單方便:可與8 位微處理器或微控制器相聯;
工作溫度寬:0—50oC
可靠性高:壽命為50,000 小時(25oC)

圖3-2 液晶原理圖
3.1.3自鎖開關說明
自鎖開關電路中起到電源的開關作用,常開的其中一腳接DC電源插口電源腳,常開的另一腳接電路的VCC

圖3-3自鎖開關原理圖 圖3-4自鎖開關硬件圖
3.1.4上拉電阻介紹
其實排阻就是由8個電阻組成的,其中一端全部接在一起,103為8個10K電阻,
102為8個1K電阻,他們在電路中起到“上拉”的作用,又稱上拉電阻。
上拉就是將不確定的信號通過一個電阻嵌位在高電平,電阻同時起限流作用,下拉同理.
上拉是對器件注入電流,下拉是輸出電流,弱強只是上拉電阻的阻值不同,沒有什么嚴格區分,對于非集電極(或漏極)開路輸出型電路(如普通門電路)提升電流和電壓的能力是有限的,上拉電阻的功能主要是為集電極開路輸出型電路輸出電流通道。
上拉,就是把電位拉高,比如拉到VCC
下拉,就是把電壓拉低,拉到GND
一般就是剛上電的時候,端口電壓不穩定,為了讓他穩定為高或低,就會用到上拉或下拉電阻。
有些芯片內部集成了上拉電阻(如單片機的P1、2、3口),所以外部就不用上拉電阻了。但是有一些開漏的(如單片機的P0口),外部必須加上拉電阻。

圖3-5 排組上拉電阻原理圖
3.1.5三極管介紹
常見的三極管為9012、s8550、9013、s8050.單片機應用電路中三極管主要的作用就是開關作用。
其中9012與8550為pnp型三極管,可以通用。
其中9013與8050為npn型三極管,可以通用。
區別引腳:三極管向著自己,引腳從左到右分別為ebc,原理圖中有箭頭的一端為e,與電阻相連的為b,另一個為c。箭頭向里指為PNP(9012或8550),箭頭向外指為NPN(9013或8050)。
三極管的工作原理
三極管是電流放大器件,有三個極,分別叫做集電極C,基極B,發射極E。分成NPN和PNP兩種。我們僅以NPN三極管的共發射極放大電路為例來說明一下三極管放大電路的基本原理。
(1)電流放大
下面的分析僅對于NPN型硅三極管。如上圖所示,我們把從基極B流至發射極E的電流叫做基極電流Ib;把從集電極C流至發射極E的電流叫做集電極電流 Ic。這兩個電流的方向都是流出發射極的,所以發射極E上就用了一個箭頭來表示電流的方向。三極管的放大作用就是:集電極電流受基極電流的控制(假設電源 能夠提供給集電極足夠大的電流的話),并且基極電流很小的變化,會引起集電極電流很大的變化,且變化滿足一定的比例關系:集電極電流的變化量是基極電流變 化量的β倍,即電流變化被放大了β倍,所以我們把β叫做三極管的放大倍數(β一般遠大于1,例如幾十,幾百)。如果我們將一個變化的小信號加到基極跟發射 極之間,這就會引起基極電流Ib的變化,Ib的變化被放大后,導致了Ic很大的變化。如果集電極電流Ic是流過一個電阻R的,那么根據電壓計算公式 U=R*I 可以算得,這電阻上電壓就會發生很大的變化。我們將這個電阻上的電壓取出來,就得到了放大后的電壓信號了。
(2)偏置電路
三極管在實際的放大電路中使用時,還需要加合適的偏置電路。這有幾個原因。首先是由于三極管BE結的非線性(相當于一個二極管),基極電流必須在輸入電壓 大到一定程度后才能產生(對于硅管,常取0.7V)。當基極與發射極之間的電壓小于0.7V時,基極電流就可以認為是0。但實際中要放大的信號往往遠比 0.7V要小,如果不加偏置的話,這么小的信號就不足以引起基極電流的改變(因為小于0.7V時,基極電流都是0)。如果我們事先在三極管的基極上加上一 個合適的電流(叫做偏置電流,上圖中那個電阻Rb就是用來提供這個電流的,所以它被叫做基極偏置電阻),那么當一個小信號跟這個偏置電流疊加在一起時,小 信號就會導致基極電流的變化,而基極電流的變化,就會被放大并在集電極上輸出。另一個原因就是輸出信號范圍的要求,如果沒有加偏置,那么只有對那些增加的 信號放大,而對減小的信號無效(因為沒有偏置時集電極電流為0,不能再減小了)。而加上偏置,事先讓集電極有一定的電流,當輸入的基極電流變小時,集電極 電流就可以減小;當輸入的基極電流增大時,集電極電流就增大。這樣減小的信號和增大的信號都可以被放大了。
(3)開關作用
下面說說三極管的飽和情況。像上面那樣的圖,因為受到電阻 Rc的限制(Rc是固定值,那么最大電流為U/Rc,其中U為電源電壓),集電極電流是不能無限增加下去的。當基極電流的增大,不能使集電極電流繼續增大 時,三極管就進入了飽和狀態。一般判斷三極管是否飽和的準則是:Ib*β〉Ic。進入飽和狀態之后,三極管的集電極跟發射極之間的電壓將很小,可以理解為 一個開關閉合了。這樣我們就可以拿三極管來當作開關使用:當基極電流為0時,三極管集電極電流為0(這叫做三極管截止),相當于開關斷開;當基極電流很 大,以至于三極管飽和時,相當于開關閉合。如果三極管主要工作在截止和飽和狀態,那么這樣的三極管我們一般把它叫做開關管。
(4)工作狀態
如果我們在上面這個圖中,將電阻Rc換成一個燈泡,那么當基極電流為0時,集電極電流為0,燈泡滅。如果基極電流比較大時(大于流過燈泡的電流除以三極管 的放大倍數 β),三極管就飽和,相當于開關閉合,燈泡就亮了。由于控制電流只需要比燈泡電流的β分之一大一點就行了,所以就可以用一個小電流來控制一個大電流的通 斷。如果基極電流從0慢慢增加,那么燈泡的亮度也會隨著增加(在三極管未飽和之前)。

圖3-6 三極管引腳介紹 圖3-7 PNP型原理圖 圖3-8 NPN型原理圖
3.1.6繼電器介紹
電磁繼電器一般由鐵芯、線圈、銜鐵、觸點簧片等組成的。只要在線圈兩端加上一定的電壓,線圈中就會流過一定的電流,從而產生電磁效應,銜鐵就會在電磁力吸引的作用下克服返回彈簧的拉力吸向鐵芯,從而帶動銜鐵的動觸點與靜觸點(常開觸點)吸合。當線圈斷電后,電磁的吸力也隨之消失,銜鐵就會在彈簧的反作用力返回原來的位置,使動觸點與原來的靜觸點(常閉觸點)釋放。這樣吸合、釋放,從而達到了在電路中的導通、切斷的目的。對于繼電器的“常開、常閉”觸點,可以這樣來區分:繼電器線圈未通電時處于斷開狀態的靜觸點,稱為“常開觸點”;處于接通狀態的靜觸點稱為“常閉觸點”。繼電器一般有兩股電路,為低壓控制電路和高壓工作電路。
繼電器的線圈和接線端子是分立的,互補影響的~~~~繼電器的觸點只相當于開關

圖3-9 繼電器硬件圖 圖3-10 繼電器原理圖
3.1.7供電方式
圖3-11 DC插頭 圖3-12 USB電源線
3.1.8輕觸按鍵
圖3-13 實物圖 圖3-14 按鍵原理圖

圖3-15 按鍵解析圖相贈 圖3-16 按鍵解析圖
3.2功能單元模塊設計
3.2.1 開鎖機構
通過單片機送給開鎖執行機構,電路驅動電磁鎖吸合,從而達到開鎖的目的。如下圖所示,為密碼鎖開鎖電路原理圖。
當用戶輸入的密碼正確時,單片機便輸出開門信號,送到開鎖驅動電路,然后驅動電磁鎖,達到開門的目的。本次設計中,基于節省成本考慮,用發光二極管代替電磁鎖,信息通過LCD顯示,并利用蜂鳴器和二極管聲光指示。其中,綠發光二極管亮,表示開鎖;否則,表示密碼輸入錯誤并開啟報警電路。
圖3-17 密碼鎖開鎖電路原理圖
3.2.2 矩陣鍵盤設計電路
每一條水平(行線)與垂直線(列線)的交叉處不相通,而是通過一個按鍵來連通,利用這種行列式矩陣結構只需要M條行線和N條列線,即可組成具有M×N個按鍵的鍵盤。由于本設計中要求使用16個按鍵輸入,為減少鍵盤與單片機接口時所占用的I/O線的數目,故使用矩陣鍵盤。本設計中,矩陣鍵盤行線和單片機P1.0-P1.3相連,列線與單片機P1.4-P1.7相連。矩陣鍵盤設計電路圖,如圖4所示。
鍵盤掃描采用行掃描法,即依次置行線中的每一行為低電平,其余均為高電平,掃描列線電平狀態,為低電平即表示該鍵按下。
圖3-18 矩陣鍵盤設計電路
3.2.3 聲音提示電路設計
聲音提示電路采用小蜂鳴器提示。蜂鳴器能夠根據脈沖信號,以及信號的頻率發出各種不同的聲音,這樣可以根據系統要求在密碼出入正確和密碼輸入錯誤時發出不同的聲音提示,已達到報警的要求。蜂鳴器電路,如下圖所示。

圖3-19 蜂鳴器電路
3.2.4 AT24C02掉電存儲單元的設計
本設計中掉電存儲單元采用AT24C02外部存儲器[8-9],其作用是在系統電源斷開的時候,存儲當前設定的密碼數據。
AT24C02是一個2K位串行CMOS E2PROM,內部含有256個8位字節, 含一個16字節頁寫緩沖器,具有寫保護功能。其采用兩線串行的總線和單片機通訊,電壓最低可以到2.5V,額定電流為1mA,靜態電流10Ua(5.5V),芯片內的資料可以在斷電的情況下保存40年以上,而且采用8腳的DIP封裝,使用方便。如下所示,下圖為AT24C02管腳示意圖,下表為AT24C02管腳說明。

圖3-20 AT24C02管腳示意圖
表1 AT24C02管腳說明
本設計中,AT24C02的SCL和SDA引腳接上拉電阻后與單片機的P3.4(T0)和P3.5(T1)腳相連,其電路下圖所示。

圖3-22 AT24C02掉電存儲單元設計圖
第四章 系統模塊與程序設計
4.1 模塊介紹
與硬件電路相關聯,本系統軟件包括主程序模塊、密碼比較判斷模塊、鍵盤掃描模塊、修改密碼模塊、1602A液晶顯示模塊等[10]。系統程序流程下圖所示。

圖4-1 系統程序流程圖
4.1.1 主程序模塊
主程序主要用于定義全局變量,給全局變量賦初值,初始化E2PROM,啟動定時器以及 從AT24C02中讀取密碼,為整個程序提供數據;檢測按鍵;調用顯示等功能。
4.1.2 密碼比較判斷模塊
該模塊的功能是將鍵盤輸入的密碼利用if語句與設定的密碼進行逐個比較,若密碼完全正確則開鎖;若不正確,則開啟報警電路,復位后重新輸入密碼。其密碼輸入和比較判決流程圖下圖所示。

圖4-2 密碼輸入和比較判決流程圖
4.1.3 鍵盤掃描模塊
鍵盤使用矩陣式鍵盤,由行和列組成,CPU對所有鍵盤進行監視,從而實現逐列掃描鍵盤確定被按鍵的具體位置、判斷鍵盤上有無鍵按下、消除去抖動、判斷閉合的鍵是否釋放等功能。如下圖所示,為鍵盤掃描流程圖

圖4-3 鍵盤掃描流程圖
4.1.4 修改密碼模塊
在密碼輸入正確情況下,可以按下“重置密碼”對密碼進行重新設置,每設定一位就將密碼送給AT24C02存儲起來,當設置6位密碼完畢后,系統將自動跳到程序開始,調用新設置的密碼。下圖為修改密碼流程圖。

圖4-4 修改密碼流程圖
4.2電子密碼鎖原理圖
4.2.1 總電路圖
圖4-5 總電路圖
4.2.2控制電路
圖4-6 控制電路圖
4.2.3實物圖
圖4-7實物圖
4.2.4仿真圖
五 系統功能
本設計中系統可實現功能如下:
(1)對輸入的6位密碼進行隱藏;
(2)通過發光二極管和蜂鳴器,對解密正確或者錯誤進行聲光報警;
(3)6位密碼修改;
(4)在密碼遺失情況下,通過初始密碼進行密碼再設置;
(5)采用AT24C02外部存儲器,完成斷電密碼保護功能;
六 設計總結
從基本方案的制定,到硬件電路的選擇,再到電路的焊接,最后進行程序調試——在此期間我們遇到很多困難,但經過不懈努力,終于擊破了各個難點,達到的所需要的效果。在這次設計中,我深刻認識到自身的不足——缺少實戰經驗。與此同時,也因為這次設計,我得到一定的鍛煉,體會到理論與實踐相結合的重要意義。
由于本次設計時間有限,一些設想沒有完全實現,比如說:電子密碼鎖的網絡通信擴展,人機界面智能化等。期待以后有機會對以上設想進行進一步研究實踐。
致謝
非常感謝**老師,老師在我大學的最后學習階段——畢業設計階段給自己的指導,從最初的定題,到資料收集,到寫作、修改,到論文定稿,她們給了我耐心的指導和無私的幫助。為了指導我們的畢業論文,他甚至放棄了自己的休息時間,他的這種無私奉獻的敬業精神令人欽佩,在此我向他表示我誠摯的謝意。同時,感謝所有任課老師和所有同學在這四年來給自己的指導和幫助,是他們教會了我專業知識,教會了我如何學習,教會了我如何做人。正是由于他們,我才能在各方面取得顯著的進步,在此向他們表示我由衷的謝意,并祝所有的老師培養出越來越多的優秀人才,桃李滿天下
單片機源程序如下:
- <font style="background-color:rgb(255, 255, 255)">#include <REG51.h>
- #include<intrins.h>
- #define LCM_Data P0
- #define uchar unsigned char
- #define uint unsigned int
- #define w 6 //定義密碼位數
- sbit lcd1602_rs=P2^7;
- sbit lcd1602_rw=P2^6;
- sbit lcd1602_en=P2^5;
-
- sbit Scl=P3^4; //24C02串行時鐘
- sbit Sda=P3^5; //24C02串行數據
-
- sbit ALAM = P2^1; //報警
- sbit KEY = P3^6; //開鎖
-
- sbit open_led=P2^2; //開鎖指示燈
-
- bit operation=0; //操作標志位
- bit pass=0; //密碼正確標志
- bit ReInputEn=0; //重置輸入充許標志
- bit s3_keydown=0; //3秒按鍵標志位
- bit key_disable=0; //鎖定鍵盤標志
-
- unsigned char countt0,second; //t0中斷計數器,秒計數器
-
- void Delay5Ms(void);
-
- unsigned char code a[]={0xFE,0xFD,0xFB,0xF7}; //控盤掃描控制表
-
- unsigned char code start_line[] = {"password: "};
- unsigned char code name[] = {"===Coded Lock==="}; //顯示名稱
- unsigned char code Correct[] = {" correct "}; //輸入正確
- unsigned char code Error[] = {" error "}; //輸入錯誤
- unsigned char code codepass[] = {" pass "};
- unsigned char code LockOpen[] = {" open "}; //OPEN
- unsigned char code SetNew[] = {"SetNewWordEnable"};
- unsigned char code Input[] = {"input: "}; //INPUT
- unsigned char code ResetOK[] = {"ResetPasswordOK "};
- unsigned char code initword[] = {"Init password..."};
- unsigned char code Er_try[] = {"error,try again!"};
- unsigned char code again[] = {"input again "};
-
- unsigned char InputData[6]; //輸入密碼暫存區
- unsigned char CurrentPassword[6]={1,3,1,4,2,0}; //當前密碼值
- unsigned char TempPassword[6];
- unsigned char N=0; //密碼輸入位數記數
- unsigned char ErrorCont; //錯誤次數計數
- unsigned char CorrectCont; //正確輸入計數
- unsigned char ReInputCont; //重新輸入計數
- unsigned char code initpassword[6]={0,0,0,0,0,0};
-
- //=====================5ms延時==============================
- void Delay5Ms(void)
- {
- unsigned int TempCyc = 5552;
- while(TempCyc--);
- }
-
- //===================400ms延時==============================
- void Delay400Ms(void)
- {
- unsigned char TempCycA = 5;
- unsigned int TempCycB;
- while(TempCycA--)
- {
- TempCycB=7269;
- while(TempCycB--);
- }
- }
-
- //=============================================================================================
- //================================24C02========================================================
- //=============================================================================================
-
- void mDelay(uint t) //延時
- {
- uchar i;
- while(t--)
- {
- for(i=0;i<125;i++)
- {;}
- }
- }
- void Nop(void) //空操作
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
-
-
- /*起始條件*/
-
- void Start(void)
- {
- Sda=1;
- Scl=1;
- Nop();
- Sda=0;
- Nop();
- }
-
-
- /*停止條件*/
- void Stop(void)
- {
- Sda=0;
- Scl=1;
- Nop();
- Sda=1;
- Nop();
- }
-
- /*應答位*/
- void Ack(void)
- {
- Sda=0;
- Nop();
- Scl=1;
- Nop();
- Scl=0;
- }
-
- /*反向應答位*/
- void NoAck(void)
- {
- Sda=1;
- Nop();
- Scl=1;
- Nop();
- Scl=0;
- }
-
- /*發送數據子程序,Data為要求發送的數據*/
- void Send(uchar Data)
- {
- uchar BitCounter=8;
- uchar temp;
- do
- {
- temp=Data;
- Scl=0;
- Nop();
- if((temp&0x80)==0x80)
- Sda=1;
- else
- Sda=0;
- Scl=1;
- temp=Data<<1;
- Data=temp;
- BitCounter--;
- }
- while(BitCounter);
- Scl=0;
- }
-
- /*讀一字節的數據,并返回該字節值*/
- uchar Read(void)
- {
- uchar temp=0;
- uchar temp1=0;
- uchar BitCounter=8;
- Sda=1;
- do{
- Scl=0;
- Nop();
- Scl=1;
- Nop();
- if(Sda)
- temp=temp|0x01;
- else
- temp=temp&0xfe;
- if(BitCounter-1)
- {
- temp1=temp<<1;
- temp=temp1;
- }
- BitCounter--;
- }
- while(BitCounter);
- return(temp);
- }
-
- void WrToROM(uchar Data[],uchar Address,uchar Num)
- {
- uchar i;
- uchar *PData;
- PData=Data;
- for(i=0;i<Num;i++)
- {
- Start();
- Send(0xa0);
- Ack();
- Send(Address+i);
- Ack();
- Send(*(PData+i));
- Ack();
- Stop();
- mDelay(20);
- }
- }
-
- void RdFromROM(uchar Data[],uchar Address,uchar Num)
- {
- uchar i;
- uchar *PData;
- PData=Data;
- for(i=0;i<Num;i++)
- {
- Start();
- Send(0xa0);
- Ack();
- Send(Address+i);
- Ack();
- Start();
- Send(0xa1);
- Ack();
- *(PData+i)=Read();
- Scl=0;
- NoAck();
- Stop();
- }
- }
- //==================================================================================================
- //=======================================LCD1602====================================================
- //==================================================================================================
-
- #define yi 0x80 //LCD第一行的初始位置,因為LCD1602字符地址首位D7恒定為1(100000000=80)
- #define er 0x80+0x40 //LCD第二行初始位置(因為第二行第一個字符位置地址是0x40)
-
-
- //----------------延時函數,后面經常調用----------------------
- void delay(uint xms)//延時函數,有參函數
- {
- uint x,y;
- for(x=xms;x>0;x--)
- for(y=110;y>0;y--);
- }
-
- //--------------------------寫指令---------------------------
- write_1602com(uchar com)//****液晶寫入指令函數****
- {
- lcd1602_rs=0;//數據/指令選擇置為指令
- lcd1602_rw=0; //讀寫選擇置為寫
- P0=com;//送入數據
- delay(1);
- lcd1602_en=1;//拉高使能端,為制造有效的下降沿做準備
- delay(1);
- lcd1602_en=0;//en由高變低,產生下降沿,液晶執行命令
- }
-
- //-------------------------寫數據-----------------------------
- write_1602dat(uchar dat)//***液晶寫入數據函數****
- {
- lcd1602_rs=1;//數據/指令選擇置為數據
- lcd1602_rw=0; //讀寫選擇置為寫
- P0=dat;//送入數據
- delay(1);
- lcd1602_en=1; //en置高電平,為制造下降沿做準備
- delay(1);
- lcd1602_en=0; //en由高變低,產生下降沿,液晶執行命令
- }
-
- //-------------------------初始化-------------------------
- void lcd_init(void)
- {
- write_1602com(0x38);//設置液晶工作模式,意思:16*2行顯示,5*7點陣,8位數據
- write_1602com(0x0c);//開顯示不顯示光標
- write_1602com(0x06);//整屏不移動,光標自動右移
- write_1602com(0x01);//清顯示
- }
- //========================================================================================
- //=========================================================================================
-
- //==============將按鍵值編碼為數值=========================
- unsigned char coding(unsigned char m)
- {
- unsigned char k;
-
- switch(m)
- {
- case (0x11): k=1;break;
- case (0x21): k=2;break;
- case (0x41): k=3;break;
- case (0x81): k='A';break;
- case (0x12): k=4;break;
- case (0x22): k=5;break;
- case (0x42): k=6;break;
- case (0x82): k='B';break;
- case (0x14): k=7;break;
- case (0x24): k=8;break;
- case (0x44): k=9;break;
- case (0x84): k='C';break;
- case (0x18): k='*';break;
- case (0x28): k=0;break;
- case (0x48): k='#';break;
- case (0x88): k='D';break;
- }
- return(k);
- }
-
-
- //=====================按鍵檢測并返回按鍵值===============================
- unsigned char keynum(void)
- {
- unsigned char row,col,i;
- P1=0xf0;
- if((P1&0xf0)!=0xf0)
- {
- Delay5Ms();
- Delay5Ms();
- if((P1&0xf0)!=0xf0)
- {
- row=P1^0xf0; //確定行線
- i=0;
- P1=a[i]; //精確定位
- while(i<4)
- {
- if((P1&0xf0)!=0xf0)
- {
- col=~(P1&0xff); //確定列線
- break; //已定位后提前退出
- }
- else
- {
- i++;
- P1=a[i];
- }
- }
- }
- else
- {
- return 0;
- }
-
- while((P1&0xf0)!=0xf0);
- return (row|col); //行線與列線組合后返回
- }
- else return 0; //無鍵按下時返回0
- }
- //=======================一聲提示音,表示有效輸入========================
- void OneAlam(void)
- {
- ALAM=0;
- Delay5Ms();
- ALAM=1;
- }
- //========================二聲提示音,表示操作成功========================
- void TwoAlam(void)
- {
- ALAM=0;
- Delay5Ms();
- ALAM=1;
- Delay5Ms();
- ALAM=0;
- Delay5Ms();
- ALAM=1;
- }
- //========================三聲提示音,表示錯誤========================
- void ThreeAlam(void)
- {
- ALAM=0;
- Delay5Ms();
- ALAM=1;
- Delay5Ms();
- ALAM=0;
- Delay5Ms();
- ALAM=1;
- Delay5Ms();
- ALAM=0;
- Delay5Ms();
- ALAM=1;
-
- }
- //=====================顯示輸入的N個數字,用H代替以便隱藏============================
- void DisplayOne(void)
- {
- // DisplayOneChar(9+N,1,'*');
- write_1602com(yi+5+N);
- write_1602dat('*');
- }
- //=======================顯示提示輸入=========================
- void DisplayChar(void)
- {
- unsigned char i;
- if(pass==1)
- {
- //DisplayListChar(0,1,LockOpen);
- write_1602com(er);
- for(i=0;i<16;i++)
- {
- write_1602dat(LockOpen[i]);
- }
- }
- else
- {
- if(N==0)
- {
- //DisplayListChar(0,1,Error);
- write_1602com(er);
- for(i=0;i<16;i++)
- {
- write_1602dat(Error[i]);
- }
- }
- else
- {
- //DisplayListChar(0,1,start_line);
- write_1602com(er);
- for(i=0;i<16;i++)
- {
- write_1602dat(start_line[i]);
- }
- }
- }
- }
-
- void DisplayInput(void)
- {
- unsigned char i;
- if(CorrectCont==1)
- {
- //DisplayListChar(0,0,Input);
- write_1602com(er);
- for(i=0;i<16;i++)
- {
- write_1602dat(Input[i]);
- }
- }
- }
-
-
- //========================重置密碼==================================================
- //==================================================================================
- void ResetPassword(void)
- {
- unsigned char i;
- unsigned char j;
- if(pass==0)
- {
- pass=0;
- DisplayChar();
- ThreeAlam();
- }
- else
- {
- if(ReInputEn==1)
- {
- if(N==6)
- {
- ReInputCont++;
- if(ReInputCont==2)
- {
- for(i=0;i<6;)
- {
- if(TempPassword[i]==InputData[i]) //將兩次輸入的新密碼作對比
- i++;
- else
- {
- //DisplayListChar(0,1,Error);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(Error[j]);
- }
- ThreeAlam(); //錯誤提示
- pass=0;
- ReInputEn=0; //關閉重置功能,
- ReInputCont=0;
- DisplayChar();
- break;
- }
- }
- if(i==6)
- {
- //DisplayListChar(0,1,ResetOK);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(ResetOK[j]);
- }
-
- TwoAlam(); //操作成功提示
- WrToROM(TempPassword,0,6); //將新密碼寫入24C02存儲
- ReInputEn=0;
- }
- ReInputCont=0;
- CorrectCont=0;
- }
- else
- {
- OneAlam();
- //DisplayListChar(0, 1, again); //顯示再次輸入一次
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(again[j]);
- }
- for(i=0;i<6;i++)
- {
- TempPassword[i]=InputData[i]; //將第一次輸入的數據暫存起來
- }
- }
-
- N=0; //輸入數據位數計數器清零
- }
- }
- }
-
- }
-
-
-
- //=======================輸入密碼錯誤超過三過,報警并鎖死鍵盤======================
- void Alam_KeyUnable(void)
- {
- P1=0x00;
- {
- ALAM=~ALAM;
- Delay5Ms();
- }
- }
-
-
- //=======================取消所有操作============================================
- void Cancel(void)
- {
- unsigned char i;
- unsigned char j;
- //DisplayListChar(0, 1, start_line);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(start_line[j]);
- }
- TwoAlam(); //提示音
- for(i=0;i<6;i++)
- {
- InputData[i]=0;
- }
- KEY=1; //關閉鎖
- ALAM=1; //報警關
- operation=0; //操作標志位清零
- pass=0; //密碼正確標志清零
- ReInputEn=0; //重置輸入充許標志清零
- ErrorCont=0; //密碼錯誤輸入次數清零
- CorrectCont=0; //密碼正確輸入次數清零
- ReInputCont=0; //重置密碼輸入次數清零
- open_led=1;
- s3_keydown=0;
- key_disable=0;
- N=0; //輸入位數計數器清零
- }
-
-
- //==========================確認鍵,并通過相應標志位執行相應功能===============================
- void Ensure(void)
- {
- unsigned char i,j;
- RdFromROM(CurrentPassword,0,6); //從24C02里讀出存儲密碼
- if(N==6)
- {
- if(ReInputEn==0) //重置密碼功能未開啟
- {
- for(i=0;i<6;)
- {
- if(CurrentPassword[i]==InputData[i])
- {
- i++;
- }
- else
- {
- ErrorCont++;
- if(ErrorCont==3) //錯誤輸入計數達三次時,報警并鎖定鍵盤
- {
- write_1602com(er);
- for(i=0;i<16;i++)
- {
- write_1602dat(Error[i]);
- }
- do
- Alam_KeyUnable();
- while(1);
- }
- else
- {
- TR0=1; //開啟定時
- key_disable=1; //鎖定鍵盤
- pass=0;
- break;
- }
- }
- }
-
- if(i==6)
- {
- CorrectCont++;
- if(CorrectCont==1) //正確輸入計數,當只有一次正確輸入時,開鎖,
- {
- //DisplayListChar(0,1,LockOpen);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(LockOpen[j]);
- }
- TwoAlam(); //操作成功提示音
- KEY=0; //開鎖
- pass=1; //置正確標志位
- TR0=1; //開啟定時
- open_led=0; //開鎖指示燈亮
- for(j=0;j<6;j++) //將輸入清除
- {
- InputData[i]=0;
- }
- }
- else //當兩次正確輸入時,開啟重置密碼功能
- {
- //DisplayListChar(0,1,SetNew);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(SetNew[j]);
- }
- TwoAlam(); //操作成功提示
- ReInputEn=1; //允許重置密碼輸入
- CorrectCont=0; //正確計數器清零
- }
- }
-
- else //=========================當第一次使用或忘記密碼時可以用131420對其密碼初始化============
- {
- if((InputData[0]==1)&&(InputData[1]==3)&&(InputData[2]==1)&&(InputData[3]==4)&&(InputData[4]==2)&&(InputData[5]==0))
- {
- WrToROM(initpassword,0,6); //強制將初始密碼寫入24C02存儲
- //DisplayListChar(0,1,initword); //顯示初始化密碼
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(initword[j]);
- }
- TwoAlam();
- Delay400Ms();
- TwoAlam();
- N=0;
- }
- else
- {
- //DisplayListChar(0,1,Error);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(Error[j]);
- }
- ThreeAlam(); //錯誤提示音
- pass=0;
- }
- }
- }
-
- else //當已經開啟重置密碼功能時,而按下開鎖鍵,
- {
- //DisplayListChar(0,1,Er_try);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(Er_try[j]);
- }
- ThreeAlam();
- }
- }
-
- else
- {
- //DisplayListChar(0,1,Error);
- write_1602com(er);
- for(j=0;j<16;j++)
- {
- write_1602dat(Error[j]);
- }
-
- ThreeAlam(); //錯誤提示音
- pass=0;
- }
- N=0; //將輸入數據計數器清零,為下一次輸入作準備
- operation=1;
- }
- //==============================主函數===============================
- void main(void)
- {
- unsigned char KEY,NUM;
- unsigned char i,j;
- P1=0xFF;
- TMOD=0x11;
- TL0=0xB0;
- TH0=0x3C;
- EA=1;
- ET0=1;
- TR0=0;
- Delay400Ms(); //啟動等待,等LCM講入工作狀態
- lcd_init(); //LCD初始化
- write_1602com(yi);//日歷顯示固定符號從第一行第0個位置之后開始顯示
- for(i=0;i<16;i++)
- {
- write_1602dat(name[i]);//向液晶屏寫日歷顯示的固定符號部分
- }
- write_1602com(er);//時間顯示固定符號寫入位置,從第2個位置后開始顯示
- for(i=0;i<16;i++)
- {
- write_1602dat(start_line[i]);//寫顯示時間固定符號,兩個冒號
- }
- write_1602com(er+9); //設置光標位置
- write_1602com(0x0f); //設置光標為閃爍
- Delay5Ms(); //延時片刻(可不要)
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
- </font>
復制代碼
所有資料51hei提供下載: