本系統(tǒng)采用以單片機(jī)為核心元件的控制方案。由于單片機(jī)種類(lèi)繁多,各種型號(hào)都有其一定的應(yīng)用環(huán)境,因此在選用時(shí)要多加比較,合理選擇,以獲得最佳的性價(jià)比。一般來(lái)說(shuō)在選取單片機(jī)時(shí)從下面幾個(gè)方面考慮:性能、存儲(chǔ)器、運(yùn)行速度、I/O口、定時(shí)/計(jì)數(shù)器、串行接口、模擬電路功能、工作電壓、功耗、封裝形式、抗干擾性、保密性,除了以上的一些方面外,還有一些最基本的條件,比如:中斷源的數(shù)量和優(yōu)先級(jí)、工作溫度范圍、有沒(méi)有低電壓檢測(cè)功能、單片機(jī)內(nèi)有無(wú)時(shí)鐘振蕩器、有無(wú)上電復(fù)位功能等。在開(kāi)發(fā)過(guò)程中還要考慮開(kāi)發(fā)工具、編程器、開(kāi)發(fā)成本、開(kāi)發(fā)人員的適應(yīng)性、技術(shù)支持和服務(wù)等因素。基于以上因素本設(shè)計(jì)選用單片機(jī)STC89C516作為本設(shè)計(jì)的核心元件,利用單片機(jī)靈活的編程設(shè)計(jì)和豐富的I/O端口,及其控制的準(zhǔn)確性,實(shí)現(xiàn)基本的密碼鎖功能。在單片機(jī)的外圍電路外接輸入鍵盤(pán)用于密碼的輸入和一些功能的控制,外接AT24C02芯片用于密碼的存儲(chǔ),外接LCD1602顯示器用于顯示作用。
二、 硬件設(shè)計(jì)硬件連接如下: P1 -->矩陣鍵盤(pán) P20--> EEPROM模塊SDA P21--> EEPROM模塊SCL P22-->繼電器模塊J15 其他管腳說(shuō)明: P0 LCD1602_DATAPINS P2^7 LCD1602_E; P2^5 LCD1602_RW; P2^6 LCD1602_RS;
P1 矩陣鍵盤(pán)
P2^1; 存儲(chǔ)模塊 24C02 SCL P2^0 存儲(chǔ)模塊 24C02 SDA 2.1 主控芯片2.2存儲(chǔ)模塊24c02存儲(chǔ)模塊的設(shè)計(jì)是把WP引腳接到GND上因?yàn)橐屍骷M(jìn)行正常的讀/寫(xiě)操作,把SDA串行數(shù)據(jù)/地址與單片機(jī)的P2.0引腳使AT24C02與單片機(jī)進(jìn)行所有數(shù)據(jù)的發(fā)送或接收,把SCL串行時(shí)鐘引腳與單片機(jī)的P2.1引腳相連接,讓單片機(jī)產(chǎn)生一個(gè)AT24C02工作的時(shí)鐘,使其正常的工作。存儲(chǔ)模塊電路如圖所示。 AT24C02的特點(diǎn):數(shù)據(jù)線看門(mén)狗定時(shí)器;可編程復(fù)位門(mén)級(jí);高數(shù)據(jù)傳輸速率400kHz速率和I2C總線;2.7V至7V電壓;低功耗CMOS工藝兼容;16 bespate寫(xiě)緩沖區(qū);反撇寫(xiě)保護(hù)芯片;高低電平復(fù)位信號(hào)輸出;100萬(wàn)擦除周期;保存長(zhǎng)達(dá)100年。  2.3顯示模塊LCD1602如果想要了解系統(tǒng)的運(yùn)行與工作狀態(tài)顯示器是不可缺少的,顯示器是一個(gè)典型的輸出設(shè)備并且它的實(shí)際應(yīng)用也是極為廣泛的,幾乎所有的電子產(chǎn)品都會(huì)使用到顯示器其差別僅在于顯示器的結(jié)構(gòu)類(lèi)型不同而已。最簡(jiǎn)單的顯示器可以是LED發(fā)光二極管或者數(shù)碼管,它可以給出一個(gè)簡(jiǎn)單的開(kāi)關(guān)信息或者數(shù)字顯示,而需要顯示復(fù)雜的完整的信息上述的器件就不能勝任,而液晶的出現(xiàn)就很好的解決了這一問(wèn)題,它不僅顯示內(nèi)容豐富而且好節(jié)約了單片機(jī)的管腳資源。本設(shè)計(jì)采用的是液晶顯示LCD1602。LCD1602內(nèi)部的字符已經(jīng)儲(chǔ)存了不同的字符形式,每一個(gè)字符都有一個(gè)固定的代碼,其代碼與標(biāo)準(zhǔn)的ASCII字符代碼一致。因此只要寫(xiě)入顯示字符的ASCII碼即可,這種標(biāo)準(zhǔn)化的設(shè)計(jì)給使用帶來(lái)很大的方便。比如英文字母“C”的ASCII代碼是01000011(43H),顯示時(shí)單片機(jī)往液晶模塊寫(xiě)入顯示指令,模塊就會(huì)把地址為43H中的點(diǎn)陣字符圖形識(shí)別出,并會(huì)在液晶屏相應(yīng)位置上看到字母“C”。 目前市場(chǎng)字符液晶絕大多數(shù)是基于HD44780的液晶芯片,控制原理是完全相同的,因此基于HD44780的寫(xiě)控制程序可以很容易地應(yīng)用到市場(chǎng)上大部分的字符液晶。LCD1602液晶的幾個(gè)特性:+5V電壓、對(duì)比度可調(diào)、內(nèi)含復(fù)位電路;提供各種控制命令,如:清屏、字符閃爍、光標(biāo)閃爍、顯示移位等多種功能;有80字節(jié)顯示數(shù)據(jù)存儲(chǔ)器DDRAM;內(nèi)建有160個(gè)5X7點(diǎn)陣的字型的字符發(fā)生器CGROM 8個(gè)可由用戶自定義的5X7的字符發(fā)生器CGRAM。1602的引腳如下所示: LCD1602采用標(biāo)準(zhǔn)的16腳接口,其中VSS為地電源,VDD接5V正電源,VEE為液晶顯示器。RS為寄存器選擇,高電平時(shí)選擇數(shù)據(jù)寄存器、低電平時(shí)選擇指令寄存器。RW為讀寫(xiě)信號(hào)線,高電平1時(shí)進(jìn)行讀操作,低電平0時(shí)進(jìn)行寫(xiě)操作。E端為使能端。D0~D7為8位雙向數(shù)據(jù)線。 2.4鍵盤(pán)輸入模塊鍵盤(pán)是單片機(jī)十分重要的輸入設(shè)備,是實(shí)現(xiàn)人機(jī)對(duì)話的紐帶。鍵盤(pán)是由一組規(guī)則排列的按鍵組成,一個(gè)按鍵實(shí)際上就是一個(gè)開(kāi)關(guān)元件,即鍵盤(pán)是一組規(guī)則排列的開(kāi)關(guān)。根據(jù)按鍵與單片機(jī)的連接方式不同,按鍵主要分為獨(dú)立式按鍵和矩陣式按鍵 ,有了這些按鍵,對(duì)單片機(jī)的控制就方便多了。 本設(shè)計(jì)按鍵數(shù)量較多,所以采用矩陣式按鍵以節(jié)省I/O口線。將16個(gè)按鍵分為4排4列排列好,下圖是矩陣鍵盤(pán)硬件結(jié)構(gòu)。當(dāng)有一個(gè)鍵按下時(shí),通過(guò)某一邊引腳賦低電平,掃描全部引腳看是否與最初的賦值一樣,不一樣則根據(jù)相應(yīng)的算法(通過(guò)改變后的值與初始值相或,根據(jù)結(jié)果賦值)確定是哪個(gè)鍵按下。
2.5開(kāi)鎖電路開(kāi)鎖電路的功能是當(dāng)輸入正確的密碼后密碼鎖將被鎖定,既開(kāi)鎖。當(dāng)單片機(jī)P2.2引腳發(fā)出信號(hào)經(jīng)三極管放大后,觸動(dòng)電磁閥即會(huì)把鎖打開(kāi)。一旦輸入密碼,單片機(jī)便會(huì)與初始密碼進(jìn)行比對(duì),如果密碼輸入3次都與原始密碼不相符即會(huì)報(bào)警。其原理圖如圖3-11所示 
四、 實(shí)驗(yàn)現(xiàn)象將線連接好并將程序下載后,可以看到1602上顯示: 此時(shí)可以按下任意鍵繼續(xù) 在這里我們可以“1”或“9”選擇開(kāi)鎖或者是修改密碼。如果這里選擇的開(kāi)鎖,按下確定鍵,此時(shí)會(huì)提示輸入密碼,初始密碼默認(rèn)為888888,輸入密碼 然后按下確定鍵,如果密碼正確則會(huì)顯示:并且可以看到繼電器模塊指示燈亮并可以聽(tīng)到繼電器閉合的聲音。 如果密碼錯(cuò)誤則會(huì)提示:Error.
如果需要修改密碼,則選擇Change password 
這里會(huì)提示輸入密碼: 
輸入原密碼 
按下確認(rèn)鍵,如果密碼正確會(huì)提示輸入新密碼, 輸入密碼后按下確認(rèn)鍵,會(huì)提示OK并返回到待機(jī)畫(huà)面。
三、 軟件設(shè)計(jì)
3.1 按鍵掃描
按鍵掃描程序如下:
#include "key.h"
u8 KeyValue=0;
void delay(u16 i)
{
while(i--);
}
u8 KeyDown(void)
{
char a=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//有按鍵按下
{
delay(1000);//延時(shí)10ms去抖
if(GPIO_KEY!=0x0f)//有按鍵按下
{
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
}
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+4;break;
case(0Xd0): KeyValue=KeyValue+8;break;
case(0Xe0): KeyValue=KeyValue+12;break;
}
while((a<50)&&(GPIO_KEY!=0xf0))
{
delay(1000);
a++;
}
}
}
else
{
KeyValue=0xff; //無(wú)按鍵按下
}
return KeyValue; //返回KeyValue
}
從前面硬件電路中可以看到,P1口的低四位接的4*4矩陣鍵盤(pán)的行,高四位接的矩陣鍵盤(pán)的列。檢測(cè)矩陣鍵盤(pán)是否有按鍵按下時(shí):先將P1端口的低四位置1,高四位清零,檢測(cè)P1端口的狀態(tài),如果高四位不為零,則表示有按鍵按下,并且可以知道是x0-x3哪一列有按鍵按下,比如P1=0x1f;則第一列有按鍵按下。此時(shí)我們?cè)趯1口第四位清零,高四位置1;檢測(cè)P1的狀態(tài),就知道y0-y3哪一行有按鍵按下。結(jié)合x(chóng)y就可以知道具體是哪個(gè)按鍵按下。
3.2 1602初始化
16002初始化程序如下:
#include "lcd.h"
uchar i;
/*******************************************************************************
* 函 數(shù) 名 : Lcd1602_Delay1ms
* 函數(shù)功能 : 延時(shí)函數(shù),延時(shí)1ms
* 輸 入 : c
* 輸 出 : 無(wú)
* 說(shuō) 名 : 該函數(shù)是在12MHZ晶振下,12分頻單片機(jī)的延時(shí)。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //誤差 0us
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
* 函 數(shù) 名 : LcdWriteCom
* 函數(shù)功能 : 向LCD寫(xiě)入一個(gè)字節(jié)的命令
* 輸 入 : com
* 輸 出 : 無(wú)
*******************************************************************************/
#ifndef LCD1602_4PINS //當(dāng)沒(méi)有定義這個(gè)LCD1602_4PINS時(shí)
void LcdWriteCom(uchar com) //寫(xiě)入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //選擇發(fā)送命令
LCD1602_RW = 0; //選擇寫(xiě)入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待數(shù)據(jù)穩(wěn)定
LCD1602_E = 1; //寫(xiě)入時(shí)序
Lcd1602_Delay1ms(5); //保持時(shí)間
LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com) //寫(xiě)入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //選擇寫(xiě)入命令
LCD1602_RW = 0; //選擇寫(xiě)入
LCD1602_DATAPINS = com; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫(xiě)入時(shí)序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = com << 4; //發(fā)送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫(xiě)入時(shí)序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 數(shù) 名 : LcdWriteData
* 函數(shù)功能 : 向LCD寫(xiě)入一個(gè)字節(jié)的數(shù)據(jù)
* 輸 入 : dat
* 輸 出 : 無(wú)
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat) //寫(xiě)入數(shù)據(jù)
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //選擇輸入數(shù)據(jù)
LCD1602_RW = 0; //選擇寫(xiě)入
LCD1602_DATAPINS = dat; //寫(xiě)入數(shù)據(jù)
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫(xiě)入時(shí)序
Lcd1602_Delay1ms(5); //保持時(shí)間
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) //寫(xiě)入數(shù)據(jù)
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //選擇寫(xiě)入數(shù)據(jù)
LCD1602_RW = 0; //選擇寫(xiě)入
LCD1602_DATAPINS = dat; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫(xiě)入時(shí)序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //寫(xiě)入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫(xiě)入時(shí)序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/**********************************************************************
***********************************************************************/
/*****************************************************************************
函數(shù)名 :
函數(shù)功能 :顯示*
**********************************************************************************/
/******************************************************************************/
/****************************************************************************/
/**************************************************
字符串顯示函數(shù)
Coordinate 高四位顯示坐標(biāo)的X,第四位顯示坐標(biāo)的Y
如在第一行從第一位開(kāi)始顯示 hello: ShowString (0x01,“hello”);
************************************************/
void ShowString (unsigned char Coordinate,char *ptr)
{
if(Coordinate<=0x0f) //高四位為0,顯示第一行
{
LcdWriteCom((Coordinate&0x0f)+0x80);
while(*ptr!='\0')
{
LcdWriteData(*ptr);
ptr++;
}
}
else //高四位為1,顯示第2行
{
LcdWriteCom((Coordinate&0x0f)+0xc0);
while(*ptr!='\0')
{
LcdWriteData(*ptr);
ptr++;
}
}
}
/**************************************************************************/
/*******************************************************************************
* 函 數(shù) 名 : LcdInit()
* 函數(shù)功能 : 初始化LCD屏
* 輸 入 : 無(wú)
* 輸 出 : 無(wú)
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //開(kāi)顯示
LcdWriteCom(0x0c); //開(kāi)顯示不顯示光標(biāo)
LcdWriteCom(0x06); //寫(xiě)一個(gè)指針加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //設(shè)置數(shù)據(jù)指針起點(diǎn)
}
#else
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //將8位總線轉(zhuǎn)為4位總線
LcdWriteCom(0x28); //在四位線下的初始化
LcdWriteCom(0x0c); //開(kāi)顯示不顯示光標(biāo)
LcdWriteCom(0x06); //寫(xiě)一個(gè)指針加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //設(shè)置數(shù)據(jù)指針起點(diǎn)
}
#endif
1602的初始化函數(shù)比較長(zhǎng),但其中大部分是1602驅(qū)動(dòng)的底層協(xié)議,初學(xué)者不必深究,只需要學(xué)會(huì)怎么使用即可。這里簡(jiǎn)單介紹幾個(gè)常用的函數(shù)。
LcdWriteCom()
1602的寫(xiě)命令函數(shù),通過(guò)此函數(shù)向1602寫(xiě)命令。比如:清屏LcdWriteCom(0x01); LcdWriteCom(0x80); //設(shè)置數(shù)據(jù)指針起點(diǎn)
LcdWriteData()
當(dāng)需要在1602上顯示時(shí),就需要用到LcdWriteData(),不過(guò)在寫(xiě)數(shù)據(jù)之前需要通過(guò)LcdWriteCom()函數(shù)告訴要寫(xiě)數(shù)據(jù)的地址,1602的第一行的16個(gè)顯示位地址是0x80到0x8f;第二行的地址是0xc0到0xcf。比如在1602的第一行第一位顯示數(shù)字8:LcdWriteCom(0x80);
LcdWriteData(‘8’);
ShowString (unsigned char Coordinate,char *ptr)
ShowString (首地址,字符串)函數(shù)在需要顯示字符串時(shí)使用。比如在第二行第3位開(kāi)始顯示hello:
ShowString (0x13,”hello”);
其中首地址的高四位為0則表示在第一排顯示,為“1”則在第二排顯示。低四位為0則在第0位顯示。
3.3 24C02初始化
24C02的初始化如下:
#include"i2c.h"
/*******************************************************************************
* 函數(shù)名 : Delay10us()
* 函數(shù)功能 : 延時(shí)10us
* 輸入 : 無(wú)
* 輸出 : 無(wú)
*******************************************************************************/
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
/*******************************************************************************
* 函數(shù)名 : I2cStart()
* 函數(shù)功能 : 起始信號(hào):在SCL時(shí)鐘信號(hào)在高電平期間SDA信號(hào)產(chǎn)生一個(gè)下降沿
* 輸入 : 無(wú)
* 輸出 : 無(wú)
* 備注 : 起始之后SDA和SCL都為0
*******************************************************************************/
void I2cStart()
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();//建立時(shí)間是SDA保持時(shí)間>4.7us
SDA=0;
Delay10us();//保持時(shí)間是>4us
SCL=0;
Delay10us();
}
/*******************************************************************************
* 函數(shù)名 : I2cStop()
* 函數(shù)功能 : 終止信號(hào):在SCL時(shí)鐘信號(hào)高電平期間SDA信號(hào)產(chǎn)生一個(gè)上升沿
* 輸入 : 無(wú)
* 輸出 : 無(wú)
* 備注 : 結(jié)束之后保持SDA和SCL都為1;表示總線空閑
*******************************************************************************/
void I2cStop()
{
SDA=0;
Delay10us();
SCL=1;
Delay10us();//建立時(shí)間大于4.7us
SDA=1;
Delay10us();
}
/*******************************************************************************
* 函數(shù)名 : I2cSendByte(unsigned char dat)
* 函數(shù)功能 : 通過(guò)I2C發(fā)送一個(gè)字節(jié)。在SCL時(shí)鐘信號(hào)高電平期間,保持發(fā)送信號(hào)SDA保持穩(wěn)定
* 輸入 : num
* 輸出 : 0或1。發(fā)送成功返回1,發(fā)送失敗返回0
* 備注 : 發(fā)送完一個(gè)字節(jié)SCL=0,SDA=1
*******************************************************************************/
unsigned char I2cSendByte(unsigned char dat)
{
unsigned char a=0,b=0;//最大255,一個(gè)機(jī)器周期為1us,最大延時(shí)255us。
for(a=0;a<8;a++)//要發(fā)送8位,從最高位開(kāi)始
{
SDA=dat>>7; //起始信號(hào)之后SCL=0,所以可以直接改變SDA信號(hào)
dat=dat<<1;
Delay10us();
SCL=1;
Delay10us();//建立時(shí)間>4.7us
SCL=0;
Delay10us();//時(shí)間大于4us
}
SDA=1;
Delay10us();
SCL=1;
while(SDA)//等待應(yīng)答,也就是等待從設(shè)備把SDA拉低
{
b++;
if(b>200) //如果超過(guò)2000us沒(méi)有應(yīng)答發(fā)送失敗,或者為非應(yīng)答,表示接收結(jié)束
{
SCL=0;
Delay10us();
return 0;
}
}
SCL=0;
Delay10us();
return 1;
}
/*******************************************************************************
* 函數(shù)名 : I2cReadByte()
* 函數(shù)功能 : 使用I2c讀取一個(gè)字節(jié)
* 輸入 : 無(wú)
* 輸出 : dat
* 備注 : 接收完一個(gè)字節(jié)SCL=0,SDA=1.
*******************************************************************************/
unsigned char I2cReadByte()
{
unsigned char a=0,dat=0;
SDA=1; //起始和發(fā)送一個(gè)字節(jié)之后SCL都是0
Delay10us();
for(a=0;a<8;a++)//接收8個(gè)字節(jié)
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
SCL=0;
Delay10us();
}
return dat;
}
/*******************************************************************************
* 函數(shù)名 : void At24c02Write(unsigned char addr,unsigned char dat)
* 函數(shù)功能 : 往24c02的一個(gè)地址寫(xiě)入一個(gè)數(shù)據(jù)
* 輸入 : 無(wú)
* 輸出 : 無(wú)
*******************************************************************************/
void At24c02Write(unsigned char addr,unsigned char dat)
{
I2cStart();
I2cSendByte(0xa0);//發(fā)送寫(xiě)器件地址
I2cSendByte(addr);//發(fā)送要寫(xiě)入內(nèi)存地址
I2cSendByte(dat); //發(fā)送數(shù)據(jù)
I2cStop();
}
/*******************************************************************************
* 函數(shù)名 : unsigned char At24c02Read(unsigned char addr)
* 函數(shù)功能 : 讀取24c02的一個(gè)地址的一個(gè)數(shù)據(jù)
* 輸入 : 無(wú)
* 輸出 : 無(wú)
*******************************************************************************/
unsigned char At24c02Read(unsigned char addr)
{
unsigned char num;
I2cStart();
I2cSendByte(0xa0); //發(fā)送寫(xiě)器件地址
I2cSendByte(addr); //發(fā)送要讀取的地址
I2cStart();
I2cSendByte(0xa1); //發(fā)送讀器件地址
num=I2cReadByte(); //讀取數(shù)據(jù)
I2cStop();
return num;
}
24c02采用IIC與單片機(jī)通信,其詳細(xì)通信時(shí)序參考24C02數(shù)據(jù)手冊(cè)。我們只需使用At24c02Read(unsigned char addr)和At24c02Write(unsigned char addr,unsigned char dat)即可。
Keil代碼工程文件下載:
電子密碼鎖Keil代碼.7z
(1.93 MB, 下載次數(shù): 123)
2021-10-8 03:01 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|