標(biāo)題:
51單片機(jī)+PCF8574簡易密碼鎖程序 帶詳細(xì)注釋 1602顯示
[打印本頁]
作者:
LUQIMAI
時(shí)間:
2020-6-8 08:17
標(biāo)題:
51單片機(jī)+PCF8574簡易密碼鎖程序 帶詳細(xì)注釋 1602顯示
本帖最后由 LUQIMAI 于 2020-6-10 12:52 編輯
* 名稱:基于STC51的簡易密碼鎖
* 硬件配置:IAP15W4K61S4+LCD1602+PCF8574+4*4矩陣鍵盤
* 功能說明:鍵盤表
* [ 0,1,2,3,
* 4,5,6,7,
* 8,9,a,b,
* c,d,e,f
* ]
* 按鍵說明:f:確認(rèn)鍵;e:設(shè)置鍵;b:上鎖鍵
* 初始密碼:1234
* 開門流程:通電,輸入初始密碼,按f鍵,提示open,同時(shí)P2燈亮代表開門。
* 修改密碼流程:通電后,按e鍵,首先輸入舊的密碼(第一次設(shè)置時(shí),舊密碼就是初始密碼),按照LCD提示操作即可。
* 上鎖流程:開門后,按下b鍵,上鎖,P2燈滅
* 燈光說明:流水燈-在修改密碼時(shí),每一步成功都會(huì)有流水燈提示
* 全亮燈-門開
* 全滅燈-門關(guān)
* 不足之處:1.不知是單片機(jī)識(shí)別出現(xiàn)問題,還是鍵盤讀入的問題。有時(shí)輸入正確的密碼,但提示錯(cuò)誤,慢慢的按鍵輸入,出錯(cuò)的幾率會(huì)低些
* 2.需要一直通電,如果重新供電后,修改的密碼會(huì)失效,所以離應(yīng)用到實(shí)際生活還有距離
* 3.暫時(shí)這些,有問題望指
* 如果有不同想法的朋友,歡迎一起交流學(xué)習(xí)!
硬件連接圖如下:
硬件連接的詳細(xì)接法程序中有,不清楚的也可以直接回帖問我
51hei圖片_20200607182508.jpg
(98.41 KB, 下載次數(shù): 52)
下載附件
2020-6-8 08:14 上傳
注意注意!。!做了幾處修改,下面是優(yōu)化版
注意注意。。!做了幾處修改
,下面是優(yōu)化版
注意注意。。。∽隽藥滋幮薷
,下面是優(yōu)化版
修改: 1.添加刪除功能
2.優(yōu)化了幾處錯(cuò)誤,基本完成所有密碼鎖的功能
如有發(fā)現(xiàn)其他錯(cuò)誤,望不惜賜教!!
此處是優(yōu)化版的源碼,請下載這個(gè):
優(yōu)化版.rar
(83.14 KB, 下載次數(shù): 44)
2020-6-10 12:51 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
(有幾處錯(cuò)誤)單片機(jī)源程序如下:
#include <stc15.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define KeyPort P0 //外接鍵盤,低四位接行,高四位接列
uchar KEY_TABLE[16] =
{
0xEE, 0xDE, 0xBE, 0x7E,
0xED, 0xDD, 0xBD, 0x7D,
0xEB, 0xDB, 0xBB, 0x7B,
0xE7, 0xD7, 0xB7, 0x77
};
int flag1=0; //修改密碼標(biāo)志位
uchar num,i=0,j;
uchar passwordtemp[16],password[16]={'1','2','3','4'},newpassword[16]; //輸入的密碼,默認(rèn)的密碼
uchar inputtimes; //密碼輸入錯(cuò)誤次數(shù)
uint n,m; //輸入密碼長度,實(shí)際密碼長度
bit Flag=0;\
uchar light,light1=0,light2=0xf0; //設(shè)置成功,開鎖,錯(cuò)誤,
sbit SCL = P1^0;
sbit SDA = P1^1;
char ADDR = 0x4e; // PCF8574 T 模塊的地址碼
//char ADDR = 0x7e; // PCF8574 AT 模塊的地址碼
//***************************** 延時(shí) y ms ***********************************************
void delay1(int y) //
{
;
while(y--)
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
}
//******************************** IIC 串口開始 ********************************************
void IIC_start(void)
{
SDA=1;
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=0;
_nop_();
_nop_();
}
//********************************** IIC 串口寫1個(gè)字節(jié) ******************************************
void IIC_writeByte(char temp)
{
char i;
for(i=0;i<8;i++)
{
SDA=(bit)(temp & 0x80) ; // 根據(jù)規(guī)定1602的數(shù)據(jù)最高位必須為 1
temp <<=1;
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=0;
}
_nop_();
_nop_();
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
while(SDA);
_nop_();
SCL=0;
}
//******************************** 1602寫命令 ********************************************
void LCD_write_command(char comm)
{
char tmp;
IIC_start(); // 串口開始
IIC_writeByte(ADDR); // 先選PCF 8574T 的地址 (應(yīng)該是相當(dāng)于選中的意思吧)
tmp = comm & 0xF0; // 與0xf0 應(yīng)該是取第四位的意思吧
tmp |= 0x0C; //保留高4位為指令的高四位,低四位為 RS = 0, RW = 0, EN = 1
IIC_writeByte(tmp); //從串口送出
delay1(20);
tmp &= 0xFB; //Make EN = 0
IIC_writeByte(tmp);
tmp = (comm & 0x0F) << 4 ; //將指令的低四位 送到高位置保存
tmp |= 0x0C; //RS = 0, RW = 0, EN = 1
IIC_writeByte(tmp);
delay1(20);
tmp &= 0xFB; // Make EN = 0
IIC_writeByte(tmp);
}
//******************************** 1602寫數(shù)據(jù) ********************************************
void LCD_write_data(char data1)
{
char tmp;
IIC_start();
IIC_writeByte(ADDR); // 先選PCF 8574T 的地址 (應(yīng)該是相當(dāng)于選中的意思吧)
tmp = data1 & 0xF0;
tmp |= 0x0D; //RS = 1, RW = 0, EN = 1
IIC_writeByte(tmp);
delay1(20);
tmp &= 0xFB; //Make EN = 0
IIC_writeByte(tmp);
tmp = (data1 & 0x0F) << 4 ;
tmp |= 0x0D; //RS = 0, RW = 0, EN = 1
IIC_writeByte(tmp);
delay1(20);
tmp &= 0xFB ; // Make EN = 0
IIC_writeByte(tmp);
}
//******************************** 1602初始化 ********************************************
void Init_Lcd(void)
{
LCD_write_command(0x33); //將8位總線轉(zhuǎn)為4位總線
delay1(50) ;
LCD_write_command(0x32); //
delay1(50) ;
LCD_write_command(0x28); // 4位數(shù)據(jù)線,顯示2行,5*7點(diǎn)陣字符 !如果是0x38 則為8位數(shù)據(jù)線,顯示2行,5*7點(diǎn)陣字符
delay1(50) ;
LCD_write_command(0x0C); // 開顯示,關(guān)閉光標(biāo),不閃爍
delay1(50) ;
LCD_write_command(0x06); // 設(shè)定輸入方式,增量不位移
delay1(50) ;
LCD_write_command(0x01); // 清屏
delay1(50) ;
}
//*************************************** 在指定位置顯示字符串 *************************************
void Write_LCD(int x, int y, char *str)
{
char addr;
if( x < 0)
{
x = 0;
}
if(x > 15)
{
x = 15;
}
if(y<0)
{
y = 0;
}
if(y > 1)
{
y = 1;
}
addr = 0x80 + 0x40 * y + x; // Move cursor 移動(dòng)光標(biāo)
LCD_write_command(addr);
while (*str)
{
LCD_write_data(*str++);
}
}
//-------------------------------------------- 顯示字符串的函數(shù) ----------------------------------------------------
void LCD_write_word(unsigned char *s) //顯示字符串的函數(shù)
{
while(*s>0)
{
LCD_write_data(*s);
s++;
}
}
//********************************* 指定位置顯示一個(gè)字符*******************************************
/*
void Print_Char (unsigned char line,unsigned char num,unsigned char date)
{
LCD_write_command(line+num);
LCD_write_data(date);
}
*/
//按指定位置顯示一個(gè)字符(針對1602液晶)-用在溫度顯示
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //當(dāng)要顯示第二行時(shí)地址碼+0x40;
X |= 0x80; // 算出指令碼
LCD_write_command(X); //這里不檢測忙信號(hào),發(fā)送地址碼
LCD_write_data(DData);
}
//--------------------------------------初始化----------------------------------------------------------------
void initial()
{
P1M0=0;
P1M1=0;
P2M0=0;
P2M1=0;
P0M0=0;
P0M1=0;
}
/*------------------------------------------------
按鍵掃描函數(shù),返回掃描鍵值
------------------------------------------------*/
unsigned char KeyScan(void) //鍵盤掃描函數(shù),使用行列反轉(zhuǎn)掃描法
{
uchar cord_h,cord_l; //行列值中間變量
uchar tempt;
uint i;
KeyPort=0xf0; //列線輸出全為0
cord_l=KeyPort&0xf0; //讀入行線值
if(cord_l!=0xf0) //先檢測有無按鍵按下
{
delay1(10); //去抖
if(cord_l!=0xf0)
{
cord_l=KeyPort&0xf0; //讀入列線值
KeyPort=0x0f; //行線輸出為0
cord_h=KeyPort&0x0f; //讀入行線值
while((KeyPort&0x0f)!=0x0f);//等待松開并輸出
tempt = cord_l+cord_h;
for(i=0;i<16;i++)
if(KEY_TABLE[i]==tempt)
break;
return(KEY_TABLE[i]);
}
}
return(0xff); //返回該值
}
/*------------------------------------------------
按鍵值處理函數(shù),返回掃鍵值
------------------------------------------------*/
unsigned char KeyPro(void)
{
switch(KeyScan())
{
case 0xee:return '0';break;//0 按下相應(yīng)的鍵顯示相對應(yīng)的碼值
case 0xde:return '1';break;//1
case 0xbe:return '2';break;//2
case 0x7e:return '3';break;//3
case 0xed:return '4';break;//4
case 0xdd:return '5';break;//5
case 0xbd:return '6';break;//6
case 0x7d:return '7';break;//7
case 0xeb:return '8';break;//8
case 0xdb:return '9';break;//9
case 0xbb:return 'a';break;//a
case 0x7b:return 'b';break;//b
case 0xe7:return 'c';break;//c
case 0xd7:return 'd';break;//d
case 0xb7:return 'e';break;//e
case 0x77:return 'f';break;//f
default:return 0xff;break;
}
}
//--------------------------------------------------------流水燈--------------------------------------------------------
void RuningLight() //流水燈
{
light=0xfe;
P2=light;
for(j=0;j<8;j++)
{ light<<=1 ;
delay1(250);
P2=light;
}
P2=0xff;
}
//--------------------------------------------------------密碼驗(yàn)證--------------------------------------------------------
void VriefytPassword() //驗(yàn)證密碼
{ if(flag1)
m=sizeof(newpassword); //記錄新密碼的長度
else
m=sizeof(password); //記錄舊密碼的長度
n=sizeof(passwordtemp); //記錄輸入密碼的長度
if(m==n) //長度判斷
{
if(flag1) //修改密碼后
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應(yīng)
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
else //修改密碼前
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應(yīng)
{ if(passwordtemp[j]==password[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
{ Flag=1;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Wrong length!"); //密碼正確顯示的信息
delay1(10);
}
if(Flag) //輸入錯(cuò)誤提示和輸入錯(cuò)誤總次數(shù)判斷,限定三次
{
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Wrong Retry!"); //輸入錯(cuò)誤提示
for(j=0;j<sizeof(passwordtemp);j++) //清除輸入的錯(cuò)誤密碼
passwordtemp[j]='\0';
inputtimes++; //連續(xù)輸入錯(cuò)誤,則次數(shù)累加
i=0;
if(inputtimes==3)
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Wrong 3 times!");//密碼錯(cuò)誤,提示重新輸入
while(1)
P2=light2; //停止該位置,重啟電源后才能輸入,實(shí)際實(shí)用中則需要等到一定時(shí)間后才能再次輸入。
}
}
else
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Right Open!>>>>");//密碼正確顯示的信息
P2=light1;
inputtimes=0;//輸入正確則次數(shù)清零,重新計(jì)數(shù)
Flag=0; //清除正確標(biāo)志
i=0;
}
}
//--------------------------------------------------------修改密碼時(shí)的密碼驗(yàn)證--------------------------------------------------------
void SetPassword() //設(shè)置新密碼時(shí),先驗(yàn)證
{ while(1)
{ num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進(jìn)行處理
{
if(i==0)
Write_LCD(0,1," ");//清除該行
if(num=='f') //確定鍵按下,進(jìn)入判斷密碼對錯(cuò)
{
i=0;
if(flag1)
m=sizeof(newpassword);
else
m=sizeof(password);
n=sizeof(passwordtemp);
if(m==n) //長度判斷
{ if(flag1)
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應(yīng)
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應(yīng)
{ if(passwordtemp[j]==password[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
{ Flag=1;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Wrong length!"); //密碼正確顯示的信息
delay1(10);
i=0;
P2=light2;
inputtimes++;
}
if(Flag) //輸入錯(cuò)誤提示和輸入錯(cuò)誤總次數(shù)判斷,限定三次
{
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Wrong Retry!"); //密碼錯(cuò)誤
for(j=0;j<sizeof(passwordtemp);j++)
passwordtemp[j]='\0';
inputtimes++; //連續(xù)輸入錯(cuò)誤,則次數(shù)累加
if(inputtimes==3)
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Wrong 3 times!");//密碼錯(cuò)誤,提示重新輸入
while(1)
P2=light2; //停止該位置,重啟電源后才能輸入,實(shí)際實(shí)用中則需要等到一定時(shí)間后才能再次輸入。
}
}
else
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Right Password!");//密碼正確
RuningLight();
i=0;
inputtimes=0;//輸入正確則次數(shù)清零,重新計(jì)數(shù)
Flag=0; //清除正確標(biāo)志
break;
}
}
else //沒有按確定鍵,保存鍵值
{
if(i<16)
{
passwordtemp[i]=num; //保存密碼
DisplayOneChar(i,1,num); //輸入的密碼用"*"代替
i++; //計(jì)數(shù),不能超過16位
}
else
{ Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry");
inputtimes++;
i=0;
P2=light2;
}
}
}
}
}
//--------------------------------------------------------新密碼輸入--------------------------------------------------------
void NewPasswordInput() //新密碼輸入
{
while(1)
{ num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進(jìn)行處理
{
if(i==0)
Write_LCD(0,1," ");//清除該行
if(num=='f')
{ i=0;
RuningLight();
break;
}
else if(i<16) //新密碼不能超過16位
{
newpassword[i]=num; //保存密碼
DisplayOneChar(i,1,num); //顯示新密碼
i++; //計(jì)數(shù),不能超過16位
}
else
{ i=0;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry"); //輸入過多,報(bào)錯(cuò)
delay1(10);
for(j=0;j<sizeof(newpassword);j++) //清除新密碼
newpassword[j]='\0';
P2=light2;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"new password!"); //重新輸入新密碼
delay1(10);
}
}
}
}
//--------------------------------------------------------確認(rèn)修改的密碼--------------------------------------------------------
void AgainInput() //新密碼確認(rèn)
{
while(1)
{
num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進(jìn)行處理
{ if(i==0)
Write_LCD(0,1," ");//清除該行
if(num=='f')
{
i=0;
n=sizeof(passwordtemp);
m=sizeof(newpassword);
if(m==n) //長度判斷
{
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應(yīng)
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
Flag=1;
if(Flag) //輸入錯(cuò)誤提示和輸入錯(cuò)誤總次數(shù)判斷,限定三次
{
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Difference!!"); //密碼正確顯示的信息
for(j=0;j<sizeof(passwordtemp);j++) //清除密碼
passwordtemp[j]='\0';
i=0;
Flag=0;
P2=light2;
}
else
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Right!"); //密碼正確顯示的信息
delay1(10);
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Finish!");
RuningLight();
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Right Open>>>");//清除該行
P2=light1;
inputtimes=0;//輸入正確則次數(shù)清零,重新計(jì)數(shù)
Flag=0; //清除正確標(biāo)志
i=0;
break;
}
}
else if(i<16) //密碼不能超過16位
{
passwordtemp[i]=num; //保存密碼
DisplayOneChar(i,1,num); //顯示新密碼
i++; //計(jì)數(shù),不能超過16位
}
else
{ Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry"); //輸入過多,報(bào)錯(cuò)
delay1(10);
for(j=0;j<sizeof(passwordtemp);j++) //清除密碼
passwordtemp[j]='\0';
i=0; //重新輸入
P2=light2;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Input New Again!"); //重新輸入新密碼
delay1(10);
}
}
}
}
//--------------------------------------------------------主函數(shù)--------------------------------------------------------
void main()
{
initial();
Init_Lcd(); //初始化液晶屏
delay1(10); //延時(shí)用于穩(wěn)定,可以去掉
Write_LCD(0,0," Welcome! "); //寫入第一行信息,主循環(huán)中不再更改此信息,所以在while之前寫入
delay1(10);
Write_LCD(0,1,"Input password!"); //寫入第二行信息,提示輸入密碼
delay1(10);
while (1) //主循環(huán)
{
num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進(jìn)行處理
{
if(i==0)
Write_LCD(0,1," "); //清除該行
if(num=='e') //設(shè)置新密碼
{ P2=0xff;
for(j=0;j<sizeof(newpassword);j++) //釋放存儲(chǔ)新密碼數(shù)組
newpassword[j] = '\0';
Write_LCD(0,1,"Set Password!");
delay1(10);
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Input Password!"); //用戶驗(yàn)證
delay1(10);
SetPassword(); //驗(yàn)證密碼
P2=0xff;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"New Password!"); //新密碼輸入
delay1(10);
NewPasswordInput(); //新密碼輸入
P2=0xff;
Write_LCD(0,1," ");
delay1(10);
Write_LCD(0,1,"Again Input!!");
AgainInput(); //新密碼確認(rèn)
for(j=0;j<sizeof(passwordtemp);j++) //釋放存儲(chǔ)輸入密碼數(shù)組
passwordtemp[j] = '\0';
flag1=1; //修改密碼標(biāo)志位
}
else if(num=='f') //確定鍵按下,進(jìn)入判斷密碼對錯(cuò)
{ i=0; //清除輸入標(biāo)志
VriefytPassword(); //密碼認(rèn)證
}
else if(num=='b') //上鎖
{
P2=0xff;
delay1(10);
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Input password!");
i=0;
for(j=0;j<sizeof(passwordtemp);j++)
passwordtemp[j] ='\0';
}
else //沒有按確定鍵,上鎖鍵,設(shè)置鍵,保存鍵值
{
if(i<16)
{
passwordtemp[i]=num; //保存密碼
DisplayOneChar(i,1,num); //輸入的密碼用"*"代替
i++; //計(jì)數(shù),不能超過16位
}
else
{ Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry");
inputtimes++;
i=0;
}
}
}
}
}
復(fù)制代碼
所有程序51hei提供下載:
基于STC51的簡易密碼鎖.rar
(50.08 KB, 下載次數(shù): 22)
2020-6-8 08:15 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
作者:
欣語寶貝
時(shí)間:
2020-7-30 21:26
沙發(fā)是我
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1