基于單片機的電子密碼鎖設計 摘要:鎖,是指加在門、箱子、抽屜等物體上的封緘器,要用專用的鑰匙才能打開。自古以來鎖都是人們財產安全乃至生命安全的一種重要保障。伴隨著人類歷史的發展和人們對自身財產安全和人生安全的重視,各種各樣的多功能的鎖具也相繼出現,人們使用的鎖具也由傳統的機械式鎖逐漸發展為安全性能更好,功能更多的電子密碼鎖。 在現代社會,電子密碼鎖已是一個被大家所熟識的名詞。相信很多人的小區大門上的鎖都用的是電子密碼鎖。本文中將要介紹的電子密碼鎖是一種通過判斷密碼輸入是否正確來控制電路或是芯片的工作狀態,進而控制鎖的打開和閉合,從而完成開鎖、閉鎖任務的電子鎖裝置。 本設計是基于AT89C51單片機為控制核心的密碼鎖設計方案。在本次基于單片機的電子密碼鎖設計中,將采用AT89C51單片機作為控制核心,配合相應的電路和軟件程序,實現密碼的輸入和修改、信息的顯示、鍵盤的鎖定、系統報警、開鎖和閉鎖等功能。在設計中,利用識別密碼是否正確來開鎖或報警,通過串行存儲器AT24C02來實現密碼的修改和存儲。 本文設計的密碼鎖具有安全性高、功耗低、操作簡單等優點。
The Design Of Electronic Code Lock Based On Single Chip Microcomputer Abstract:As sealed device, the lock added to such objects like door, box, drawer etc, can be opened with specified key. Since the ancient time, lock is a kind of security, guaranteeing people’s property safety even life safety. With the development of human history and more attention paid to property safety and life safety, various multi-functional locks can be seen in the world. Traditional mechanical locks people use in life are gradually replaced by electronic combination lock characterized with better safety performance and more functions. In the modern society, electronic combination lock is a noun familiar to everyone. Usually, the door of community is equipped with electronic combination lock. This paper will introduce an electronic combination lock. This lock controls the electric circuits and the performance of chips by identifying password. Thus, the openness and closeness of the lock can be controlled, and the task of electronic lock device can be completed. This design is about combination lock, based on the AT89C51 single-chip microcomputer as the core of controlling goals. This design in which the AT89C51 single-chip microcomputer as the core of the controlling goals cooperated with relevant circuits and software programs can achieve such functions like password input and modification, information display, keyboard locking, warning system, and the openness and closeness of the lock etc. In this design, the openness of lock and alarming are according to identifying the password, and password revision and storage is achieved by the function of the AT24C02 serial storage. Electronic combination lock described in this paper is characterized with high security, low power consumption, and simplicity of operation etc.
目錄 第1章 緒論 1.1 電子密碼鎖簡介 1.2 電子密碼鎖設計的背景及意義 1.3 電子密碼鎖的現狀及發展趨勢 第2章 總體設計 2.1 設計分析 2.2 系統結構 第3章 硬件電路設計 3.1 單片機接口分配 3.2 單片機最小系統設計 3.2.1 時鐘電路 3.2.2 復位電路 3.2.3 最小系統 3.3 矩陣鍵盤設計 3.4 LCD顯示模塊設計 3.5 掉電存儲模塊 3.5.1 I2C總線 3.5.2 AT24C02簡介 3.6 開鎖機構 3.7 報警機構 3.8 硬件綜合設計 第4章 軟件設計 4.1 軟件總體設計 4.2 鍵盤掃描子程序 4.3顯示模塊子程序 4.4 掉電存儲子程序 4.4.1 寫操作方式 4.4.2 讀操作方式 4.5 定時器中斷子程序 4.6 密碼輸入子程序 4.7 報警子程序 第5章 聯合仿真和調試 第6章 實物設計和制作 總結 致謝 參考文獻 附錄1 設計實物圖 附錄2 程序源代碼 第1章 緒論 1.1 電子密碼鎖簡介 什么是電子密碼鎖?“一種通過密碼輸入來控制電路或者是芯片工作,從而控制機械開關的閉合,完成開鎖、閉鎖任務的電子產品。”——百度百科上是這樣解釋的。簡單來說,電子密碼鎖就是能夠實現密碼等信息的設置、存貯、識別和顯示,以及報警信號的接收和發送等功能的電子器件。 電子密碼鎖相對傳統機械鎖有以下幾個優勢: (1)密碼可更改。用戶可以隨時更改密碼,以確保密碼鎖的安全性和可靠性。可以更改密碼這一功能同時也避免了人員的更替而使鎖的安全性降低,這是傳統鑰匙鎖所不具備的功能。 (2)操作簡單。無論是開鎖還是更改密碼,只要識字的人都能夠直接使用,使用方法簡單而不繁瑣。 (3)能夠報警。報警功能無疑更增加了鎖的安全性。 (4)無法“技術”破解。不知道密碼就無法打開鎖,即使是慣偷也只能望“鎖”興嘆。 1.2 電子密碼鎖設計的背景及意義在現代文明社會,雖然人們的道德素質越來越高,“梁上君子”、“三只手”等人群相對舊社會大大減少,但是像“某某小區遭入室行竊,居民損失XXXX”之類的新聞我們還是經常能夠在報紙上看到的。隨著人們生活水平和自身防范意識的提高,個人財產安全和人身安全的問題也越來越受到人們的重視,擁有一把能夠有效保證居民財產安全和人身安全的鎖具也越發的重要起來。 鎖具的起源可以追朔到人類社會財產私有化的出現,鎖具從其出現到發展至今天的高科技化、信息化,已經有若干年的歷史了。經過若干年的使用和研究,人們對鎖具的結構、機理也了解得相當透徹了,因此,不使用鑰匙就能將鎖打開的方法也層出不窮。特別是傳統的機械鎖,由于其構造簡單,在慣偷面前,甚至能夠只用一根鐵絲就直接將其打開,使其失去了保障用戶個人財產安全的意義。 那么,如何才能提高鎖具保障用戶財產安全的有效性呢?在信息現代化的今天,鎖具也應該向高精度、高安全性的智能化、信息化發展。自20世紀70年代第一塊單片機芯片TMS-1000于美國德克薩斯儀器公司面世以來,基于其體積小、價格低廉、個性突出等特點,越來越多的電子產品開始采用單片機芯片作為核心控制部件。在這樣的大環境下,基于單片機的電子密碼鎖也應運而生。這種電子密碼鎖是以單片機為核心,配以相應的硬件電路和軟件程序,實現密碼的設置、存貯、識別和顯示,以及報警信號的接收和發送等功能,具有操作快、修改密碼簡單、安全性高、功耗低等優點;趩纹瑱C的電子密碼鎖的面世使人們的自身財產安全有了更多的保障,同時也促進了安全信息系統的發展,是安全信息系統的一大進步。 基于單片機的電子密碼鎖的出現,在一定程度上解決了用戶私人財產安全的問題。但是,時代在發展,社會在進步,任何事物只有不斷地進步才能適應時代發展的需求。電子密碼鎖雖然有安全性高、操作簡單等優點,但是卻不如機械鎖價格低廉,因此,在市場上的主流產品還是機械鎖。電子密碼鎖要想取代機械鎖成為市場上的主流,就必須不斷改進,在具有更多功能的同時向更智能化和更低成本化發展。這就需要我們不斷研究電子密碼鎖的設計方法和實現原理。因此,研究基于單片機的電子密碼鎖的設計是很有必要且具有現實意義的。 1.3 電子密碼鎖的現狀及發展趨勢目前,和西方發達國家相比,我國的電子密碼鎖技術還相對落后。在西方發達國家,電子密碼鎖的種類已經很齊全,技術也比較先進,且在各個領域得到了廣泛應用。在我國,電子密碼鎖技術卻才相當于國際上七十年代的水平,相對來說還很落后。20世紀80年代以來,隨著各種電子集成電路的出現,特別是單片機的面世,電子密碼鎖得到了很大的發展。相對于笨重而構造簡單的傳統機械鎖來說,電子密碼鎖具有體積小,可靠性高的優勢。但是就目前而言,電子密碼鎖的價格相對較高且需要有電源提供能量,使得其使用還局限在一定范圍,特別是在國內,各種條件的制約使得電子密碼鎖暫時難以普及。 盡管電子密碼鎖還存在著一些缺陷,但是其安全性高、方便易用、能夠智能報警的優勢卻是傳統鑰匙鎖取代不了的,而且隨著電子信息技術的發展和各種電子器件的價格的不斷降低,電子密碼鎖也將往低成本、多功能的方向發展。
第2章 總體設計2.1 設計分析一個電子密碼鎖,應該能實現以下功能: (1)能夠從鍵盤中輸入密碼,并相應地在顯示器上顯示‘*’; (2)能夠判斷密碼是否正確,正確則開鎖,錯誤則輸出相應信息; (3)能夠實現密碼的修改; (4)斷電或者單片機復位后能夠保存之前的操作,比如密碼的修改; (5)在操作錯誤達到一定次數后能夠報警; (6)在一定時間內沒有任何按鍵操作則關閉顯示器,并鎖定鍵盤,禁止鍵盤輸入(單片機復位后鎖定取消); (7)設置一個備用密碼。為了防止用戶忘記密碼而開不了鎖,應該在經常使用的密碼外再設置一個備用密碼以防萬一。此備用密碼應該只有少數人知道,比如小區管理員。 根據以上分析,本次電子密碼鎖設計的主要重點是以下幾個部分:4x4矩陣鍵盤設計、LCD信息顯示、密碼的掉電存儲和密碼的比較和處理。當然,除了這幾個部分外還有定時器/計數器計時中斷和報警等功能模塊。 本設計應該按以下步驟去實現: 第一步:選擇材料和器件。 第二步:根據單片機原理和模擬電子技術基礎等理論知識在PROTEUS 中畫出仿真圖。 第三步:檢查仿真圖,確保其能夠實現所有功能。 第四步:根據需要實現的功能邏輯畫出程序流程圖。 第五步:根據程序流程圖和PROTEUS仿真圖,使用 KEIL軟件進行程序的編寫和調試。 第六步:將KEIL和PROTEUS聯合仿真、調試,查看是否實現所有功能。 第七步:根據PROTEUS仿真圖焊接器件。 第八步:實物調試。 基于實際情況,在設計中,用發光二極管代替電磁鎖,二極管亮則代表鎖開,二極管不亮則代表鎖關。 2.2 系統結構本設計系統主要由單片機芯片、矩陣鍵盤、LCD顯示模塊、掉電存儲模塊、報警機構和開鎖機構組成。如圖2-1所示。 
圖2-1 系統總體設計結構圖 時鐘電路給單片機提供晶振頻率,復位電路不但使單片機上電復位,還能在使用過程中通過需要通過按鍵再次手動復位,矩陣鍵盤提供按鍵的輸入,LCD模塊顯示信息,掉電存儲負責密碼的存儲,開鎖機構和報警機構分別負責開鎖和報警功能。 設計中,單片機選用AT89C51,LCD顯示模塊選用LCD1602液晶顯示器,串行存儲器選用電可擦除存儲器AT24C02,開鎖機構用發光二極管代替,報警機構選用蜂鳴器。
第3章 硬件電路設計 3.1 單片機接口分配AT89C51單片機在一塊芯片上集成了CPU、RAM、ROM、定時器/計數器和多種I/O功能部件,具有一臺微型計算機的基本結構,按功能可以將其分成八個組成部分:微處理器(CPU)、數據存儲器(RAM)、程序存儲器(ROM/EPROM)、特殊功能寄存器(SFR)、I/O口、串行口、定時器/計數器及中斷系統。 在本設計中,單片機的各個接口我是這樣分配的:P0口接一個上拉電阻后與LCD1602的8位雙向數據端D0~D7相接,P1口用作矩陣鍵盤接口,P2口的P2.0~P2.2和LCD1602的4~6引腳相接,P2.5和P2.6接串行存儲器AT24C02,P3口用作開鎖電路和報警電路的接口。 3.2 單片機最小系統設計單片機最小系統就是指能使單片機工作的最少的器件構成的系統。因為單片機已經包含了數據存儲器和程序存儲器,所以只要在其外部加上時鐘電路和復位電路就可以構成單片機最小系統。 3.2.1 時鐘電路 單片機工作需要晶振給CPU提供頻率,時鐘電路就是給單片機提供晶振頻率的電路。圖3-1是時鐘電路的PROTEUS仿真圖。 
圖3-1 時鐘電路 單片機允許的振蕩晶體可在1.2~24MHz之間選擇,一般為11.0592MHz,電容C2,C3的取值對振蕩頻率輸出的穩定性、大小及振蕩電路起振速度有一定的影響,可在20~100pF之間選擇,典型值位30pF。 3.2.2 復位電路計算機每次開始工作,CPU和系統中的其他部件都必須要有一個確定的初值,即復位狀態。圖3-2是單片機復位電路仿真圖。 
圖3-2 復位電路 單片機RST引腳是高電平有效。單片機在上電瞬間C1充電,RST引腳端出現正脈沖,只要RST斷保持兩個機械周期(大約10ms)以上的高電平,單片機就能復位。在單片機工作后,如果還想再次復位,只需按下開關,單片機就能重新變成復位狀態。 當晶體振蕩頻率為12MHz時,RC的典型值為C=10μF,R=8.2KΩ。 3.2.3 最小系統 單片機加上時鐘電路和復位電路就構成了能使其正常工作的最小系統。 單片機最小系統是單片機正常工作的基礎,任何一個單片機系統設計都是基于單片機最小系統的基礎上來完成的,而在單片機系統實物設計中,最應該首先解決的也應該是單片機最小系統問題,只有保證了單片機最小系統的正確性,才能保證接下來的其他模塊的正確設計。 圖3-3是單片機最小系統的完整仿真圖。

圖3-3 單片機最小系統 3.3 矩陣鍵盤設計一組鍵或者一個鍵盤,需要通過接口電路和CPU相連接,CPU可以采用查詢接口或者中斷的方式了解有沒有鍵被按下,并檢查是哪個鍵被按下。無論是查詢方式還是中斷方式都要用到單片機的I/O口。由于單片機I/O口較少的原因,當系統中需要用到較多按鍵時,為了能夠更合理更有效地利用單片機的I/O口,一般采用矩陣鍵盤的方式來實現多按鍵的功能。 圖3-4是4x4矩陣鍵盤在PROTEUS中的電路原理仿真圖。 
圖3-4 4x4矩陣鍵盤 矩陣鍵盤又叫做行列式鍵盤。行列式鍵盤的硬件結構比較簡單,由行輸出口和列輸出口構成行列式鍵盤,按鍵設置在行、列交點上。圖3-4中,P1.0~P1.3是行輸出口,P1.4~P1.7是列輸出口。行輸出口和列輸出口不相交,只有當鍵被按下時相應的行和列才能相連。如此,只要檢測行和列是否相連就可以知道是否有鍵按下。 由于按鍵設置在行、列線交點上,行、列分別連接到按鍵開關的兩端,平時無鍵按下時,行線處于高電平,假設列線為低電平,當有鍵按下時,按下的鍵就會將相應的行和列連通,使得對應的行線被列線拉低,也變為低電平。這就是識別矩陣鍵盤是否有鍵被按下的關鍵。 當確定有鍵被按下時,通過逐行掃描,讀出I/O口的值可以知道哪一行的值被改變了,被改變了的行即是被按下的按鍵所在行。同時,由于每個鍵都有它的行值和列值,行值和列值得組合就是這個按鍵的編碼,當算法一定時,每個按鍵的編碼是固定的,且各個按鍵的編碼互不相同,所有通過讀I/O的值還能具體知道是哪一個鍵被按下,這樣就實現了鍵盤的識別。 3.4 LCD顯示模塊設計 在單片機應用系統中,常用的顯示設備有單個發光二極管、八段LED顯示器、液晶顯示器(LCD)、屏幕顯示器(CRT)等。在本次設計中,基于設計所要實現的功能和節約成本等實際情況,我采用LCD1602作為本次設計的顯示器。 LCD1602是一種字符型液晶顯示器,是一種專門用于顯示字母、數字、符號等的點陣式液晶顯示器。LCD1602的顯示容量為16x2個字符(可以顯示2行,每行顯示16個字符),芯片工作電壓為4.5~5.5V,工作電流為2.0mA(5.0V),模塊最佳工作電壓是5.0V。 LCD1602具有16個引腳,如表3-1所示。在LCD1602的有關設計中,主要是通過編寫程序控制LCD1602的4、5、6引腳來實現數據或者指令的寫入和執行,再通過數據或者指令的寫入和執行來進一步實現LCD1602的顯示功能。 表3-1是LCD1602的16個引腳和引腳對應功能。
表3-1 LCD1602引腳說明 作為一個字符型液晶顯示器,LCD1602內部自帶有一個字符發生存儲器,此字符發生存儲器就相當于一個字符集。LCD1602的字符集中存有160個不同的字符,這些字符包括了英文大小寫字母、阿拉伯數字、標點符號等一些經常用到的字符。字符集中的每一個字符都對應有一個固定的ASCII碼值,通過顯示ASCII碼對應的字符圖像就能夠實現對應字符的顯示。 圖3-5是PROTEUS中顯示模塊的仿真圖。 由于LCD要正常工作必須提供足夠的電流,因此在實際應用為了保證顯示器能夠正常工作,應在數據端口接一上拉電阻。圖3-5中RP1同時還是P0口的上拉電阻。

圖3-5 LCD模塊仿真圖 3.5 掉電存儲模塊 3.5.1 I2C總線I2C總線為同步串行數據傳輸總線,用于單片機的外圍擴展。I2C總線上所有的外圍器件都有規范的器件地址,器件地址有7位組成,它和1位方向為構成了I2C總線器件的尋址字節。尋址字節格式如下: 表3-2 I2C尋址格式 D7~D4是I2C總線的器件地址,由廠家在器件出廠時給定,對于AT24C系列固定為1010。A2~A0根據電路中A2,A1,A0引腳接電源或者接地而不同,接地則相應位為0,接電源則相應位為1。R/位為I2C總線的數據方向位,決定I2C總線的數據傳送方向,高電平為接收,低電平為發送。
圖3-6為I2C總線的數據傳送時序。

圖3-6 I2C總線數據傳送時序 起始信號:時鐘線SCL為高電平,數據線SDA出現由高向低的負跳變時,啟動I2C總線。 停止信號:時鐘線SCL為高電平,數據線SDA出現由低向高的正跳變時,停止I2C總線。 應答信號位ACK:I2C總線進行數據傳送時,每成功傳送一個字節的數據后,接收器件都必然產生一個應答信號,即在第9個時鐘周期時將SDA線拉低,表示其已經成功接收到一個8個數據。圖3-6中的第9個時鐘脈沖對應于應答位。應答位對應的數據線SDA上是低電平時為應答信號,是高電平則為非應答信號。為非應答信號時,證明器件沒有成功接收到一個8位數據。 數據傳送位:圖3-6中的第1~8個時鐘脈沖為一個字節的8位數據傳送位。脈沖為高電平時,串行傳送數據;脈沖為低電平時,不傳送數據,允許總線上數據線SDA的電平發生變化。在I2C數據傳輸過程中,只有當SCL為低電平時才允許SDA變化,當SCL為高電平時,不允許SDA電平改變。當然,起始信號和停止信號是例外。因此,當SCL為高電平時,SDA的變化被看成是起始信號或者停止信號。 3.5.2 AT24C02簡介 AT24C02是Atmel公司生產的AT24CXX系列串行E2PROM中的一種,是具有I2C總線接口功能的電可擦除串行存儲器。AT24C02內部含有256個字節,通過I2C總線接口進行操作,有一個專門的寫保護功能(WP=1時即為寫保護)。 圖3-7是AT24C02的引腳排列圖。  其引腳功能如下: A0~A2:器件地址輸入端。在本設計中,A0~A2都接地,故其值都為0。 Vcc:+1.8~6.0V工作電壓。 Vss:地或電源負極。 圖3-7 AT24C02引腳 SCL:串行時鐘輸入端。數據發送或者接收的時鐘從此引腳輸入。 SDA:串行/數據地址線。用于傳送地址和發送或者接收數據,是雙向傳送端口。 WP:寫保護端。WP=1時,只能讀出,不能寫入;WP=0時,允許正常的讀寫操作。 圖3-8為PROTEUS中E2PROM的仿真圖。 
圖3-8 AT24C02仿真圖 P2.5為串行時鐘輸入線接口,P2.6為數據線接口。A0,A1,A2接地,所以單片機在讀AT24C02時,器件地址為:10100001B=0A1H;在寫AT24C02時,器件地址為:10100000B=0A0H。WP=0,允許單片機進行讀寫操作。 3.6 開鎖機構 在基于單片機的電子密碼鎖設計中,用戶需要輸入密碼,密碼正確則發出開鎖信號開鎖。 因為在設計中是以發光二極管代替電磁鎖,二極管亮代表鎖開,因此可以設計一個簡單的可以點亮二極管的電路系統代替電磁鎖開鎖機構。如圖3-9所示。 
圖3-9 二極管電路 由于單片機I/O口默認為高電平,故初始時二極管不亮,代表鎖是閉著的。當用戶輸入密碼并驗證正確時,發出開鎖信號(使P3.6=0)。 3.7 報警機構在這次基于單片機的電子密碼鎖設計中,通過控制蜂鳴器的發音來實現系統的報警功能。 蜂鳴器是一種采用直流電壓供電的電子訊響器。圖3-10是用蜂鳴器模擬的報警機構仿真圖。 
圖3-10 報警機構模擬仿真圖
當P3.7口有脈沖信號輸入時,蜂鳴器SPEAKER即會發音。通過控制輸入脈沖的頻率還能控制蜂鳴器的發音頻率。 當用戶輸入密碼錯誤次數達到預設警告次數時,系統調用報警子程序,使蜂鳴器發出報警音,同時禁止鍵盤輸入。 3.8 硬件綜合設計 根據電路原理,在PROTEUS中畫出各功能模塊的仿真圖,各個功能模塊驗證正確后,將所有模塊集合到一個電路設計圖中,畫出具有所有功能的總體硬件仿真圖。 圖3-11即為本設計的硬件綜合設計圖。 
圖3-11 基于單片機的電子密碼鎖設計仿真圖 待程序編寫好后,將KEIL和PROTEUS聯調,觀察此電路設計圖可以知道各個功能模塊和器件的工作情況。屆時,根據實際情況可以適當修改電路圖或者程序,以達到設計的目的。
第4章 軟件設計4.1 軟件總體設計根據電子密碼鎖的實際應用要求和其應該具有的功能,本次設計的主程序流程圖如圖4-1所示。 
圖4-1 主程序流程圖 此次基于單片機的電子密碼鎖設計的軟件設計方面的主要問題是如何實現鍵盤輸入、信息顯示、密碼的掉電存儲以及密碼的比較和處理。本設計接下來將分步解決這幾個問題。 4.2 鍵盤掃描子程序矩陣鍵盤掃描子程序應該具有以下2個基本的功能:(1)能判斷是否有鍵按下;(2)能確定是哪個鍵被按下。其軟件管理主要分為以下三步來完成: 讓所有的行為0,然后讀列的數值。如果列的數值全部為1,說明沒有鍵被按下,否則說明有鍵被按下。 采用一行一行的掃描方法,逐行輸出0,然后讀列的值。如果列的數值全部為1,說明不是這一行的按鍵被按下,掃描下一行,如果列的數值不全為1,則說明被按下的按鍵時在這一行。 - 查鍵值表,返回鍵值對應信息,以便確定各按鍵應該完成的功能。
采用某種算法,將被按下的鍵所在的行和列的信息合并成為一個信息,該信息即為此鍵的鍵值。用相同的方法給每一個鍵確定鍵值。在給按鍵確定鍵值時必須采用同一種算法,并且計算出來的鍵值應該是互不相同的。 本設計中各按鍵對應鍵值如表3所示。 表4-1 按鍵鍵值表
鍵盤掃描子程序的流程圖如圖4-2所示: 
圖4-2 鍵盤掃描程序流程圖 從流程圖可以看出,此鍵盤識別程序是通過逐行掃描來確定是否有鍵按下,當確定某一行有鍵按下時,再在該行中確定被按下的是哪一個按鍵。 在本設計中,P1.0~P1.3為行輸出口,P1.4~P1.7為列輸出口。初始時將P1.0~P1.3值賦為0,P1.4~P1.7賦為1,CPU始終掃描P1端口,當P1值不為0xf0時,有按鍵被按下,否責沒有按鍵被按下。 在實際應用中,為了防止因為按鍵的抖動而使得一次按鍵按下被當做2次或者2次以上處理,應該進行按鍵消抖程序設計,只要方法是當有鍵閉合時,延時一段時間再確定是否還有鍵閉合,若有,則為鍵有效閉合,若無則為鍵無效閉合,返回重新掃描。 圖4-3為CPU掃描第一行鍵盤的程序流程圖。單行鍵盤掃描能夠準確確定被按下鍵所在的位置。 
圖4-3 單行鍵盤掃描流程圖 在本設計中,數字鍵0~9對應輸入數字0~9,功能鍵A鍵是確定鍵,B鍵是取消鍵,C鍵是改密碼鍵,D鍵位閉鎖鍵,E鍵和F鍵閑置不用。 4.3顯示模塊子程序 由于設計中要求能夠顯示密碼輸入界面、密碼輸入信息、密碼正確后提示界面、密碼錯誤后提示界面和修改密碼相關界面等信息,故要用到很多個顯示子程序來顯示不同的內容。雖然顯示子程序很多,但是由于其顯示原理都一樣,所以我就不一一介紹各個子程序了,只要能夠熟練使用LCD1602各個指令,這些大同小異的子程序也就不在話下了。 下面為LCD1602寫命令子函數和寫數據子函數。 //************************************************ //函數:寫命令函數 //功能:調用該函數可能定義1602液晶顯示器的各種命令 //************************************************ void write_1602com(uchar com) { while(lcdbusy()); //lcdbusy()為檢測LCD忙標志函數,lcdbusy()返回值 e=0; //為1,則說明LCD正在工作 rw=0; rs=0; //rs=0時為寫命令 P0=com; //待寫命令賦P0 delay(1); e=1; //e由1→0跳變時為執行命令 delay(1); e=0; } //************************************************* //函數:寫數據函數 //功能:調入該函數可以向1602液晶顯示器輸入數據 //************************************************* void write_1602dat(uchar dat) { while(lcdbusy()); e=0; rw=0; rs=1; //rs=1時為寫數據 P0=dat; delay(1); e=1; delay(1); e=0; } 以下是LCD1602從第一行第一列開始顯示N(0<N≤16)個字符的程序流程圖。 
圖4-4 顯示字符程序流程圖 顯示模塊子程序主要指根據LCD1602的命令和引腳功能來編寫,程序邏輯相當簡單。 4.4 掉電存儲子程序 掉電存儲子程序就是將初始密碼寫進AT24C02,單片機每次復位后從AT24C02中讀取密碼用來和輸入的密碼進行比較,以判斷輸入的密碼的正確性。當密碼修改成功后,將新密碼寫入AT24C02,以便單片機下次復位后使用。 掉電存儲模塊子程序主要涉及AT24C02的寫操作方式和讀操作方式。AT24C02有2種不同的寫操作形式和3種不同的讀操作方式。 4.4.1 寫操作方式兩種寫操作方式為:字節寫和頁寫。 (1)字節寫。字節寫模式下,主機發送(R/位置為0)起始命令和器件地址信息,主機在收到AT24C02的應答信號后,發送1~8位字節地址,寫入AT24C02的地址指針中。對于高于8位的地址,主機連續發送兩個8位字節地址寫入AT24C02中,主機在收到AT24C02的另外一個應答信號后再發送數據到被尋址的存儲單元,AT24C02再次應答,并在主機發出停止信號后開始內部數據的擦寫。AT24C02在內部擦寫過程中不響應主機的任何請求,因此在兩次寫操作之間應該留有足夠的反應時間。 字節寫的時序是這樣的: 地址只有8位:開始→器件地址→響應→8位字節地址→響應→數據→響應→停止 地址高于8位:開始→器件地址→響應→高8位字節地址→響應→低8位字節地址→響應→數據→響應→停止 本次設計中采用的是字節寫方式。圖4-5為字節寫的程序流程圖。 
圖4-5 將字節寫入AT24C02的程序流程圖 (2)頁寫。頁寫和字節寫所不同的是:字節寫一次只能寫入一個字節數據,頁寫一次可以寫入8個或16個字節數據。 頁寫的時序是這樣的: 地址只有8位:開始→器件地址→響應→8位字節地址→響應→數據1→響應→……→數據N→響應→停止。 地址高于8位:開始→器件地址→響應→高8位字節地址→響應→低8位字節地址→響應→數據1→響應→……→數據N→響應→停止。 4.4.2 讀操作方式 三種不同的讀操作方式為:讀當前地址內容(立即地址讀。、讀隨機地址內容(隨機地址讀。┖妥x順序地址內容(順序地址讀。 (1)讀當前地址內容。AT24C02的地址計數器內容為最后操作字節的地址加1,所有如果上次讀寫操作的地址為N,采用讀當前地址內容方式讀地址應該從N+1地址處開始。AT24C02接收到器件地址信號并且I2C總線允許接收數據(R/=1),則首先發送一個應答信號然后輸出數據。數據輸出完畢后,主機發送停止信號,讀操作完畢。 (2)讀隨機地址內容。這種讀操作方式允許主機讀出AT24C02的任意字節。主機置通過R/位為0,發送開始信號、AT24C02地址和欲讀取的字節數據地址來執行一次偽操作,在AT24C02應答后,主機再一次發送開始信號和AT24C02的地址,此時R/位置1,AT24C02響應并應答信號,然后輸出字節數據,最后主機以一個停止信號結束數據的讀取。 (3)讀順序地址內容。讀順序地址內容操作方式通過立即讀或隨機地址讀操作來啟動,主機在AT24C02發送完一個8位數據后產生一個應答信號,告知AT24C02主機要求更多數據。AT24C02收到主機的應答信號后繼續發送數據,直到主機不發送應答信號響應而發送停止信號后操作結束。 下面是三種不同的讀操作方式時序對比: 讀當前地址內容:開始→讀器件地址→響應→數據→無響應→停止。 讀隨機地址內容:開始→寫器件地址→響應→要讀的字節地址→響應→開始→讀器件地址→響應→數據→無響應→停止。 讀順序地址內容:開始→寫器件地址→響應→要讀的字節地址→響應→開始→讀器件地址→響應→數據1→響應→……→數據N→無響應→停止。 本次設計中采用的是讀隨機地址內容操作方式。
程序流程圖如圖4-6所示。 
圖4-6 讀AT24C02相應地址內容的程序流程圖 掉電存儲功能就是通過調用向AT24C02寫字節數據的程序和從AT24C02讀字節數據的程序來實現的。由于AT24C02在內部擦寫過程中不會應答任何來自主機的請求,所以當向AT24C02連續寫多個字節數據時有可能不成功,這可以通過對同一字節數據寫多次的方法來實現。 4.5 定時器中斷子程序 為了防止戶主以外的“借用”戶主的密碼,當沒有任何按鍵被按下的狀態持續一段時間后(比如20S內),應該馬上關閉顯示器屏幕,同時禁止按鍵的輸入。這樣做可以避免因為戶主忘記退出系統而使他人有機可乘。 圖4-7為實現此功能的程序流程圖。 
圖4-7 定時關閉屏幕和鎖定鍵盤輸入程序流程圖 程序中,使定時器0每50毫秒產生一次中斷,因此中斷每產生20次為1秒,當秒數為20時(每次有鍵輸入時都執行50毫秒數和秒數清0操作),關閉屏幕,并禁止鍵盤輸入。 當定時/計數器工作在定時方式時,定時時間的計算公式為: 定時時間=(216 —計數初值)×定時周期 晶振頻率為12MHz時,定時/計數器的定時周期為1μs,所以定時50ms的定時/計數器初值為: 計數初值=216 —50000 4.6 密碼輸入子程序 當從鍵盤輸入密碼時,應當將輸入的密碼存放,以便用做密碼的相關操作(判斷,修改和保存等),同時每輸入一位密碼應相應地在顯示器上顯示一個“*”號。圖4-8是密碼輸入子程序的流程圖。 
圖4-8 密碼輸入程序流程圖
輸入密碼時,當輸入的密碼位數小于6位的時候,每按下一次數字鍵,就將此數字存入數組。當輸入的密碼位數不小于6位時,再次按下數字鍵,程序就不進行任何處理,繼續掃描鍵盤,此時只有按下確定鍵或者取消鍵程序才做出相應反應。取消鍵的功能是退格。當不小心輸錯密碼時,可以退格將輸錯的位清除,退格一次密碼的位數減一位,同時顯示器上的“*”個數也減1。當輸入的密碼位數變為0時,取消鍵不再起作用。 4.7 報警子程序 報警子程序的原理很簡單,即當輸入密碼錯誤次數超過規定的最高允許次數時,不斷給蜂鳴器脈沖,使其不斷發音。同時,由于CPU一直在給蜂鳴器提供脈沖,故無暇處理諸如密碼掃描等事件,也就是說,在蜂鳴器報警的同時也屏蔽了鍵盤的輸入。 本次設計中,密碼輸入錯誤次數不得高于3次。圖4-9為報警子程序流程圖。 
圖4-9 報警子程序流程圖 第5章 聯合仿真和調試在PROTEUS中畫出仿真電路圖和在KEIL中編寫出程序后,需要驗證其正確性和可行性,最好的辦法就是就它們聯合起來仿真和調試。 KEIL和PROTEUS都是單片機愛好者和單片機相關工作者經常用到的具有相當好的輔助功能的軟件工具。KEIL是一款具有強悍功能的51系列兼容單片機C語言軟件開發系統,為用戶提供豐富的庫函數和功能強大的集成開發調試工具,其生成目標代碼的效率非常之高,且多數語句生成的匯編代碼很緊湊,容易理解。PROTEUS是目前世界上唯一一款將電路仿真軟件、PCB設計軟件和虛擬模型仿真軟件三合一的設計平臺。PROTEUS不僅具有其它電子設計自動化工具軟件的仿真功能,還能仿真單片機及外圍器件,是目前最好的仿真單片機及外圍器件的工具。 KEIL和PROTEUS都是單片機相關設計中經常用到的軟件,KEIL和PROTEUS的聯合仿真和調試能夠相當清晰地反映系統的各個功能模塊和器件的工作情況。通過KEIL和PROTEUS的聯合調試,單步執行程序或者在程序中設置斷點,可以有效地查看各語句的執行情況和各變量的值,從而找到程序中的錯誤。 KEIL和PROTEUS的聯合調試和仿真步驟如下: (1)在KEIL中建立工程,將編寫好的程序添加到工程中。 (2)在KEIL中為工程設置選項。為了實現和PROTEUS的聯合調試,除了一般工程選項的設置外,還要設置DUBUG項。具體方法為:單擊“工程菜單/為目標‘目標1’設置選項”選項,彈出窗口,點擊“Debug”按鈕。在出現的對話框里在右欄上部的下拉菜單里選中“Proteus VSM Monitor一51 Driver”。并且還要點擊一下“Use”前面表明選中的小圓點。再點擊“Setting”按鈕,設置通信接口,在“Host”后面添上“127.0.0.1”,如果使用的不是同一臺電腦,則需要在這里添上另一臺電腦的IP地址(另一臺電腦也應安裝Proteus)。在“Port”后面添加“8000”,然后點擊“OK”按鈕。最后將工程編譯,進入調試狀態,并運行。設置完之后,重新編譯、鏈接、生成可執行文件。 (3)PROTEUS設置。進入Proteus的ISIS,鼠標左鍵點擊菜單“Debug”, 選中“使用遠程調試監控”。 (4)將可執行文件加到單片機中。打開PROTEUS仿真圖,雙擊單片機,將KEIL產生的“*.HEX”文件添加到單片機中。 (5)KEIL與PROTEUS連接仿真調試。點擊PROTEUS的開始仿真按鈕即可開始KEIL與PROTEUS的聯合仿真和調試。 本次設計的聯合仿真結果如下圖所示。 
圖5-1 密碼正確后的仿真圖 密碼輸入正確后,點亮二極管,顯示器顯示歡迎回家畫面。通過觀察鍵盤引腳的電平,還能知道CPU正在掃描鍵盤第四行,等待功能鍵的輸入。 本設計中鍵盤第四行只用到了前兩個按鍵,后兩個按鍵沒有被使用。第一個按鍵為改密碼鍵,通過按鍵此鍵可以進入修改密碼功能界面;第二個鍵位閉鎖鍵,通過按下此鍵可以將鎖閉合,在設計中的直接表現是發光二極管熄滅。
第6章 實物設計和制作 聯合仿真調試通過后,本次設計業就進入了最后一步,但也是最關鍵的一步——實物設計和制作。 由于電路板空間有限,所有在進行實物設計之前應該根據系統的仿真電路圖做好各功能模塊的整體布局,這樣既可以使得實物設計的順利進行,也可以最大化的令做出來的實物看起來簡潔而美觀。 在本次設計中,實物設計是按以下步驟完成的: (1)單片機最小系統的電路焊接。只有保證了單片機最小系統的正確性,才能在接下來的其他模塊設計和焊接出現錯誤時能夠方便地檢查出原因,因此單片機最小系統是必須首先完成的。 (2)下載口電路的焊接。單片機最小系統電路焊接好后,需要檢查其正確性,這就需要往單片機中下載一個簡單的程序,看其是否能正常工作和復位,這就需要焊接一個下載口電路,此下載口電路還可以當做電源口使用,通過數據線連接電源即可給單片機供電。 圖6-1為單片機下載口電路接線圖。 圖6-1 下載口電路接線圖 其中MOSI接口接單片機的P1.5口,RST接單片機的復位端口,SCK接單片機的P1.7口,MISO接單片機的P1.6口。下載口的2端口接電源,4、6、8、10端口接地。在下載口接好后,應用單片機程序燒寫軟件通過下載口將測試程序下載進入單片機測試最小系統是否焊接正確。一般使用的測試方法是在單片機端口接一個發光二極管,通過程序控制二極管發光,若能點亮二極管則最小系統焊接正確。在本次設計中使用的單片機程序燒寫軟件為AVR_fighter。 (3)液晶顯示器及電路焊接。按照仿真電路原理圖和液晶顯示器接口使用說明焊接好液晶顯示器,將顯示子程序下載入單片機,若顯示器能夠按照要求顯示字符則焊接正確。 (4)鍵盤模塊焊接。按照鍵盤模塊仿真圖焊接按鍵,之后將測試程序導入單片機中檢驗按鍵是否正確焊接成功。本設計中檢驗按鍵的程序功能是當有按鍵按下時,將所按下的鍵值在液晶顯示器中顯示出來。 (5)E2PROM存儲器的焊接。根據AT24C02的引腳介紹,將AT24C02接到單片機上。測試AT24C02是否焊接正確的程序功能是將一個數組中的數寫入AT24C02,再將這一個數組中的數從AT24C02中讀出放入另一個數組中,比較兩個數組中的數是否相同,若相同則AT24C02的電路焊接正確,掉電存儲功能模塊功能實現。 (6)將蜂鳴器和發光二極管焊接到單片機系統中,將本次設計的源程序下載進入單片機中,看是否所有功能都實現了。若能夠實現所有功能則本次設計也就宣告完成,若不能實現,則根據出現的問題檢查線路,找出原因,直至能夠實現所有功能。 在實物制作過程中,應該注意幾個問題:第一,根據仿真圖焊接電路,但不能盡信仿真圖。仿真圖始終不能代替實物調試,在實物制作過程中應根據實際情況調試電路;第二,調試和查找錯誤過程中,如非必要應盡量不要帶電操作,以免損壞器件;第三,電路布局應盡量工整。工整簡潔的電路布局不但看著美觀,而且能夠更方便地查找電路錯誤。 本次設計的實物制作,由于經驗不足的原因,許多焊接點焊得不夠美觀,但是整體布局還是夠簡潔工整的。這也是設計中雖然經驗不足,制作過程中出現了各種各樣的問題,但是進展卻很順利的原因,簡潔工整的布局使得查找問題變得更加容易,能夠方便的理清電路,找出錯誤并加以改正。
總結本次設計經過近兩個月時間忙碌終于完成了,所有設計要求具備的功能都得到了實現,具體如下: (1)加電后,單片機自動復位,LCD顯示提示輸入密碼的信息; (2)輸入密碼時,只逐位顯示“*”,以防止密碼泄漏; (3)在按鍵輸入的過程中,如果不小心輸錯,可以清除所輸入的錯誤內容,然后繼續輸入; (4)當密碼輸入完畢并按下確認鍵后,單片機將輸入的密碼與設定的密碼比較,若密碼正確,則打開密碼鎖;若密碼不正確,則無法打開密碼鎖; (5)在密碼輸入錯誤次數達到預設值時,啟動報警程序報警; (6)可以在開鎖后進行密碼的修改,但需要兩次輸入確認; (7)修改的密碼存入AT24C02,不會因為掉電的原因而丟失; (8)在長時間沒有按鍵輸入時,系統鎖定顯示器,并禁止按鍵的輸入; (9)設定一個備用密碼,防止常用密碼忘記時無法開門。 由于設計水平有限,此次設計還是存在一些小缺陷的,比如報警系統的報警音量不夠大,雖然加了一個三極管作為驅動,使得問題得到了改善,但是問題還是沒有得到完美的解決。 另外,通過這幾個月對電子密碼鎖的研究和學習,我認為本次設計中使用的這種鍵盤輸入密碼的方式可以進行改革。在越來越高科技化的今天,遙控控制顯的愈發重要,今后的電子密碼鎖應該具有以紅外技術或無線電技術為輔助的密碼按鍵輸入遠程交互技術,這樣就能遠程輸入密碼完成操作。也可以放棄傳統的按鍵輸入密碼模式,借助傳感器技術運用聲控來實現密碼輸入,又或者使用人臉識別技術,或者用戶指紋識別技術代替傳統的按鍵輸入,這些都可以使開鎖的時間更短更方便,同時是鎖更安全。
致謝在老師的耐心指導和同學們的熱情幫助下,經過近三個月的不懈努力,本設計終于基本完成。在做設計的這段時間里,老師給我提供了極大的幫助和指導。從設計方向的分析到開題答辯報告的撰寫,從具體程序的設計到器件的選擇,老師都給了我很多很有用的建議。另外,老師親切和善、能和學生們打成一片的工作態度和認真負責的治學作風也給了我很深的印象。在此,對王老師表達最真誠的謝意和最崇高的敬意。 在做設計的過程中,自動化班的同學們也給我提供了很大的幫助,他們的關心和愛護不但幫助我更好地完成設計,更使我感受到了這個集體里家一樣的溫暖。非常感激自動化班的同學們。 同時,在即將離開校園的此時,衷心感謝每一位教導過我的老師和一直默默支持和鼓勵我的家人。 最后,我要向百忙之中抽出時間對本文進行審閱、評議和參與本人論文答辯的各位老師表示感謝。
附錄1 設計實物圖附圖1 實物正面圖
附圖2 實物反面圖 附錄2 程序源代碼
- #include <reg51.h>
- #include <string.h>
- #include <intrins.h>
- #include<stdio.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define NOP3() _nop_();_nop_();_nop_()
- uchar time_1s=0,i=0;
- uchar time_50ms=0;
- sbit rs=P2^2;
- sbit rw=P2^1;
- sbit e=P2^0;
- sbit SCL=P2^5;
- sbit SDA=P2^6;
- sbit P35=P3^5;
- sbit P36=P3^6;
- sbit P37=P3^7;
- uchar data kong[7]={'\0','\0','\0','\0','\0','\0',0};
- uchar data mima[7]={'1','2','3','4','5','6',0};
- uchar data mima0[7]={'\0','\0','\0','\0','\0','\0',0};
- uchar data mima1[7]={'\0','\0','\0','\0','\0','\0',0};
- uchar data mima2[7]={'\0','\0','\0','\0','\0','\0',0};
- uchar data mima3[7]={'\0','\0','\0','\0','\0','\0',0};
- uchar data table1[7]={'1','9','9','0','1','0',0};
- uchar code table2[15]="Enter Password:";
- uchar code table4[16]="Password Error!";
- uchar code table5[14]="Old Password:";
- uchar code table6[14]="New Password:";
- uchar code table7[12]="Enter Again:";
- uchar code table8[12]="Enter Error!";
- uchar code table9[15]="Modify Success!";
- uchar code table10[13]="Welcome back!";
- //***********************************
- //相關函數的聲明
- //***********************************
- void delay1ms();
- void delay(uchar n);
- void write_1602com(uchar com);
- void write_1602dat(uchar dat);
- void initinal(void);
- bit lcdbusy();
- uchar key_scan();
- void enter_password(void); //功能:顯示輸入密碼畫面
- void password_error(void);//功能:顯示輸入密碼錯誤后的畫面
- void ok(void);//功能:顯示輸入密碼正確后的畫面
- void new_password(void);//功能:顯示輸入新密碼的畫面
- void enter_again(void);//功能:顯示再次輸入新密碼的畫面
- void enter_error(void);//功能:顯示兩次輸入的密碼不一樣后的畫面
- void modify_success(void);//功能:顯示更改成功后的畫面
- void welcome(void); //功能:顯示歡迎畫面
- void wtite_1602com(uchar com);
- void write_1602dat(uchar dat);
- /*****************************************************
- 函數功能:延時若干毫秒
- 入口參數:n
- ***************************************************/
- void delay(uchar n)
- { unsigned char i,x,y;
- for(i=0;i<n;i++){for(x=0;x<10;x++)for(y=0;y<33;y++); } }
- /*****************************************************
- 函數功能:延時1ms
- ***************************************************/
- void delay1(uchar n){ unsigned char i,j;
- for(i=0;i<n;i++){ for(j=0;j<10;j++)delay(10);} }
- /*****************************************************
- 函數功能:定時器子函數,調用該函數可以計時
- ***************************************************/
- void time( ){ TMOD = 0x01; //定時器0,工作方式1
- TH0 = (65536-50000)/256;
- TL0 = (65536-50000)%256; //50ms中斷一次
- EA = 1;ET0 = 1;TR0 = 1;}
- /*****************************************************
- 函數功能:定時函數,在一段時間內沒有鍵按下則關閉顯示器
- ***************************************************/
- void time_1( ) interrupt 1{
- TH0 = (65536-65536)/256;TL0 = (65536-65536)%256;time_50ms++;
- if(time_50ms==20){time_1s++;time_50ms=0;}
- if(time_1s==20){write_1602com(0x01);write_1602com(0x0c);
- time_1s=0; while(1);}}
- //***********************************
- //功能:使蜂鳴器發音
- //***********************************
- void warn(){P37=1;NOP3();NOP3();NOP3();
- P37=0;NOP3();NOP3();NOP3(); }
- //***********************************
- //函數名:bit lcdbusy()
- //功能:檢測忙標志
- //***********************************
- bit lcdbusy(){bit result; rs=0;rw=1;e=1;
- delay(1);
- result=(bit)(P0&0x80);e=0;
- return result;}
- //************************************************
- //函數名:寫命令函數
- //功能:調用該函數可能定義1602液晶顯示器的各種命令
- //************************************************
- void write_1602com(uchar com){
- while(lcdbusy());
- e=0; rw=0; rs=0;
- P0=com; delay(1);
- e=1; delay(1);e=0;}
- //*************************************************
- //函數名:寫數據函數
- //功能:調入該函數可以向1602液晶顯示器輸入數據
- //*************************************************
- void write_1602dat(uchar dat){
- while(lcdbusy());e=0;rw=0;rs=1;
- P0=dat;delay(1);e=1;delay(1);e=0;}
- //**************************************************
- //函數名:初始化函數
- //功能:對1602液晶顯示器進行初始化
- //**************************************************
- void initinal(void){
- rs=0;e=0;
- write_1602com(0x38); //數據總線為8位,顯示2行,0=5×7點陣/每字符
- write_1602com(0x0f); //顯示功能開,有光標,光標不閃爍
- write_1602com(0x06); //顯示光標
- write_1602com(0x01); //清屏
- write_1602com(0x80);}
- //*********************************************
- //函數名:顯示函數
- //功能:顯示輸入密碼
- //*********************************************
- void enter_password(void){ uchar j;
- initinal();write_1602com(0x80);
- for(j=0;j<15;j++){write_1602dat(table2[j]);delay(10);}
- write_1602com(0xc0+0x0a);}
- //********************************************
- //函數名:顯示函數
- //功能:顯示輸入密碼錯誤后的畫面
- //********************************************
- void password_error(void){uchar j;
- write_1602com(0x0c); //顯示功能開,無光標
- write_1602com(0x80); //顯示位置第一行第一列
- write_1602com(0x01);
- for(j=0;j<15;j++){write_1602dat(table4[j]);delay(10);}}
- //******************************************
- //函數名:顯示函數
- //功能:顯示輸入舊密碼的畫面
- //******************************************
- void old_password(void){uchar j;
- initinal();write_1602com(0x80);
- for(j=0;j<14;j++){write_1602dat(table5[j]);delay(10);}
- write_1602com(0xc0+0x0a);}
- //******************************************
- //函數名:顯示函數
- //功能:顯示輸入新密碼的畫面
- //******************************************
- void new_password(void){uchar j;initinal();
- write_1602com(0x80);
- for(j=0;j<14;j++){write_1602dat(table6[j]);delay(10);}
- write_1602com(0xc0+0x0a);}
- //******************************************
- //函數名:顯示函數
- //功能:顯示再次輸入新密碼的畫面
- //******************************************
- void enter_again(void){uchar j;initinal();
- write_1602com(0x80);
- for(j=0;j<12;j++){write_1602dat(table7[j]);delay(10);}
- write_1602com(0xc0+0x0a);}
- //********************************************
- //函數名:顯示函數
- //功能:顯示兩次輸入的密碼不一樣后的畫面
- //********************************************
- void enter_error(void){uchar j;
- write_1602com(0x0c); //顯示功能開,無光標
- write_1602com(0x80); //顯示位置第一行第一列
- write_1602com(0x01);
- for(j=0;j<12;j++){write_1602dat(table8[j]);delay(10);}}
- //******************************************
- //函數名:顯示函數
- //功能:顯示更改成功之后的畫面
- //******************************************
- void modify_success(void){uchar j;write_1602com(0x0c);
- write_1602com(0x80);write_1602com(0x01);
- for(j=0;j<15;j++){write_1602dat(table9[j]);delay(10);}}
- //******************************************
- //函數名:顯示函數
- //功能:顯示歡迎畫面
- //******************************************
- void welcome(void){
- uchar j;
- write_1602com(0x0c); //顯示功能開,無光標
- write_1602com(0x80); //顯示位置第一行第4列
- write_1602com(0x01);
- write_1602com(0x80);
- for(j=0;j<13;j++){write_1602dat(table10[j]);delay(10);}}
- //**************************************************
- //函數名:鍵盤識別函數
- //功能:通過掃描對鍵盤進行識別
- //**************************************************
- uchar key_num(){uint temp,b;
- while(1){P1=0xfe; //開始掃描第一行
- temp=P1;
- temp=temp&0xf0;
- if(temp!=0xf0){delay(1);temp=P1;b=temp;temp=temp&0xf0;
- if(temp!=0xf0){
- while(temp!=0xf0){temp=P1;temp=temp&0xf0;}
- switch(b){case 0xee: return '4';break;
- case 0xde: return '3';break;
- case 0xbe: return '2';break;
- case 0x7e: return '1';break;}}}
- P1=0xfd; //掃描第二行
- temp=P1;
- temp=temp&0xf0;
- if(temp!=0xf0){delay(1);temp=P1;b=temp;temp=temp&0xf0;
- if(temp!=0xf0){
- while(temp!=0xf0){temp=P1;temp=temp&0xf0;}
- switch(b){case 0xed: return '8';break;
- case 0xdd: return '7';break;
- case 0xbd: return '6';break;
- case 0x7d: return '5';break;}}}
- P1=0xfb; //掃描第三行
- temp=P1;
- temp=temp&0xf0;
- if(temp!=0xf0){delay(1);temp=P1;b=temp;temp=temp&0xf0;
- if(temp!=0xf0){
- while(temp!=0xf0){temp=P1;temp=temp&0xf0;}
- switch(b){ case 0xeb: return 'b';break;
- case 0xdb: return 'a';break;
- case 0xbb: return '0';break;
- case 0x7b: return '9';break;}}}}}
- /****************************************
- 只掃描第四行,禁止數字鍵輸入
- ****************************************/
- uchar key_gn(){uint temp,b;
- while(1){P1=0xf7; //掃描第四行
- temp=P1;
- temp=temp&0xf0;
- if(temp!=0xf0){delay(1);temp=P1;b=temp;temp=temp&0xf0;
- if(temp!=0xf0){
- while(temp!=0xf0){ temp=P1;temp=temp&0xf0;}
- switch(b){case 0xe7: return 'f';break;
- case 0xd7: return 'e';break;
- case 0xb7: return 'd';break;
- case 0x77: return 'c';break;}}} }}
- /****************************************
- 密碼函數:將輸入的密碼寫放進數組
- ****************************************/
- uchar enter(uchar password[]){uchar m=0,j,back=0;
- for(m=0;;){j=key_num();time_50ms=0;time_1s=0;
- if(j>='0'&&j<='9'&&m<6){write_1602com(0x06);password[m]=j; m++;
- write_1602dat('*');}
- if(j=='a'){password[m+1]='\0';return 1;} if(j=='b'){if(m>0){write_1602com(0x11);write_1602dat(0x20);
- write_1602com(0x11);password[m]='\0';m--;}} }}
- /******************************************
- 啟動I2C總線函數
- ******************************************/
- void Start(){ SCL=1;
- SDA=1;NOP3();
- SDA=0;NOP3();
- SCL=0;}
- /******************************************
- I2C停止
- ******************************************/
- void Stop(){ SDA=0;
- SCL=1;NOP3();
- SDA=1;NOP3();}
- /******************************************
- 發送應答位函數
- ******************************************/
- void CHECK_ACK(){ SDA=0;NOP3();
- SCL=1;NOP3();
- SCL=0;NOP3();
- SDA=1;}
- /******************************************
- 發送非應答位函數
- ******************************************/
- void CHECK_NACK(){ SDA=1;NOP3();
- SCL=1;NOP3();
- SCL=0;NOP3();
- SDA=0;}
-
- /******************************************
- I2C初始化
- ******************************************/
- void Init_24cxx(){ SDA=1;NOP3();
- SCL=1;NOP3();}
- /******************************************
- 讀I2C函數
- ******************************************/
- uchar I2C_Read(){
- uchar i,temp;temp=0;
- SDA=1;SCL=0;
- for(i=0;i<8;i++){
- temp=temp<<1;SCL=1;NOP3();
- if(SDA==1){temp=temp+1;}NOP3();
- SCL=0; }
- return temp;}
- /******************************************
- 寫I2C函數
- ******************************************/
- void I2C_Write(uchar date1){
- uchar i,temp;temp=date1;
- SCL=0;
- for(i=0;i<8;i++){
- SDA=(bit)(temp&0x80);
- SCL=1;NOP3();SCL=0;
- temp=temp<<1;}NOP3();}
- /******************************************
- 寫相應地址的數據
- ******************************************/
- void Write_add(uint address,uchar date1){
- uchar addrh,addrl;
- addrh=address>>8;
- addrl=address%256;
- EA=0;
- Start();
- I2C_Write(0xa0);//發送命令字+芯片編號+P0+W
- CHECK_ACK();
- I2C_Write(addrh);//發高位地址
- CHECK_ACK();
- I2C_Write(addrl);//發低位地址
- CHECK_ACK();
- I2C_Write(date1);//發送數據
- CHECK_ACK();
- Stop();//停止
- EA=1;}
- /******************************************
- 讀相應地址的數據
- ******************************************/
- uchar Read_add(uint address){
- uchar addrh,addrl,temp;
- addrh=address>>8;
- addrl=address%256;
- EA=0;
- Start();
- I2C_Write(0xa0);
- CHECK_ACK();
- I2C_Write(addrh);//發高位地址
- CHECK_ACK();
- I2C_Write(addrl);//發低位地址
- CHECK_ACK();
- Start();
- I2C_Write(0xa1);
- CHECK_ACK();
- temp=I2C_Read();
- CHECK_NACK();
- Stop();
- EA=1;
- return temp;
- }
- /******************************************
- 寫數據函數:將數組寫入AT24C02
- ******************************************/
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
完整的Word格式文檔51黑下載地址:
基于單片機的電子密碼鎖設計(終稿).doc
(2.77 MB, 下載次數: 1452)
|