Arduino密码锁:实现安全保护

简介:本人使用的是arduino mega2560(因为手头上没有uno板了),但是初学者普遍使用的是arduino uno,所以我写文章的时候还是写的arduino uno(仿真除外),mega上我用的是uno兼容的引脚,所以代码是既可以在mega上跑也可以在uno上跑的。

目录
一.学习目标 2
知识目标: 2
技能目标: 2
整体思路 2
二.知识储备 2
4*4按键屏(keypad) 2
OLED屏 7
舵机 12
面包板 13
EEPROM 14
三.案例实现 15
案例描述 16
四.密码锁实验程序 16
程序编写 16
整体硬件搭建 19
五.知识拓展 20

一.学习目标

知识目标:

  1. 了解OLED显示屏工作原理
  2. 了解舵机原理
  3. 了解44按键屏工作原理
    技能目标:
    设计一个4
    4按键的密码锁,可以更改密码,将设置的密码保存在eeprom,密码正确时控制舵机开关

整体思路

二.知识储备

4*4按键屏(keypad)

工作原理

本人参考的是这位大佬的这篇博客,这是位宝藏级博主,本人跟着学了很久很久了。
博客链接
https://blog.csdn.net/weixin_41659040/article/details/119881718
接线图

          Keypad从左往右的8个引脚分别接arduino的9-2号引脚

示范简单程序

#include <Keypad.h>
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
int secret_lenth;
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup(){
  Serial.begin(9600);
}

void loop(){
  char key = keypad.getKey();
  if (key != NO_KEY){
  secret_lenth=int(key)-48; 
  Serial.print(key);    
  Serial.print("       ");        
  Serial.println(secret_lenth);
  }
}

代码分析效果图
我将char类型变成了int型(方便后续工作),他们对应的ASCLL码不一样,结合ASCLL码表知0对应48,1对应49…,所以程序中我减去了48保证了数字量的一样,字母和字符我都没处理所以就会是这种效果A=17;*=-13;

ASCLL码数字部分表

Keypad.h库下载方式
1.在github上搜索这个库切记是第一个别下错了

Github链接:https://github.com/Chris–A/Keypad

2.找到你的下载文件后,我建议保存到一个专门放arduino外源库的地方方便今后寻找。

例如新建一个文件夹专门存放这些东西,养成好习惯

3.打开arduino添加库

  1. 成功后你的头文件就会变红

    OLED屏
    工作原理
    OLED特点
    (1)功耗低——与LCD相比,OLED不需要背光源,而背光源在LCD中是比较耗能的一部分,所以OLED是比较节能的。例如,24in的AMOLED模块功耗仅仅为440mw,而24in的多晶硅LCD模块达到了605mw。
    (2)响应速度快——OLED技术与其他技术相比,其响应速度快,响应时间可以达到微秒级别。较高的响应速度更好的实现了运动的图像。根据有关的数据分析,其响应速度达到了液晶显示器响应速度的1000倍左右。
    (3)较宽的视角——与其他显示相比,由于OLED是主动发光的,所以在很大视角范围内画面是不会显示失真的。其上下,左右的视角宽度超过170度。
    (4)能实现高分辨率显示——大多高分辨率的OLED显示采用的是有源矩阵也就是AMOLED,它的发光层可以是吸纳26万真彩色的高分辨率,并且随着科学技术的发展,其分辨率在以后会得到更高的提升。
    (5)宽温度特性——与LCD相比,OLED可以在很大的温度范围内进行工作,根据有关的技术分析,温度在-40摄氏度到80摄氏度都是可以正常运行的。这样就可以降低地域限制,在极寒地带也可以正常使用。
    (6)OLED能够实现软屏——OLED可以在塑料、树脂等不同的柔性衬底材料上进行生产,将有机层蒸镀或涂布在塑料基衬上,就可以实现软屏。
    (7)OLED成品的质量比较轻——与其他产品相比,OLED的质量比较小,厚度与LCD相比是比较小的,其抗震系数较高,能够适应较大的加速度,振动等比较恶劣的环境。

    接线图

SDA接SDA,SCL接SCL,切记线不能接错,我画错了,你也不能接错

示例程序

//显示中英文字符程序
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16 //定义显示高度
#define LOGO16_GLCD_WIDTH  16 //定义显示宽度

//中文:中  (存储点阵变量,用函数display.drawBitmap()调用即可)
static const unsigned char PROGMEM str_1[] =
{0x00,0xFE,0x02,0x12,0x92,0x92,0x92,0xF2,0x92,0x92,0x92,0x12,0x02,0xFE,0x00,0x00,
0x00,0xFF,0x40,0x48,0x48,0x48,0x48,0x4F,0x48,0x4A,0x4C,0x48,0x40,0xFF,0x00,0x00};/*"国",0*/


//中文:国
static const unsigned char PROGMEM str_2[] =
{
0x00,0x7F,0x40,0x48,0x49,0x49,0x49,0x4F,0x49,0x49,0x49,0x48,0x40,0x7F,0x00,0x00,
0x00,0xFF,0x02,0x12,0x12,0x12,0x12,0xF2,0x12,0x52,0x32,0x12,0x02,0xFF,0x00,0x00,
};/*"国",0*/
/* (16 X 16 , 宋体 )*/

#if (SSD1306_LCDHEIGHT != 64)
//#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

void setup()   {                
  Serial.begin(9600);

  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done
  
  display.clearDisplay(); //清屏

  //英文字符显示,直接用display.println或print显示字符串就行
  //println换行,print不换行
  display.setTextSize(1);             //设置字体大小
  display.setTextColor(WHITE);        //设置字体颜色白色
  display.setCursor(0,0);             //设置字体的起始位置
  display.println("Hello, world!");   //输出字符并换行
  
  display.setTextColor(BLACK, WHITE); //设置字体黑色,字体背景白色 
  display.println(3.141592);          //输出数字并换行
  
  display.setTextSize(2);             //设置字体大小
  display.setTextColor(WHITE);        //设置字体白色
  display.print("0x");                //输出字符
  display.println(0xDEADBEEF, HEX);   //输出为ASCII编码的十六进制
  //display.clearDisplay(); //清屏
  delay(2000);
  display.display();                  //显示以上
  display.clearDisplay(); //清屏
  delay(2000);
  //display.drawRect(38, 38, 51, 6, WHITE);//以(38,38)为起点绘制一个长度51宽度为6的矩形
  //中文字符显示
  //delay(3000);
  //display.clearDisplay(); //清屏
  //display.drawBitmap(26, 32, str_1, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH, 1); //在坐标X:26  Y:16的位置显示中文字符凌
  //display.drawBitmap(42, 32, str_2, 16, 16, 1); //在坐标X:42  Y:16的位置显示中文字符顺
  //display.display();                  //把缓存的都显示
}

void loop() {
  display.setTextSize(2);             //设置字体大小
  display.setTextColor(WHITE);        //设置字体颜色白色
  display.setCursor(0,0);             //设置字体的起始位置
  display.println("Hello, world!");   //输出字符并换行
  
  display.setTextColor(BLACK, WHITE); //设置字体黑色,字体背景白色 
  display.println(3.88);          //输出数字并换行
  display.display();                  //显示以上
}

程序分析效果图
注释写的很清楚了,我就不细讲了。我见过很多oled的库,但是我独爱这个库

Adafruit_GFX,Adafruit_SSD1306库下载方式

舵机
工作原理
指在自动驾驶仪中操纵飞机舵面(操纵面)转动的一种执行部件。分有:①电动舵机,由电动机、传动部件和离合器组成。接受自动驾驶仪的指令信号而工作,当人工驾驶飞机时,由于离合器保持脱开而传动部件不发生作用。②液压舵机,由液压作动器和旁通活门组成。当人工驾驶飞机时,旁通活门打开,由于作动器活塞两边的液压互相连通而不妨害人工操纵。此外,还有电动液压舵机,简称“电液舵机”。舵机的组成 一般来讲,舵机主要由以下几个部分组成,舵盘、减速齿轮组、位置反馈电位计、直流电机、控制电路等, 舵机的输入线共有三条,如图6所示,红色中间,是电源线,一边黑色的是地线,这辆根线给舵机提供最基本的能源保证,主要是电机的转动消耗。电源有两种规格,一是4.8V,一是6.0V,分别对应不同的转矩标准,即输出力矩不同,6.0V对应的要大一些,具体看应用条件;另外一根线是控制信号线,Futaba的一般为白色,JR的一般为桔黄色。另外要注意一点,SANWA的某些型号的舵机引线电源线在边上而不是中间,需要辨认。但记住红色为电源,黑色为地线,一般不会搞错。

示例程序

面包板
面包板是由于板子上有很多小插孔,专为电子电路的无焊接实验设计制造的。由于各种电子元器件可根据需要随意插入或拔出,免去了焊接,节省了电路的组装时间,而且元件可以重复使用,所以非常适合电子调试和训练。

EEPROM
工作原理
在实际的应用中,保存在单片机RAM中的数据,掉电后就丢失了,保存在单片机的FLASH中的数据,又不能随意改变,也就是不能用它来记录变化的数值。但是在某些场合,我们又确实需要记录下某些数据,而它们还时常需要改变或更新,掉电之后数据还不能丢失。比如,我们的家用电表度数,电视机里边的频道记忆,一般都是使用EEPROM来保存数据,特点就是掉电后存储的数据不丢失。
一般情况下,EEPROM拥有30万到100万次的寿命,也就是它可以反复写入30-100万次,而读取次数是无限的。
通常,单片机里的Flash都用于存放运行代码,在运行过程中不能改;EEPROM是用来保存用户数据,运行过程中可以改变,比如一个时钟的闹铃时间初始化设定为12:00,后来在运行中改为6:00,这是保存在EEPROM里,不怕掉电,就算重新上电也不需要重新调整到6:00。但最大区别是其实是:FLASH按扇区操作,EEPROM则按字节操作,二者寻址方法不同,存储单元的结构也不同,FLASH的电路结构较简单,同样容量占芯片面积较小,成本自然比EEPROM低,因而适合用作程序存储器,EEPROM则更多的用作非易失的数据存储器。当然用FLASH做数据存储器也行,但操作比EEPROM麻烦的多,所以更“人性化”的MCU设计会集成FLASH和EEPROM两种非易失性存储器,而廉价型设计往往只有 FLASH,早期可电擦写型MCU则都是EEPRM结构,现在已基本上停产了。
示范简单程序
arduino已经为我们准备好了EEPROM类库”EEPROM.h”。
我们要使用得先调用EEPROM.h,然后使用write和read方法,即可操作EEPROM。

参考链接:
https://blog.csdn.net/sdlgq/article/details/51931900

#include <EEPROM.h>
int addr = 0;
void setup()
{
}
void loop()
{
  //每次写入1个字节,注意不要溢出。
  //比如要保存模拟值,模拟值读出后是一个0-1024的值,但每字节的大小为0-255,容纳不了,所以这里可以变通一下,将值除以4再存储到val,就能够容纳了。使用的时候读出来再乘以4还原回来。  
  int val = analogRead(0) / 4;
  EEPROM.write(addr, val);

  addr = addr + 1;
  if (addr == 512)  // 当读写位置到了最大容量时,注意不要溢出。
    addr = 0;
  delay(100);
}

案例实现
把以上硬件部分的代码再结合一点点软件功能方面的代码就可以了。

名称 数量
Arduino mega开发板 1
杜邦线 1扎
OLED屏 1
面包板 1
Keypad 1
Servo 1
充电宝 1
案例描述

  1. 按照电路图原理图连

    红色引线表示5V电源,白色引线(SDA除外)表示接地口,黄色引线和橙色引线表示不同的信号线连接的引脚口也会不同,下文会对不同装置不同的信号引脚口进行分析。

四.密码锁实验程序

程序编写
总体流程

细分流程代码设计思路

6位密码程序

#include <Keypad.h>
#include <EEPROM.h>

#include <Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
#define SSD1306_LCDHEIGHT 64
Adafruit_SSD1306 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16 //定义显示高度
#define LOGO16_GLCD_WIDTH  16 //定义显示宽度

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

Servo myservo;  // 创建舵机对象来控制舵机
int pos = 0;    // 用来存储舵机位置的变量
int D_break=1,A_break=1,ZhuYe=0;
char secret_num[6]={};  //设置6位密码,保存至eeprom
char secret_input[6]={};//输入密码进行判断
//for(int i = 0;i<6;i++)
//{
//    EEPROM.write(i,TimeOn[i]);
//    //延时100ms 等待写入
//    delay(10);
//}
void setup(){
  Serial.begin(9600);
  myservo.attach(10);                         // 把连接在引脚9上的舵机赋予舵机对象
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  display.setTextColor(WHITE);        //开像素点发光
  display.clearDisplay();             //清屏
  
//--------------------------------------OLED屏调试代码
  display.clearDisplay();             
  display.setTextSize(2); 
  display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
  display.setCursor(0,5);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("ShuRu: A");                //这里输入显示内容,可以是变量
  display.setCursor(0,25);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("SheZhi:D");                //这里输入显示内容,可以是变量
  display.display();  
//---------------------------------------  

  myservo.write(0);                   //舵机旋转指定角度
  delay(1000);

  for(int i = 0;i<6;i++)              //初始化密码
 {
    secret_num[i]=EEPROM.read(i);
    delay(10);
 }
 
}

void loop(){
  char key = keypad.getKey();
  if(ZhuYe==1)                       //刷新屏幕
  {
  display.clearDisplay();             
  display.setTextSize(2); 
  display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
  display.setCursor(0,5);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("ShuRu: A");                //这里输入显示内容,可以是变量
  display.setCursor(0,25);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("SheZhi:D");                //这里输入显示内容,可以是变量
  display.display();  
  ZhuYe=0;
  }
  if (key != NO_KEY)
  {
  //Serial.println(key);
  if(key=='B'||key=='C')                //旋转至0度
   {
    myservo.write(0);                   //舵机旋转指定角度
   }
  if(key=='D')
   {
    while(D_break)
    {
    display.clearDisplay();             //清屏
    display.setTextSize(2); 
    display.setTextColor(WHITE,BLACK);  //设置字体黑色,字体背景白色 
    display.setCursor(0,5);             //128*64的点阵屏对应x,y轴,x,y的起始点
    display.print("shezhi");            //这里输入显示内容,可以是变量
    display.display();
    int num_break=0;                    //循环跳出标志
    while(1)
     {
      char key = keypad.getKey();
      if(key != NO_KEY)
       {
        secret_num[num_break]=key;
        display.clearDisplay();             //清屏
        display.setTextSize(2); 
        display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
        display.setCursor(0,5);            //128*64的点阵屏对应x,y轴,x,y的起始点
        display.print("shezhi");           //这里输入显示内容,可以是变量
        display.setCursor(0,45);           //128*64的点阵屏对应x,y轴,x,y的起始点
        display.print(num_break+1);        //这里输入显示内容,可以是变量
        display.display();
        num_break++;
       }
      if(num_break>5)                     //将设置数据保存
       {
        for(int i = 0;i<6;i++)
         {
          EEPROM.write(i,secret_num[i]);
          //延时100ms 等待写入
          delay(10);
         }
        display.clearDisplay();             //清屏
        for(int i=0;i<6;i++)
         {
          display.setTextSize(2); 
          display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
          display.setCursor(i*15,30);        //移动显示设置的密码
          display.print(secret_num[i]);      //这里输入显示内容,可以是变量
          display.display();  
         }
        num_break=0;                        //设置完成跳出循环
        delay(2000);
        display.clearDisplay();             //清屏
        display.setTextSize(2); 
        display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
        display.setCursor(0,25);           //128*64的点阵屏对应x,y轴,x,y的起始点
        display.print("OK!");              //显示OK,设置成功
        display.display();
        delay(1000);
        display.clearDisplay();
        ZhuYe=1;
        goto start;
       }
     }
    }
   }
   if(key=='A')                         //验证密码
   {
    while(A_break)
    {
    display.clearDisplay();             //清屏
    display.setTextSize(2); 
    display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
    display.setCursor(0,15);           //128*64的点阵屏对应x,y轴,x,y的起始点
    display.print("ShuRu:");           //这里输入显示内容,可以是变量
    display.display();
    int num_break2=0;                    //循环跳出标志
    while(1)
     {
      char key = keypad.getKey();
      //display.clearDisplay();             //清屏
      if(key != NO_KEY)
       {
         secret_input[num_break2]=key;
         //display.clearDisplay();                     //清屏
         display.setTextSize(2); 
         display.setTextColor(WHITE,BLACK);            //设置字体黑色,字体背景白色 
         display.setCursor(0,15);                      //128*64的点阵屏对应x,y轴,x,y的起始点
         display.print("ShuRu:");                      //这里输入显示内容,可以是变量
         display.setCursor(num_break2*15,45);          //128*64的点阵屏对应x,y轴,x,y的起始点
         display.print(secret_input[num_break2]);      //这里输入显示内容,可以是变量
         display.display();
         num_break2++;
       }
       if(num_break2>5)
       {
        int num_True=0;
        for(int i = 0;i<6;i++)
         {
          if(secret_input[i]==secret_num[i])   //对比输入和密码
           {
            num_True++;                        //每对一位加1
           }
          //延时100ms 等待写入
          delay(10);
         }
         if(num_True==6)                       //6位密码都正确时
           {
             Serial.print("密码正确!");
             num_True=0;
             display.clearDisplay();             //清屏
             display.setTextSize(2); 
             display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
             display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
             display.print("success");           //这里输入显示内容,可以是变量
             display.display();
             delay(2000);
             display.clearDisplay();
             display.clearDisplay();             //清屏
             display.setTextSize(2); 
             display.setTextColor(WHITE,BLACK);  //设置字体黑色,字体背景白色 
             display.setCursor(0,25);            //128*64的点阵屏对应x,y轴,x,y的起始点
             myservo.write(100);                 //舵机旋转指定角度
             delay(1500);
             ZhuYe=1;
             goto start;
           }
          else 
          {
            Serial.print("密码错误!");
            num_True=0;
            display.clearDisplay();             //清屏
            display.setTextSize(2); 
            display.setTextColor(WHITE,BLACK);  //设置字体黑色,字体背景白色 
            display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
            display.print("fail");              //这里输入显示内容,可以是变量
            display.display();
            delay(2000);
            display.clearDisplay();
            display.clearDisplay();              //清屏
            display.setTextSize(2); 
            display.setTextColor(WHITE,BLACK);   //设置字体黑色,字体背景白色 
            display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
            ZhuYe=1;
            goto start;
          }
       }
     }
   }
   
  }
 }
 start:{}
}

初始页面

输入页面

成功登录

任意长度密码程序

#include <Keypad.h>
#include <EEPROM.h>
#include <Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
#define SSD1306_LCDHEIGHT 64
Adafruit_SSD1306 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16 //定义显示高度
#define LOGO16_GLCD_WIDTH  16 //定义显示宽度

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

Servo myservo;  // 创建舵机对象来控制舵机
int pos = 0;    // 用来存储舵机位置的变量
int D_break=1,A_break=1,ZhuYe=0;
char secret_num[6]={};  //设置6位密码,保存至eeprom
char secret_input[6]={};//输入密码进行判断
int secret_lenth;       //密码设置长度
//for(int i = 0;i<6;i++)
//{
//    EEPROM.write(i,TimeOn[i]);
//    //延时100ms 等待写入
//    delay(10);
//}
void setup(){
  Serial.begin(9600);
  myservo.attach(10);                         // 把连接在引脚9上的舵机赋予舵机对象
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  display.setTextColor(WHITE);        //开像素点发光
  display.clearDisplay();             //清屏
  
//--------------------------------------OLED屏调试代码
  display.clearDisplay();             
  display.setTextSize(2); 
  display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
  display.setCursor(0,5);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("ShuRu: A");                //这里输入显示内容,可以是变量
  display.setCursor(0,25);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("SheZhi:D");                //这里输入显示内容,可以是变量
  display.display();  
//---------------------------------------  

  myservo.write(0);                   //舵机旋转指定角度
  delay(1000);
  secret_lenth=EEPROM.read(10);
  for(int i = 0;i<secret_lenth;i++)              //初始化密码
 {
    secret_num[i]=EEPROM.read(i);
    delay(10);
 }
 
}

void loop(){
  char key = keypad.getKey();
  if(ZhuYe==1)
  {
  display.clearDisplay();             
  display.setTextSize(2); 
  display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
  display.setCursor(0,5);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("ShuRu: A");                //这里输入显示内容,可以是变量
  display.setCursor(0,25);            //128*64的点阵屏对应x,y轴,x,y的起始点
  display.print("SheZhi:D");                //这里输入显示内容,可以是变量
  display.display();  
  ZhuYe=0;
  }
  if (key != NO_KEY)
  {
  //Serial.println(key);
  if(key=='B'||key=='C')
   {
    myservo.write(0);                   //舵机旋转指定角度
   }
  if(key=='D')
   {
    int lenth_num=0;
    while(D_break)
    {
    display.clearDisplay();             //清屏
    display.setTextSize(2); 
    display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
    display.setCursor(0,5);             //128*64的点阵屏对应x,y轴,x,y的起始点
    display.print("shezhi");       //这里输入显示内容,可以是变量
    display.setCursor(0,35);         
    display.print("lenth");   //这里输入显示内容,可以是变量
    display.display();
    char key = keypad.getKey();
    if(key != NO_KEY)
       {
        secret_lenth=int(key)-48;
        lenth_num=1;
        display.setCursor(80,35);   //128*64的点阵屏对应x,y轴,x,y的起始点      
        display.print(secret_lenth);   //这里输入显示内容,可以是变量
        display.display();
       }
    int num_break=0;                    //循环跳出标志
    while(lenth_num)
     {
      char key = keypad.getKey();
      if(key != NO_KEY)
       {
        secret_num[num_break]=key;
        display.clearDisplay();             //清屏
        display.setTextSize(2); 
        display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
        display.setCursor(0,5);             //128*64的点阵屏对应x,y轴,x,y的起始点
        display.print("shezhi");       //这里输入显示内容,可以是变量
        display.setCursor(0,45);          //128*64的点阵屏对应x,y轴,x,y的起始点
        display.print(num_break+1);   //这里输入显示内容,可以是变量
        display.display();
        num_break++;
       }
      if(num_break>secret_lenth-1)
       {
        for(int i = 0;i<secret_lenth;i++)
         {
          EEPROM.write(i,secret_num[i]);
          //延时100ms 等待写入
          delay(10);
         }
         EEPROM.write(10,secret_lenth);
         delay(10);
        display.clearDisplay();             //清屏
        for(int i=0;i<secret_lenth;i++)
         {
          display.setTextSize(2); 
          display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
          display.setCursor(i*15,30);          //128*64的点阵屏对应x,y轴,x,y的起始点
          display.print(secret_num[i]);   //这里输入显示内容,可以是变量
          display.display();  
         }
        num_break=0;
        delay(2000);
        display.clearDisplay();             //清屏
        display.setTextSize(2); 
        display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
        display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
        display.print("OK!");       //这里输入显示内容,可以是变量
        display.display();
        delay(1000);
        display.clearDisplay();
        ZhuYe=1;
        goto start;
       }
     }
    }
   }
   if(key=='A')                         //验证密码
   {
    while(A_break)
    {
    display.clearDisplay();             //清屏
    display.setTextSize(2); 
    display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
    display.setCursor(0,15);          //128*64的点阵屏对应x,y轴,x,y的起始点
    display.print("ShuRu:");   //这里输入显示内容,可以是变量
    display.display();
    int num_break2=0;                    //循环跳出标志
    while(1)
     {
      char key = keypad.getKey();
      //display.clearDisplay();             //清屏
      if(key != NO_KEY)
       {
         secret_input[num_break2]=key;
         //display.clearDisplay();             //清屏
         display.setTextSize(2); 
         display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
         display.setCursor(0,15);             //128*64的点阵屏对应x,y轴,x,y的起始点
         display.print("ShuRu:");            //这里输入显示内容,可以是变量
         display.setCursor(num_break2*15,45);          //128*64的点阵屏对应x,y轴,x,y的起始点
         display.print(secret_input[num_break2]);   //这里输入显示内容,可以是变量
         display.display();
         num_break2++;
       }
       if(num_break2>secret_lenth-1)
       {
        int num_True=0;
        for(int i = 0;i<secret_lenth;i++)
         {
          if(secret_input[i]==secret_num[i])
           {
            num_True++;
           }
          //延时100ms 等待写入
          delay(10);
         }
         if(num_True==secret_lenth)
           {
             Serial.print("密码正确!");
             num_True=0;
             display.clearDisplay();             //清屏
             display.setTextSize(2); 
             display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
             display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
             display.print("success");       //这里输入显示内容,可以是变量
             display.display();
             delay(2000);
             display.clearDisplay();
             display.clearDisplay();             //清屏
             display.setTextSize(2); 
             display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
             display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
             myservo.write(100);                   //舵机旋转指定角度
             delay(1500);
             ZhuYe=1;
             goto start;
           }
          else 
          {
            Serial.print("密码错误!");
            num_True=0;
            display.clearDisplay();             //清屏
            display.setTextSize(2); 
            display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
            display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
            display.print("fail");       //这里输入显示内容,可以是变量
            display.display();
            delay(2000);
            display.clearDisplay();
            display.clearDisplay();             //清屏
            display.setTextSize(2); 
            display.setTextColor(WHITE,BLACK); //设置字体黑色,字体背景白色 
            display.setCursor(0,25);             //128*64的点阵屏对应x,y轴,x,y的起始点
            ZhuYe=1;
            goto start;
          }
       }
     }
   }
   
  }
 }
 start:{}
}

设置密码任意长度

整体硬件搭建

演示视频

任意长度密码锁

五.知识拓展

拓展有点arduino仿真的知识proteus可以去了解一下,它支持C51,stm32,arduino等多种MCU,切记只有proteus8.12才有OLED屏,仿真没有keypad所以用了个类似的代替了

arduino官网有许多的proteus文件

生成仿真hex文件

如何导入开发板仿真参考这位博主(都是宝藏级博客呀!)
https://blog.csdn.net/laoxue123456/article/details/121558607

如何下载proteuse请参考
https://blog.csdn.net/Matcha_ice_cream/article/details/118639073

本文借鉴了许多大佬的文章,我写文章的目的不单是为了记录,更多的是分享吧,把别人好的文章推荐出去,毕竟我的知识也是源于大佬们。文章如有不足之处请私聊,感激不尽!

百度网盘链接
链接:https://pan.baidu.com/s/1OsKMcYsTd8r6wCM_DK8xZw
提取码:26tu

物联沃分享整理
物联沃-IOTWORD物联网 » Arduino密码锁:实现安全保护

发表评论