51单片机简易电子密码锁

由于作业需求,在昨天天晚上写了一个通过lcd1602,i2c,eeprom,按键,实现的可以设置密码的简易电子锁,

 

 首先点击k15(回车键)进入

 进入后可以点击0-9按键输入6位密码,错误则显示error,5s后重新显示密码输入页面,密码正确则进入。

 

 进入后可以点击Esc键设置密码,进入设置密码界面

输入密码后显示设置成功并显示新密码 

main.c文件代码还有待改进,还可以添加功能

首先先要进行多.c文件创建。话不多说,直接上代码。

lcd1602.c

#include <reg52.h>
#define LCD1602_DB P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E = P1^5;
/* 等待液晶准备好 */
void LcdWaitReady()
{
 unsigned char sta;
 
 LCD1602_DB = 0xFF;
 LCD1602_RS = 0;
 LCD1602_RW = 1;
 do {
 LCD1602_E = 1;
 sta = LCD1602_DB; //读取状态字
 LCD1602_E = 0;
 } while (sta & 0x80); //bit7 等于 1 表示液晶正忙,重复检测直到其等于 0 为止
}
/* 向 LCD1602 液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
 LcdWaitReady();
 LCD1602_RS = 0;
 LCD1602_RW = 0;
 LCD1602_DB = cmd;
 LCD1602_E = 1;
 LCD1602_E = 0;
}
/* 向 LCD1602 液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
 LcdWaitReady();
 LCD1602_RS = 1;
 LCD1602_RW = 0;
  LCD1602_DB = dat;
 LCD1602_E = 1;
 LCD1602_E = 0;
}
/* 设置显示 RAM 起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
 unsigned char addr;
 
 if (y == 0) //由输入的屏幕坐标计算显示 RAM 的地址
 addr = 0x00 + x; //第一行字符地址从 0x00 起始
 else
 addr = 0x40 + x; //第二行字符地址从 0x40 起始
 LcdWriteCmd(addr | 0x80); //设置 RAM 地址
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
 LcdSetCursor(x, y); //设置起始地址
 while (*str != '\0') //连续写入字符串数据,直到检测到结束符
 {
 LcdWriteDat(*str++);
 } 
}
//写数字
void LcdShowDat(unsigned char x, unsigned char y, unsigned char dat)
{
   LcdSetCursor(x,y);
   LcdWriteDat(dat);
}
/* 区域清除,清除从(x,y)坐标起始的 len 个字符位 */
void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{
 LcdSetCursor(x, y); //设置起始地址
 while (len--) //连续写入空格
 {
 LcdWriteDat(' ');
 } }
/* 初始化 1602 液晶 */
void InitLcd1602()
{
 LcdWriteCmd(0x38); //16*2 显示,5*7 点阵,8 位数据接口
 LcdWriteCmd(0x0C); //显示器开,光标关闭
 LcdWriteCmd(0x06); //文字不动,地址自动+1
 LcdWriteCmd(0x01); //清屏
}

 i2c.c

#include <reg52.h>
#include <intrins.h>
#define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}
sbit I2C_SCL = P3^7;
sbit I2C_SDA = P3^6;
/* 产生总线起始信号 */
void I2CStart()
{
 I2C_SDA = 1; //首先确保 SDA、SCL 都是高电平
 I2C_SCL = 1;
 I2CDelay();
 I2C_SDA = 0; //先拉低 SDA
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL
}
/* 产生总线停止信号 */
void I2CStop()
{
 I2C_SCL = 0; //首先确保 SDA、SCL 都是低电平
 I2C_SDA = 0;
 I2CDelay();
 I2C_SCL = 1; //先拉高 SCL
 I2CDelay();
 I2C_SDA = 1; //再拉高 SDA
 I2CDelay();
}
/* I2C 总线写操作,dat-待写入字节,返回值-从机应答位的值 */
bit I2CWrite(unsigned char dat)
{
 bit ack; //用于暂存应答位的值
 unsigned char mask; //用于探测字节内某一位值的掩码变量
 for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行
 {
 if ((mask&dat) == 0) //该位的值输出到 SDA 上
 I2C_SDA = 0;
 else
 I2C_SDA = 1;
 I2CDelay();
 I2C_SCL = 1; //拉高 SCL
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL,完成一个位周期
 }
 I2C_SDA = 1; //8 位数据发送完后,主机释放 SDA,以检测从机应答
 I2CDelay();
 I2C_SCL = 1; //拉高 SCL
 ack = I2C_SDA; //读取此时的 SDA 值,即为从机的应答值
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL 完成应答位,并保持住总线
 return (~ack); //应答值取反以符合通常的逻辑:
 //0=不存在或忙或写入失败,1=存在且空闲或写入成功
}
/* I2C 总线读操作,并发送非应答信号,返回值-读到的字节 */
unsigned char I2CReadNAK()
{
 unsigned char mask;
 unsigned char dat;
 I2C_SDA = 1; //首先确保主机释放 SDA
 for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行
 {
 I2CDelay();
 I2C_SCL = 1; //拉高 SCL
 if(I2C_SDA == 0) //读取 SDA 的值
 dat &= ~mask; //为 0 时,dat 中对应位清零
 else
 dat |= mask; //为 1 时,dat 中对应位置 1
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL,以使从机发送出下一位
 }
 I2C_SDA = 1; //8 位数据发送完后,拉高 SDA,发送非应答信号
 I2CDelay();
 I2C_SCL = 1; //拉高 SCL
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL 完成非应答位,并保持住总线
 return dat;
}
/* I2C 总线读操作,并发送应答信号,返回值-读到的字节 */
unsigned char I2CReadACK()
{
 unsigned char mask;
 unsigned char dat;
 I2C_SDA = 1; //首先确保主机释放 SDA
 for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行
 {
 I2CDelay();
 I2C_SCL = 1; //拉高 SCL
 if(I2C_SDA == 0) //读取 SDA 的值
 dat &= ~mask; //为 0 时,dat 中对应位清零
 else
 dat |= mask; //为 1 时,dat 中对应位置 1
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL,以使从机发送出下一位
 }
 I2C_SDA = 0; //8 位数据发送完后,拉低 SDA,发送应答信号
 I2CDelay();
 I2C_SCL = 1; //拉高 SCL
 I2CDelay();
 I2C_SCL = 0; //再拉低 SCL 完成应答位,并保持住总线
 return dat;
}

eeprom.c

#include <reg52.h>
extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadACK();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);
/* E2 读取函数,buf-数据接收指针,addr-E2 中的起始地址,len-读取长度 */
void E2Read(unsigned char *buf, unsigned char addr, unsigned char len)
{
 do { //用寻址操作查询当前是否可进行读写操作
 I2CStart();
 if (I2CWrite(0x50<<1)) //应答则跳出循环,非应答则进行下一次查询
 {
 break;
 }
 I2CStop();
 } while(1);
 I2CWrite(addr); //写入起始地址
 I2CStart(); //发送重复启动信号
 I2CWrite((0x50<<1)|0x01); //寻址器件,后续为读操作
 while (len > 1) //连续读取 len-1 个字节
 {
 *buf++ = I2CReadACK(); //最后字节之前为读取操作+应答
 len--;
 }
 *buf = I2CReadNAK(); //最后一个字节为读取操作+非应答
 I2CStop();
}
/* E2 写入函数,buf-源数据指针,addr-E2 中的起始地址,len-写入长度 */
void E2Write(unsigned char *buf, unsigned char addr, unsigned char len)
{
 while (len > 0)
 {
 //等待上次写入操作完成
 do { //用寻址操作查询当前是否可进行读写操作
 I2CStart();
 if (I2CWrite(0x50<<1)) //应答则跳出循环,非应答则进行下一次查询
 {
 break;
 }
 I2CStop();
 } while(1);
 //按页写模式连续写入字节
 I2CWrite(addr); //写入起始地址
 while (len > 0)
 {
 I2CWrite(*buf++); //写入一个字节数据
 len--; //待写入长度计数递减
 addr++; //E2 地址递增
 if ((addr&0x07) == 0) //检查地址是否到达页边界,24C02 每页 8 字节,
 { //所以检测低 3 位是否为零即可
 break; //到达页边界时,跳出循环,结束本次写操作
 }
 }
 I2CStop();
 } }

下面通过函数调用,首先,先建立两个函数

bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len)//比较字符串是否相等
{
 while (len–)
 {
 if (*ptr1++ != *ptr2++) //遇到不相等数据时即刻返回 0
 {
 return 0;
 }
 }
 return 1; //比较完全部长度数据都相等则返回 1 }
}

用来比较字符串是否相等

unsigned char key_board()//按键检测,放入while循环
{
   uchar temp; //P2口数据存储
   uchar count;
   uchar num_key=20;      //返回的键值
   static uchar key_old=0xfe;//键盘扫描循环初始值
   static uchar  key_code;

   P2=key_old;
   temp=P2;
 if(temp!=key_old)//判断是否有按键按下
    {
      count++;
      if(count==10)
        {
            F0=1;
            key_code=temp;
        }
    } 
  else
      {
           count=0;
         if(F0==1)
         {
              F0=0;
              switch(key_code)//读出键值
             {
                 //P2^0线设置为低电平 
                  case 0xEE: num_key=10;  break; 
                  case 0xDE: num_key=11;  break;
                  case 0xBE: num_key=12;  break;                                
                  case 0x7E: num_key=13;  break;            
                  //P2^1线设置为低电平 
                  case 0xED: num_key=7;  break;
                  case 0xDD: num_key=8;  break; 
                  case 0xBD: num_key=9;  break; 
                  case 0x7D: num_key=14;  break;                                   
                  //P2^2线 设置为低电平 
                  case 0xEB: num_key=4;  break;
                  case 0xDB: num_key=5; break;                           
                  case 0xBB: num_key=6; break;               
                  case 0x7B: num_key=15; break;   
                  //P2^3线 设置为低电平                                                   
                  case 0xE7: num_key=1; break; 
                  case 0xD7: num_key=2; break;
                  case 0xB7: num_key=3; break;
                  case 0x77: num_key=16; break; 
                                                                                                                                        
               }
              
             }
              
          key_old=_crol_(key_old,1);//改变扫描线 
              if(key_old==0xef)
               {
                  key_old=0xfe;
               }
         }
    return(num_key);    //返回键值
}

按键没有使用定时器,直接通过while循环检测按键,直接调用函数

下面是mian.c函数主要内容

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
unsigned char buf[4];
extern void LcdWaitReady();
extern void LcdWriteCmd(unsigned char cmd);
extern void LcdWriteDat(unsigned char dat);
extern void LcdSetCursor(unsigned char x, unsigned char y);
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);
extern void InitLcd1602();
extern void LcdShowDat(unsigned char x, unsigned char y, unsigned char dat);
extern void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);
extern void E2Read(unsigned char *buf, unsigned char addr, unsigned char len);
bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len);
unsigned char key_board();
unsigned char cnt=0;
unsigned char a[2],b[2]="1",c1=0,c2[10],c3[10],d=0,e=0;
bit f=0,g=0;
void delay_ms(unsigned int i)
{
 unsigned char k;
 while(i--)
{
  for(k=110;k>0;k--);
}
}
void main()
{
    int i=0;
    unsigned char temp;
	unsigned char mm[]="123456";
	unsigned char str[]="HELLO";
	unsigned char str2[]="Set Password";
	unsigned char str1[]="Input Password";
	unsigned char str3[]="yes";
	TMOD=0x01;
	TH0=0x4C;
	TL0=0x00;
	IE=0x82;
	TR0=1;
    InitLcd1602();
	LcdShowStr(2,0,str);		 
	while(1)
	{
		c1=key_board();

		if(d==1)
		{ 

		  if(c1<=10)
		  {
		  LcdWriteDat(42);
		  if(c1==10)
		  c2[e]=48;
		  else
		  c2[e]=c1+48;
		  e++;
		  }else if(c1==12&&f==0)
		  {
		   e=0;
		   E2Read(c3,20,6);
		   if(CmpMemory(c2,c3,6)==1)
		   {
		   LcdAreaClear(0,0,16);
		   LcdAreaClear(0,1,16);
		   LcdShowStr(2,0,"right");
		   f=1;
		   }else
		   {
		   LcdAreaClear(0,0,16);
		   LcdAreaClear(0,1,16);
		   LcdShowStr(2,0,"Error");
		   delay_ms(5000);
		   d=0;
		   } 
		  }else if(c1==12&&g==1)
		  {
		   e=0;
		   E2Write(c2,20,6);
		   E2Read(c3,20,6);
		   LcdAreaClear(0,0,16);
		   LcdAreaClear(0,1,16);
		   LcdShowStr(2,0,"set succeeded");
		   LcdShowStr(2,1,c3);
		  }
		}
		  if(c1==12&&d==0)
		{
		LcdShowStr(2,0,str1);
		LcdWriteCmd(0x80+0x40+0x03);
		LcdWriteCmd(0x0f);
		  d=1;
		}
		if(f==1&&c1==11&&g==0)
		{
		   LcdAreaClear(0,0,16);
		   LcdAreaClear(0,1,16);
		   LcdShowStr(2,0,"Input Password");
		   LcdWriteCmd(0x80+0x40+0x03);
		   LcdWriteCmd(0x0f);
		   e=0;
		   g=1;
		}	  
	 	   
	} 	
}
void clock() interrupt 1
{
   cnt++;
   TH0=0x4C;
   TL0=0x00;
   if(cnt>=20)
   {
	 
	 cnt=0;
   }
}

bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len)//比较字符串是否相等
{
 while (len--)
 {
 if (*ptr1++ != *ptr2++) //遇到不相等数据时即刻返回 0
 {
 return 0;
 }
 }
 return 1; //比较完全部长度数据都相等则返回 1 }
}
unsigned char key_board()//按键检测,放入while循环
{
   uchar temp; //P2口数据存储
   uchar count;
   uchar num_key=20;	  //返回的键值
   static uchar key_old=0xfe;//键盘扫描循环初始值
   static uchar  key_code;

   P2=key_old;
   temp=P2;
 if(temp!=key_old)//判断是否有按键按下
    {
	  count++;
	  if(count==10)
		{
			F0=1;
			key_code=temp;
		}
	} 
  else
      {
  	     count=0;
		 if(F0==1)
		 {
		 	 F0=0;
		 	 switch(key_code)//读出键值
			 {
			     //P2^0线设置为低电平 
                  case 0xEE: num_key=10;  break; 
                  case 0xDE: num_key=11;  break;
                  case 0xBE: num_key=12;  break;                                
                  case 0x7E: num_key=13;  break;            
                  //P2^1线设置为低电平 
                  case 0xED: num_key=7;  break;
                  case 0xDD: num_key=8;  break; 
                  case 0xBD: num_key=9;  break; 
                  case 0x7D: num_key=14;  break;                                   
                  //P2^2线 设置为低电平 
                  case 0xEB: num_key=4;  break;
                  case 0xDB: num_key=5; break;                           
                  case 0xBB: num_key=6; break;               
                  case 0x7B: num_key=15; break;   
                  //P2^3线 设置为低电平                                                   
                  case 0xE7: num_key=1; break; 
                  case 0xD7: num_key=2; break;
                  case 0xB7: num_key=3; break;
                  case 0x77: num_key=16; break; 
                                                                                                                                        
               }
			  
			 }
			  
		  key_old=_crol_(key_old,1);//改变扫描线 
			  if(key_old==0xef)
			   {
			  	key_old=0xfe;
			   }
	     }
	return(num_key);	//返回键值
}

main.c函数里有一些没有用上的值和数组 

物联沃分享整理
物联沃-IOTWORD物联网 » 51单片机简易电子密码锁

发表评论