久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標題:
51單片機+PCF8574簡易密碼鎖程序 帶詳細注釋 1602顯示
[打印本頁]
作者:
LUQIMAI
時間:
2020-6-8 08:17
標題:
51單片機+PCF8574簡易密碼鎖程序 帶詳細注釋 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:確認鍵;e:設置鍵;b:上鎖鍵
* 初始密碼:1234
* 開門流程:通電,輸入初始密碼,按f鍵,提示open,同時P2燈亮代表開門。
* 修改密碼流程:通電后,按e鍵,首先輸入舊的密碼(第一次設置時,舊密碼就是初始密碼),按照LCD提示操作即可。
* 上鎖流程:開門后,按下b鍵,上鎖,P2燈滅
* 燈光說明:流水燈-在修改密碼時,每一步成功都會有流水燈提示
* 全亮燈-門開
* 全滅燈-門關
* 不足之處:1.不知是單片機識別出現問題,還是鍵盤讀入的問題。有時輸入正確的密碼,但提示錯誤,慢慢的按鍵輸入,出錯的幾率會低些
* 2.需要一直通電,如果重新供電后,修改的密碼會失效,所以離應用到實際生活還有距離
* 3.暫時這些,有問題望指
* 如果有不同想法的朋友,歡迎一起交流學習!!
硬件連接圖如下:
硬件連接的詳細接法程序中有,不清楚的也可以直接回帖問我
51hei圖片_20200607182508.jpg
(98.41 KB, 下載次數: 52)
下載附件
2020-6-8 08:14 上傳
注意注意!!!!做了幾處修改,下面是優化版
注意注意!!!!做了幾處修改
,下面是優化版
注意注意!!!!做了幾處修改
,下面是優化版
修改: 1.添加刪除功能
2.優化了幾處錯誤,基本完成所有密碼鎖的功能
如有發現其他錯誤,望不惜賜教!!
此處是優化版的源碼,請下載這個:
優化版.rar
(83.14 KB, 下載次數: 44)
2020-6-10 12:51 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
(有幾處錯誤)單片機源程序如下:
#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; //修改密碼標志位
uchar num,i=0,j;
uchar passwordtemp[16],password[16]={'1','2','3','4'},newpassword[16]; //輸入的密碼,默認的密碼
uchar inputtimes; //密碼輸入錯誤次數
uint n,m; //輸入密碼長度,實際密碼長度
bit Flag=0;\
uchar light,light1=0,light2=0xf0; //設置成功,開鎖,錯誤,
sbit SCL = P1^0;
sbit SDA = P1^1;
char ADDR = 0x4e; // PCF8574 T 模塊的地址碼
//char ADDR = 0x7e; // PCF8574 AT 模塊的地址碼
//***************************** 延時 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個字節 ******************************************
void IIC_writeByte(char temp)
{
char i;
for(i=0;i<8;i++)
{
SDA=(bit)(temp & 0x80) ; // 根據規定1602的數據最高位必須為 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 的地址 (應該是相當于選中的意思吧)
tmp = comm & 0xF0; // 與0xf0 應該是取第四位的意思吧
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寫數據 ********************************************
void LCD_write_data(char data1)
{
char tmp;
IIC_start();
IIC_writeByte(ADDR); // 先選PCF 8574T 的地址 (應該是相當于選中的意思吧)
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位總線轉為4位總線
delay1(50) ;
LCD_write_command(0x32); //
delay1(50) ;
LCD_write_command(0x28); // 4位數據線,顯示2行,5*7點陣字符 !如果是0x38 則為8位數據線,顯示2行,5*7點陣字符
delay1(50) ;
LCD_write_command(0x0C); // 開顯示,關閉光標,不閃爍
delay1(50) ;
LCD_write_command(0x06); // 設定輸入方式,增量不位移
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 移動光標
LCD_write_command(addr);
while (*str)
{
LCD_write_data(*str++);
}
}
//-------------------------------------------- 顯示字符串的函數 ----------------------------------------------------
void LCD_write_word(unsigned char *s) //顯示字符串的函數
{
while(*s>0)
{
LCD_write_data(*s);
s++;
}
}
//********************************* 指定位置顯示一個字符*******************************************
/*
void Print_Char (unsigned char line,unsigned char num,unsigned char date)
{
LCD_write_command(line+num);
LCD_write_data(date);
}
*/
//按指定位置顯示一個字符(針對1602液晶)-用在溫度顯示
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //當要顯示第二行時地址碼+0x40;
X |= 0x80; // 算出指令碼
LCD_write_command(X); //這里不檢測忙信號,發送地址碼
LCD_write_data(DData);
}
//--------------------------------------初始化----------------------------------------------------------------
void initial()
{
P1M0=0;
P1M1=0;
P2M0=0;
P2M1=0;
P0M0=0;
P0M1=0;
}
/*------------------------------------------------
按鍵掃描函數,返回掃描鍵值
------------------------------------------------*/
unsigned char KeyScan(void) //鍵盤掃描函數,使用行列反轉掃描法
{
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); //返回該值
}
/*------------------------------------------------
按鍵值處理函數,返回掃鍵值
------------------------------------------------*/
unsigned char KeyPro(void)
{
switch(KeyScan())
{
case 0xee:return '0';break;//0 按下相應的鍵顯示相對應的碼值
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;
}
//--------------------------------------------------------密碼驗證--------------------------------------------------------
void VriefytPassword() //驗證密碼
{ if(flag1)
m=sizeof(newpassword); //記錄新密碼的長度
else
m=sizeof(password); //記錄舊密碼的長度
n=sizeof(passwordtemp); //記錄輸入密碼的長度
if(m==n) //長度判斷
{
if(flag1) //修改密碼后
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
else //修改密碼前
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應
{ 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) //輸入錯誤提示和輸入錯誤總次數判斷,限定三次
{
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Wrong Retry!"); //輸入錯誤提示
for(j=0;j<sizeof(passwordtemp);j++) //清除輸入的錯誤密碼
passwordtemp[j]='\0';
inputtimes++; //連續輸入錯誤,則次數累加
i=0;
if(inputtimes==3)
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Wrong 3 times!");//密碼錯誤,提示重新輸入
while(1)
P2=light2; //停止該位置,重啟電源后才能輸入,實際實用中則需要等到一定時間后才能再次輸入。
}
}
else
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Right Open!>>>>");//密碼正確顯示的信息
P2=light1;
inputtimes=0;//輸入正確則次數清零,重新計數
Flag=0; //清除正確標志
i=0;
}
}
//--------------------------------------------------------修改密碼時的密碼驗證--------------------------------------------------------
void SetPassword() //設置新密碼時,先驗證
{ while(1)
{ num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進行處理
{
if(i==0)
Write_LCD(0,1," ");//清除該行
if(num=='f') //確定鍵按下,進入判斷密碼對錯
{
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++) //是否一一對應
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
for(j=0;j<sizeof(passwordtemp);j++) //是否一一對應
{ 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) //輸入錯誤提示和輸入錯誤總次數判斷,限定三次
{
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Wrong Retry!"); //密碼錯誤
for(j=0;j<sizeof(passwordtemp);j++)
passwordtemp[j]='\0';
inputtimes++; //連續輸入錯誤,則次數累加
if(inputtimes==3)
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Wrong 3 times!");//密碼錯誤,提示重新輸入
while(1)
P2=light2; //停止該位置,重啟電源后才能輸入,實際實用中則需要等到一定時間后才能再次輸入。
}
}
else
{
Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Right Password!");//密碼正確
RuningLight();
i=0;
inputtimes=0;//輸入正確則次數清零,重新計數
Flag=0; //清除正確標志
break;
}
}
else //沒有按確定鍵,保存鍵值
{
if(i<16)
{
passwordtemp[i]=num; //保存密碼
DisplayOneChar(i,1,num); //輸入的密碼用"*"代替
i++; //計數,不能超過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) //如果掃描是按鍵有效值則進行處理
{
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++; //計數,不能超過16位
}
else
{ i=0;
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry"); //輸入過多,報錯
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);
}
}
}
}
//--------------------------------------------------------確認修改的密碼--------------------------------------------------------
void AgainInput() //新密碼確認
{
while(1)
{
num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進行處理
{ 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++) //是否一一對應
{ if(passwordtemp[j]==newpassword[j])
Flag=0;
else
{ Flag=1;
break;
}
}
}
else
Flag=1;
if(Flag) //輸入錯誤提示和輸入錯誤總次數判斷,限定三次
{
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;//輸入正確則次數清零,重新計數
Flag=0; //清除正確標志
i=0;
break;
}
}
else if(i<16) //密碼不能超過16位
{
passwordtemp[i]=num; //保存密碼
DisplayOneChar(i,1,num); //顯示新密碼
i++; //計數,不能超過16位
}
else
{ Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry"); //輸入過多,報錯
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);
}
}
}
}
//--------------------------------------------------------主函數--------------------------------------------------------
void main()
{
initial();
Init_Lcd(); //初始化液晶屏
delay1(10); //延時用于穩定,可以去掉
Write_LCD(0,0," Welcome! "); //寫入第一行信息,主循環中不再更改此信息,所以在while之前寫入
delay1(10);
Write_LCD(0,1,"Input password!"); //寫入第二行信息,提示輸入密碼
delay1(10);
while (1) //主循環
{
num=KeyPro(); //掃描鍵盤
if(num!=0xff) //如果掃描是按鍵有效值則進行處理
{
if(i==0)
Write_LCD(0,1," "); //清除該行
if(num=='e') //設置新密碼
{ P2=0xff;
for(j=0;j<sizeof(newpassword);j++) //釋放存儲新密碼數組
newpassword[j] = '\0';
Write_LCD(0,1,"Set Password!");
delay1(10);
Write_LCD(0,1," "); //清除該行
delay1(10);
Write_LCD(0,1,"Input Password!"); //用戶驗證
delay1(10);
SetPassword(); //驗證密碼
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(); //新密碼確認
for(j=0;j<sizeof(passwordtemp);j++) //釋放存儲輸入密碼數組
passwordtemp[j] = '\0';
flag1=1; //修改密碼標志位
}
else if(num=='f') //確定鍵按下,進入判斷密碼對錯
{ i=0; //清除輸入標志
VriefytPassword(); //密碼認證
}
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 //沒有按確定鍵,上鎖鍵,設置鍵,保存鍵值
{
if(i<16)
{
passwordtemp[i]=num; //保存密碼
DisplayOneChar(i,1,num); //輸入的密碼用"*"代替
i++; //計數,不能超過16位
}
else
{ Write_LCD(0,1," ");//清除該行
delay1(10);
Write_LCD(0,1,"Too Many Retry");
inputtimes++;
i=0;
}
}
}
}
}
復制代碼
所有程序51hei提供下載:
基于STC51的簡易密碼鎖.rar
(50.08 KB, 下載次數: 22)
2020-6-8 08:15 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
欣語寶貝
時間:
2020-7-30 21:26
沙發是我
歡迎光臨 (http://www.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
一区二区三区播放
|
日韩欧美中文在线
|
丝袜美腿一区二区三区动态图
|
久久精品免费
|
www.成人.com
|
亚洲国产成人久久综合一区,久久久国产99
|
91精品国产高清一区二区三区
|
欧美日韩国产一区二区三区
|
久久久精品国产
|
久久草在线视频
|
日韩欧美一级片
|
欧美成人h版在线观看
|
久久久一区二区三区
|
日韩成人免费视频
|
一区二区av
|
免费 视频 1级
|
亚洲综合五月天婷婷
|
午夜免费成人
|
午夜视频一区二区
|
欧美日韩在线精品
|
免费看a
|
精品不卡
|
97精品视频在线
|
日韩蜜桃视频
|
特一级毛片
|
日韩有码一区二区三区
|
亚洲第一av
|
91视频免费
|
国产精品免费一区二区
|
国产一区不卡
|
极品销魂美女一区二区
|
亚洲最大看片网站
|
九九热在线免费视频
|
91资源在线
|
国产精品视频一区二区三区不卡
|
一区二区免费看
|
亚洲夜射
|
精品伦精品一区二区三区视频
|
91原创视频在线观看
|
一区二区精品视频
|
日韩一区在线播放
|