Kódzár építése - Building a code lock

Code lock
morvfer
Site Admin
Hozzászólások: 10
Csatlakozott: 2017. május 15., hétfő 15:49

Kódzár építése - Building a code lock

Hozzászólás Szerző: morvfer » 2023. április 19., szerda 8:26

Kép

A kódzár építéséhez szükséges elemek:

1; arduino modul (Pro Mini, Nano, Uno)
2; billentyűzet (4x3 matrix)
3; oled kijelző (SSD1306, elhagyható)
4; 4 db led (WS2812B, APA106, elhagyható, de jó ha van)
5; passzív csipogó (zümmer) - ez mindenképp ajánlott
6; relé modul a nyitáshoz
7; nyomógomb - ezt rejtett helyre tesszük, a kódváltáshoz szükséges

The necessary components for building a code lock:

1; Arduino module (Pro Mini, Nano, Uno)
2; Keypad (4x3 matrix)
3; OLED display (SSD1306, optional)
4; 4 LEDs (WS2812B, APA106, optional but recommended)
5; Passive buzzer - recommended
6; Relay module for opening
7; Push button - this is hidden and used for changing the code.


Kód: Egész kijelölése

#include <Wire.h>
#include <EEPROM.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN 11   // A neopixel led adatvezeték csatlakozója az Arduino-n
#define LED_COUNT 4  // A használt LED-ek száma
Adafruit_NeoPixel leds(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
int ledState = 0;

unsigned char addr = 0x3C; //0x78

//  standard ascii 5x7 font - https://github.com/PaulStoffregen/LedDisplay/blob/master/font5x7.h
//  0x3E, 0x51, 0x49, 0x45, 0x3E,  //crossed 0
static const unsigned char  font[] = {
  0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x5F, 0x00, 0x00,
  0x00, 0x07, 0x00, 0x07, 0x00,
  0x14, 0x7F, 0x14, 0x7F, 0x14,
  0x24, 0x2A, 0x7F, 0x2A, 0x12,
  0x23, 0x13, 0x08, 0x64, 0x62,
  0x36, 0x49, 0x56, 0x20, 0x50,
  0x00, 0x08, 0x07, 0x03, 0x00,
  0x00, 0x1C, 0x22, 0x41, 0x00,
  0x00, 0x41, 0x22, 0x1C, 0x00,
  0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
  0x08, 0x08, 0x3E, 0x08, 0x08,
  0x00, 0x80, 0x70, 0x30, 0x00,
  0x08, 0x08, 0x08, 0x08, 0x08,
  0x00, 0x00, 0x60, 0x60, 0x00,
  0x20, 0x10, 0x08, 0x04, 0x02,
  0x3E, 0x41, 0x41, 0x41, 0x3E,   //un-crossed 0
  0x00, 0x42, 0x7F, 0x40, 0x00,
  0x72, 0x49, 0x49, 0x49, 0x46,
  0x21, 0x41, 0x49, 0x4D, 0x33,
  0x18, 0x14, 0x12, 0x7F, 0x10,
  0x27, 0x45, 0x45, 0x45, 0x39,
  0x3C, 0x4A, 0x49, 0x49, 0x31,
  0x41, 0x21, 0x11, 0x09, 0x07,
  0x36, 0x49, 0x49, 0x49, 0x36,
  0x46, 0x49, 0x49, 0x29, 0x1E,
  0x00, 0x00, 0x14, 0x00, 0x00,
  0x00, 0x40, 0x34, 0x00, 0x00,
  0x00, 0x08, 0x14, 0x22, 0x41,
  0x14, 0x14, 0x14, 0x14, 0x14,
  0x00, 0x41, 0x22, 0x14, 0x08,
  0x02, 0x01, 0x59, 0x09, 0x06,
  0x3E, 0x41, 0x5D, 0x59, 0x4E,
  0x7C, 0x12, 0x11, 0x12, 0x7C,    //A
  0x7F, 0x49, 0x49, 0x49, 0x36,
  0x3E, 0x41, 0x41, 0x41, 0x22,
  0x7F, 0x41, 0x41, 0x41, 0x3E,
  0x7F, 0x49, 0x49, 0x49, 0x41,
  0x7F, 0x09, 0x09, 0x09, 0x01,
  0x3E, 0x41, 0x41, 0x51, 0x73,
  0x7F, 0x08, 0x08, 0x08, 0x7F,   //H
  0x00, 0x41, 0x7F, 0x41, 0x00,
  0x20, 0x40, 0x41, 0x3F, 0x01,
  0x7F, 0x08, 0x14, 0x22, 0x41,
  0x7F, 0x40, 0x40, 0x40, 0x40,
  0x7F, 0x02, 0x1C, 0x02, 0x7F,
  0x7F, 0x04, 0x08, 0x10, 0x7F,
  0x3E, 0x41, 0x41, 0x41, 0x3E,
  0x7F, 0x09, 0x09, 0x09, 0x06,
  0x3E, 0x41, 0x51, 0x21, 0x5E,
  0x7F, 0x09, 0x19, 0x29, 0x46,
  0x26, 0x49, 0x49, 0x49, 0x32,   //S
  0x03, 0x01, 0x7F, 0x01, 0x03,
  0x3F, 0x40, 0x40, 0x40, 0x3F,
  0x1F, 0x20, 0x40, 0x20, 0x1F,
  0x3F, 0x40, 0x38, 0x40, 0x3F,
  0x63, 0x14, 0x08, 0x14, 0x63,
  0x03, 0x04, 0x78, 0x04, 0x03,
  0x61, 0x59, 0x49, 0x4D, 0x43,
  0x00, 0x7F, 0x41, 0x41, 0x41,
  0x02, 0x04, 0x08, 0x10, 0x20,
  0x00, 0x41, 0x41, 0x41, 0x7F,
  0x04, 0x02, 0x01, 0x02, 0x04,
  0x40, 0x40, 0x40, 0x40, 0x40,
  0x00, 0x03, 0x07, 0x08, 0x00,
  0x20, 0x54, 0x54, 0x78, 0x40,
  0x7F, 0x28, 0x44, 0x44, 0x38,
  0x38, 0x44, 0x44, 0x44, 0x28,
  0x38, 0x44, 0x44, 0x28, 0x7F,
  0x38, 0x54, 0x54, 0x54, 0x18,
  0x00, 0x08, 0x7E, 0x09, 0x02,
  0x18, 0xA4, 0xA4, 0x9C, 0x78,
  0x7F, 0x08, 0x04, 0x04, 0x78,
  0x00, 0x44, 0x7D, 0x40, 0x00,
  0x20, 0x40, 0x40, 0x3D, 0x00,
  0x7F, 0x10, 0x28, 0x44, 0x00,
  0x00, 0x41, 0x7F, 0x40, 0x00,
  0x7C, 0x04, 0x78, 0x04, 0x78,
  0x7C, 0x08, 0x04, 0x04, 0x78,   //n
  0x38, 0x44, 0x44, 0x44, 0x38,
  0xFC, 0x18, 0x24, 0x24, 0x18,
  0x18, 0x24, 0x24, 0x18, 0xFC,
  0x7C, 0x08, 0x04, 0x04, 0x08,
  0x48, 0x54, 0x54, 0x54, 0x24,
  0x04, 0x04, 0x3F, 0x44, 0x24,
  0x3C, 0x40, 0x40, 0x20, 0x7C,   //u
  0x1C, 0x20, 0x40, 0x20, 0x1C,
  0x3C, 0x40, 0x30, 0x40, 0x3C,
  0x44, 0x28, 0x10, 0x28, 0x44,
  0x4C, 0x90, 0x90, 0x90, 0x7C,
  0x44, 0x64, 0x54, 0x4C, 0x44,   //z
  0x00, 0x08, 0x36, 0x41, 0x00,
};
unsigned char key, mem[4], num[4], ir = 0;
bool pMode = false;

void setup() {
  pinMode(7, OUTPUT);  //relé
  pinMode(8, OUTPUT);  // COL1
  pinMode(9, OUTPUT);  // COL2
  pinMode(10, OUTPUT); // COL3
  pinMode(13, OUTPUT);  //ready LED
  pinMode(12, OUTPUT);  //buzzer
  pinMode(2, INPUT_PULLUP); // ROW4
  pinMode(3, INPUT_PULLUP); // ROW3
  pinMode(4, INPUT_PULLUP); // ROW2
  pinMode(5, INPUT_PULLUP); // ROW1
  pinMode(6, INPUT_PULLUP); //nyomógomb pMode

  leds.begin();  // LED-ek inicializálása

  Wire.begin();        // init i2c bus
  Wire.setClock(200000);  //200khz
  oled_init();
  clrScreen();

  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);

  readyL();
  for (unsigned char i = 0; i < 4; ++i) {
    num[i] = EEPROM.read(i);
  }
  for (unsigned char j = 0; j < 4; j++) {
    drawChar2(0x5F, 5, j + 2);
  }
}

void loop()
{

  if (!digitalRead(6)) {
    pMode = true;
    drawChar2(0x20,1,1);
    drawChar2(0x43,1,2);  //code, programozó módhoz
    drawChar2(0x4F,1,3);
    drawChar2(0x44,1,4);
    drawChar2(0x45,1,5);
    drawChar2(0x20,1,6);
    drawChar2(0x20,1,7);
    drawChar2(0x20,1,8);
    drawChar2(32, 1, 6);
    digitalWrite(13, LOW);
  }

  if (!digitalRead(5) || !digitalRead(4) || !digitalRead(3) || !digitalRead(2)) {
    get_key();
    tone(12, 1000, 50);
    drawChar2(key + 48, 5, ir + 2);
    mem[ir] = key;
    if (ir < LED_COUNT) {  // Ha még nem világít az összes LED-ek
      leds.setPixelColor(ledState, 0, 0, 255);  // Az aktuális LED bekapcsolása kékre
      leds.show();  // LED-ek frissítése
      ledState++;   // Az aktuális LED számának növelése
    }

    if (ir == 3 && pMode == false) {
      if (mem[0] == num[0] && mem[1] == num[1] && mem[2] == num[2] && mem[3] == num[3]) {
        digitalWrite(7, HIGH);
        for (int i = 0; i < 4; i++) {
          leds.setPixelColor(i, 0, 255, 0); // minden LED zöldre kapcsolása, ha helyes kód lett beírva
        }
        leds.show(); // a változtatások megjelenítése a LED-eken
        tone(12, 1000, 150);
        delay(150);
        tone(12, 1500, 150);
        delay(2000);         // Relé ennyi ideig húz be
        digitalWrite(7, LOW);

        ledsclear();

      }

      if (mem[0] != num[0] || mem[1] != num[1] || mem[2] != num[2] || mem[3] != num[3]) {

        for (int i = 0; i < 4; i++) {
          leds.setPixelColor(i, 255, 0, 0); // minden LED pirosra kapcsolása, ha hibás kód lett beírva
        }
        leds.show(); // a változtatások megjelenítése a LED-eken

        tone(12, 1000, 150);
        delay(200);
        tone(12, 1500, 150);
        delay(200);
        tone(12, 2000, 150);
        delay(200);
        tone(12, 1500, 150);
        delay(200);
        tone(12, 1000, 150);
        delay(300);

        ledsclear();


      }
    }
    if (ir == 3 && pMode == true) {
      for (unsigned char j = 0; j < 4; j++) {
        EEPROM.write(j, mem[j]);
      }
      num[0] = mem[0];
      num[1] = mem[1];
      num[2] = mem[2];
      num[3] = mem[3];
      ledsclear();
      pMode = false;
      readyL();
    }
    ir++;
    if (ir == 4) {
      ir = 0;
      for (unsigned char j = 0; j < 4; j++) {
        drawChar2(0x5F, 5, j + 2);
      }
    }
    while (!digitalRead(5) || !digitalRead(4) || !digitalRead(3) || !digitalRead(2)) {}
    delay(100);
  }

}

void readyL() {
  drawChar2(0x4e, 1, 1); //NYITOKOD
  drawChar2(0x59, 1, 2);
  drawChar2(0x49, 1, 3);
  drawChar2(0x54, 1, 4);
  drawChar2(0x4f, 1, 5);
  drawChar2(0x4b, 1, 6);
  drawChar2(0x4f, 1, 7);
  drawChar2(0x44, 1, 8);
  digitalWrite(13, HIGH);
}

void get_key() {
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  if (!digitalRead(5)) {
    key = 1;
  }
  if (!digitalRead(4)) {
    key = 4;
  }
  if (!digitalRead(3)) {
    key = 7;
  }

  digitalWrite(9, LOW);
  digitalWrite(8, HIGH);
  digitalWrite(10, HIGH);
  if (!digitalRead(5)) {
    key = 2;
  }
  if (!digitalRead(4)) {
    key = 5;
  }
  if (!digitalRead(3)) {
    key = 8;
  }
  if (!digitalRead(2)) {
    key = 0;
  }

  digitalWrite(10, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(8, HIGH);
  if (!digitalRead(5)) {
    key = 3;
  }
  if (!digitalRead(4)) {
    key = 6;
  }
  if (!digitalRead(3)) {
    key = 9;
  }

  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
}

void clrScreen()    //fill screen with 0
{
  unsigned char y, x;

  for ( y = 0; y < 8; y++ ) {
    for (x = 0; x < 17; x++) {
      command(0x21);      //col addr
      command(8 * x);     //col start
      command(8 * x + 7); //col end
      command(0x22);      //0x22
      command(y);         // Page start
      command(y);         // Page end

      Wire.beginTransmission(addr);
      Wire.write(0x40);
      for (unsigned char i = 0; i < 8; i++) {
        Wire.write(0x00);
      }
      Wire.endTransmission();
    }

  }
}

void command( unsigned char comm) {
  Wire.beginTransmission(addr);
  Wire.write(0x00);
  Wire.write(comm); // LSB
  Wire.endTransmission();
}

void oled_init() {  // https://www.micros.com.pl/mediaserver/OLED12864-0.96-W-2_0001.pdf

  command(0xAE);   // DISPLAYOFF
  command(0x8D);   // CHARGEPUMP *
  command(0x14);   //0x14-pump on
  command(0x20);   // MEMORYMODE
  command(0x0);    //0x0=horizontal, 0x01=vertical, 0x02=page
  command(0xA1);   //SEGREMAP * A0/A1=top/bottom
  command(0xC8);   //COMSCANDEC * C0/C8=left/right
  command(0xDA);   // SETCOMPINS *
  command(0x12);   //0x22=4rows, 0x12=8rows
  command(0x81);   // SETCONTRAST
  command(0x9F);   //0x8F

  //following settings are set by default
  //    command(0xD5);  // SETDISPLAYCLOCKDIV
  //    command(0x80);
  //    command(0xA8);  // SETMULTIPLEX
  //    command(0x3F);  // 0x1F
  //    command(0xD3);  // SETDISPLAYOFFSET
  //    command(0x0);
  //    command(0x40);  // SETSTARTLINE
  //    command(0xD9);  // SETPRECHARGE
  //    command(0xF1);
  //    command(0xDB);  // SETVCOMDETECT
  //    command(0x40);
  //    command(0xA4);  // DISPLAYALLON_RESUME
  //    command(0xA6);  // NORMALDISPLAY
  command(0xAF);    //DISPLAYON

}

//size x1 chars
void drawChar(char fig, unsigned char y, unsigned char x)
{

  command(0x21);       //col addr
  command(7 * x);      //col start
  command(7 * x + 4);  //col end
  command(0x22);       //0x22
  command(y);          // Page start
  command(y);          // Page end

  Wire.beginTransmission(addr);
  Wire.write(0x40);
  for (unsigned char i = 0; i < 5; i++) {
    Wire.write(font[5 * (fig - 32) + i]);
  }
  Wire.endTransmission();

}
//size x2 chars
void drawChar2(char fig, unsigned char y, unsigned char x)
{
  unsigned char i, line, btm, top;    //

  command(0x20);       // vert mode
  command(0x01);

  command(0x21);       //col addr
  command(13 * x);     //col start
  command(13 * x + 9); //col end
  command(0x22);       //0x22
  command(y);          // Page start
  command(y + 1);      // Page end

  Wire.beginTransmission(addr);
  Wire.write(0x40);

  for (i = 0; i < 5; i++) {
    line = font[5 * (fig - 32) + i]; //line=font[5*(fig-32)+i];
    btm = 0; top = 0;
    // expend char
    if (line & 64) {
      btm += 192;
    }
    if (line & 32) {
      btm += 48;
    }
    if (line & 16) {
      btm += 12;
    }
    if (line & 8) {
      btm += 3;
    }

    if (line & 4) {
      top += 192;
    }
    if (line & 2) {
      top += 48;
    }
    if (line & 1) {
      top += 12;
    }

    Wire.write(top);   //top page
    Wire.write(btm);   //second page
    Wire.write(top);
    Wire.write(btm);

  }
  Wire.endTransmission();

  command(0x20);      // horizontal mode
  command(0x00);

}
void ledsclear() {
  leds.clear();  // Minden LED kikapcsolása
  leds.show();   // LED-ek frissítése
  ledState = 0;  // Az aktuális LED számának nullázása
}







A programot itt tesztelheted: https://wokwi.com/projects/362424826523789313


Frissítés: 2025.08.26.

A használat során többször előfordult, hogy a beütött helyes kódot elutasította, így módosítottam a kódban, mivel a get_key() függvényben nem volt debounce kezelés.
Ha egy gomb mechanikailag "zizeg" (bounce-ol), akkor egyetlen lenyomás több értéket is adhat, vagy rosszul olvasódhat ki.

Update: 2025.08.26.

During use, it happened several times that the correct entered code was rejected, so I modified the code, since there was no debounce handling in the get_key() function.
If a button mechanically “bounces,” a single press can produce multiple values or be read incorrectly.

Kód: Egész kijelölése

#include <Wire.h>
#include <EEPROM.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN 11   // A neopixel led adatvezeték csatlakozója az Arduino-n
#define LED_COUNT 4  // A használt LED-ek száma
Adafruit_NeoPixel leds(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
int ledState = 0;

unsigned char addr = 0x3C; //0x78

//  standard ascii 5x7 font - https://github.com/PaulStoffregen/LedDisplay/blob/master/font5x7.h
//  0x3E, 0x51, 0x49, 0x45, 0x3E,  //crossed 0
static const unsigned char  font[] = {
  0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x5F, 0x00, 0x00,
  0x00, 0x07, 0x00, 0x07, 0x00,
  0x14, 0x7F, 0x14, 0x7F, 0x14,
  0x24, 0x2A, 0x7F, 0x2A, 0x12,
  0x23, 0x13, 0x08, 0x64, 0x62,
  0x36, 0x49, 0x56, 0x20, 0x50,
  0x00, 0x08, 0x07, 0x03, 0x00,
  0x00, 0x1C, 0x22, 0x41, 0x00,
  0x00, 0x41, 0x22, 0x1C, 0x00,
  0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
  0x08, 0x08, 0x3E, 0x08, 0x08,
  0x00, 0x80, 0x70, 0x30, 0x00,
  0x08, 0x08, 0x08, 0x08, 0x08,
  0x00, 0x00, 0x60, 0x60, 0x00,
  0x20, 0x10, 0x08, 0x04, 0x02,
  0x3E, 0x41, 0x41, 0x41, 0x3E,   //un-crossed 0
  0x00, 0x42, 0x7F, 0x40, 0x00,
  0x72, 0x49, 0x49, 0x49, 0x46,
  0x21, 0x41, 0x49, 0x4D, 0x33,
  0x18, 0x14, 0x12, 0x7F, 0x10,
  0x27, 0x45, 0x45, 0x45, 0x39,
  0x3C, 0x4A, 0x49, 0x49, 0x31,
  0x41, 0x21, 0x11, 0x09, 0x07,
  0x36, 0x49, 0x49, 0x49, 0x36,
  0x46, 0x49, 0x49, 0x29, 0x1E,
  0x00, 0x00, 0x14, 0x00, 0x00,
  0x00, 0x40, 0x34, 0x00, 0x00,
  0x00, 0x08, 0x14, 0x22, 0x41,
  0x14, 0x14, 0x14, 0x14, 0x14,
  0x00, 0x41, 0x22, 0x14, 0x08,
  0x02, 0x01, 0x59, 0x09, 0x06,
  0x3E, 0x41, 0x5D, 0x59, 0x4E,
  0x7C, 0x12, 0x11, 0x12, 0x7C,    //A
  0x7F, 0x49, 0x49, 0x49, 0x36,
  0x3E, 0x41, 0x41, 0x41, 0x22,
  0x7F, 0x41, 0x41, 0x41, 0x3E,
  0x7F, 0x49, 0x49, 0x49, 0x41,
  0x7F, 0x09, 0x09, 0x09, 0x01,
  0x3E, 0x41, 0x41, 0x51, 0x73,
  0x7F, 0x08, 0x08, 0x08, 0x7F,   //H
  0x00, 0x41, 0x7F, 0x41, 0x00,
  0x20, 0x40, 0x41, 0x3F, 0x01,
  0x7F, 0x08, 0x14, 0x22, 0x41,
  0x7F, 0x40, 0x40, 0x40, 0x40,
  0x7F, 0x02, 0x1C, 0x02, 0x7F,
  0x7F, 0x04, 0x08, 0x10, 0x7F,
  0x3E, 0x41, 0x41, 0x41, 0x3E,
  0x7F, 0x09, 0x09, 0x09, 0x06,
  0x3E, 0x41, 0x51, 0x21, 0x5E,
  0x7F, 0x09, 0x19, 0x29, 0x46,
  0x26, 0x49, 0x49, 0x49, 0x32,   //S
  0x03, 0x01, 0x7F, 0x01, 0x03,
  0x3F, 0x40, 0x40, 0x40, 0x3F,
  0x1F, 0x20, 0x40, 0x20, 0x1F,
  0x3F, 0x40, 0x38, 0x40, 0x3F,
  0x63, 0x14, 0x08, 0x14, 0x63,
  0x03, 0x04, 0x78, 0x04, 0x03,
  0x61, 0x59, 0x49, 0x4D, 0x43,
  0x00, 0x7F, 0x41, 0x41, 0x41,
  0x02, 0x04, 0x08, 0x10, 0x20,
  0x00, 0x41, 0x41, 0x41, 0x7F,
  0x04, 0x02, 0x01, 0x02, 0x04,
  0x40, 0x40, 0x40, 0x40, 0x40,
  0x00, 0x03, 0x07, 0x08, 0x00,
  0x20, 0x54, 0x54, 0x78, 0x40,
  0x7F, 0x28, 0x44, 0x44, 0x38,
  0x38, 0x44, 0x44, 0x44, 0x28,
  0x38, 0x44, 0x44, 0x28, 0x7F,
  0x38, 0x54, 0x54, 0x54, 0x18,
  0x00, 0x08, 0x7E, 0x09, 0x02,
  0x18, 0xA4, 0xA4, 0x9C, 0x78,
  0x7F, 0x08, 0x04, 0x04, 0x78,
  0x00, 0x44, 0x7D, 0x40, 0x00,
  0x20, 0x40, 0x40, 0x3D, 0x00,
  0x7F, 0x10, 0x28, 0x44, 0x00,
  0x00, 0x41, 0x7F, 0x40, 0x00,
  0x7C, 0x04, 0x78, 0x04, 0x78,
  0x7C, 0x08, 0x04, 0x04, 0x78,   //n
  0x38, 0x44, 0x44, 0x44, 0x38,
  0xFC, 0x18, 0x24, 0x24, 0x18,
  0x18, 0x24, 0x24, 0x18, 0xFC,
  0x7C, 0x08, 0x04, 0x04, 0x08,
  0x48, 0x54, 0x54, 0x54, 0x24,
  0x04, 0x04, 0x3F, 0x44, 0x24,
  0x3C, 0x40, 0x40, 0x20, 0x7C,   //u
  0x1C, 0x20, 0x40, 0x20, 0x1C,
  0x3C, 0x40, 0x30, 0x40, 0x3C,
  0x44, 0x28, 0x10, 0x28, 0x44,
  0x4C, 0x90, 0x90, 0x90, 0x7C,
  0x44, 0x64, 0x54, 0x4C, 0x44,   //z
  0x00, 0x08, 0x36, 0x41, 0x00,
};
unsigned char key, mem[4], num[4], ir = 0;
bool pMode = false;

void setup() {
  pinMode(7, OUTPUT);  //relé
  pinMode(8, OUTPUT);  // COL1
  pinMode(9, OUTPUT);  // COL2
  pinMode(10, OUTPUT); // COL3
  pinMode(13, OUTPUT);  //ready LED
  pinMode(12, OUTPUT);  //buzzer
  pinMode(2, INPUT_PULLUP); // ROW4
  pinMode(3, INPUT_PULLUP); // ROW3
  pinMode(4, INPUT_PULLUP); // ROW2
  pinMode(5, INPUT_PULLUP); // ROW1
  pinMode(6, INPUT_PULLUP); //nyomógomb pMode

  leds.begin();  // LED-ek inicializálása

  Wire.begin();        // init i2c bus
  Wire.setClock(200000);  //200khz
  oled_init();
  clrScreen();

  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);

  readyL();
  for (unsigned char i = 0; i < 4; ++i) {
    num[i] = EEPROM.read(i);
  }
  for (unsigned char j = 0; j < 4; j++) {
    drawChar2(0x5F, 5, j + 2);
  }
}

void loop()
{

  if (!digitalRead(6)) {
    pMode = true;
    drawChar2(0x20,1,1);
    drawChar2(0x43,1,2);  //code, programozó módhoz
    drawChar2(0x4F,1,3);
    drawChar2(0x44,1,4);
    drawChar2(0x45,1,5);
    drawChar2(0x20,1,6);
    drawChar2(0x20,1,7);
    drawChar2(0x20,1,8);
    drawChar2(32, 1, 6);
    digitalWrite(13, LOW);
  }

  if (!digitalRead(5) || !digitalRead(4) || !digitalRead(3) || !digitalRead(2)) {
    get_key();
    tone(12, 1000, 50);
    drawChar2(key + 48, 5, ir + 2);
    mem[ir] = key;
    if (ir < LED_COUNT) {  // Ha még nem világít az összes LED-ek
      leds.setPixelColor(ledState, 0, 0, 255);  // Az aktuális LED bekapcsolása kékre
      leds.show();  // LED-ek frissítése
      ledState++;   // Az aktuális LED számának növelése
    }

    if (ir == 3 && pMode == false) {
      if (mem[0] == num[0] && mem[1] == num[1] && mem[2] == num[2] && mem[3] == num[3]) {
        digitalWrite(7, HIGH);
        for (int i = 0; i < 4; i++) {
          leds.setPixelColor(i, 0, 255, 0); // minden LED zöldre kapcsolása, ha helyes kód lett beírva
        }
        leds.show(); // a változtatások megjelenítése a LED-eken
        tone(12, 1000, 150);
        delay(150);
        tone(12, 1500, 150);
        delay(2000);         // Relé ennyi ideig húz be
        digitalWrite(7, LOW);

        ledsclear();

      }

      if (mem[0] != num[0] || mem[1] != num[1] || mem[2] != num[2] || mem[3] != num[3]) {

        for (int i = 0; i < 4; i++) {
          leds.setPixelColor(i, 255, 0, 0); // minden LED pirosra kapcsolása, ha hibás kód lett beírva
        }
        leds.show(); // a változtatások megjelenítése a LED-eken

        tone(12, 1000, 150);
        delay(200);
        tone(12, 1500, 150);
        delay(200);
        tone(12, 2000, 150);
        delay(200);
        tone(12, 1500, 150);
        delay(200);
        tone(12, 1000, 150);
        delay(300);

        ledsclear();


      }
    }
    if (ir == 3 && pMode == true) {
      for (unsigned char j = 0; j < 4; j++) {
        EEPROM.write(j, mem[j]);
      }
      num[0] = mem[0];
      num[1] = mem[1];
      num[2] = mem[2];
      num[3] = mem[3];
      ledsclear();
      pMode = false;
      readyL();
    }
    ir++;
    if (ir == 4) {
      ir = 0;
      for (unsigned char j = 0; j < 4; j++) {
        drawChar2(0x5F, 5, j + 2);
      }
    }
    while (!digitalRead(5) || !digitalRead(4) || !digitalRead(3) || !digitalRead(2)) {}
    delay(100);
  }

}

void readyL() {
  drawChar2(0x4e, 1, 1); //NYITOKOD
  drawChar2(0x59, 1, 2);
  drawChar2(0x49, 1, 3);
  drawChar2(0x54, 1, 4);
  drawChar2(0x4f, 1, 5);
  drawChar2(0x4b, 1, 6);
  drawChar2(0x4f, 1, 7);
  drawChar2(0x44, 1, 8);
  digitalWrite(13, HIGH);
}

void get_key() {
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  if (!digitalRead(5)) {
    key = 1;
  }
  if (!digitalRead(4)) {
    key = 4;
  }
  if (!digitalRead(3)) {
    key = 7;
  }

  digitalWrite(9, LOW);
  digitalWrite(8, HIGH);
  digitalWrite(10, HIGH);
  if (!digitalRead(5)) {
    key = 2;
  }
  if (!digitalRead(4)) {
    key = 5;
  }
  if (!digitalRead(3)) {
    key = 8;
  }
  if (!digitalRead(2)) {
    key = 0;
  }

  digitalWrite(10, LOW);
  digitalWrite(9, HIGH);
  digitalWrite(8, HIGH);
  if (!digitalRead(5)) {
    key = 3;
  }
  if (!digitalRead(4)) {
    key = 6;
  }
  if (!digitalRead(3)) {
    key = 9;
  }

  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
}

void clrScreen()    //fill screen with 0
{
  unsigned char y, x;

  for ( y = 0; y < 8; y++ ) {
    for (x = 0; x < 17; x++) {
      command(0x21);      //col addr
      command(8 * x);     //col start
      command(8 * x + 7); //col end
      command(0x22);      //0x22
      command(y);         // Page start
      command(y);         // Page end

      Wire.beginTransmission(addr);
      Wire.write(0x40);
      for (unsigned char i = 0; i < 8; i++) {
        Wire.write(0x00);
      }
      Wire.endTransmission();
    }

  }
}

void command( unsigned char comm) {
  Wire.beginTransmission(addr);
  Wire.write(0x00);
  Wire.write(comm); // LSB
  Wire.endTransmission();
}

void oled_init() {  // https://www.micros.com.pl/mediaserver/OLED12864-0.96-W-2_0001.pdf

  command(0xAE);   // DISPLAYOFF
  command(0x8D);   // CHARGEPUMP *
  command(0x14);   //0x14-pump on
  command(0x20);   // MEMORYMODE
  command(0x0);    //0x0=horizontal, 0x01=vertical, 0x02=page
  command(0xA1);   //SEGREMAP * A0/A1=top/bottom
  command(0xC8);   //COMSCANDEC * C0/C8=left/right
  command(0xDA);   // SETCOMPINS *
  command(0x12);   //0x22=4rows, 0x12=8rows
  command(0x81);   // SETCONTRAST
  command(0x9F);   //0x8F

  //following settings are set by default
  //    command(0xD5);  // SETDISPLAYCLOCKDIV
  //    command(0x80);
  //    command(0xA8);  // SETMULTIPLEX
  //    command(0x3F);  // 0x1F
  //    command(0xD3);  // SETDISPLAYOFFSET
  //    command(0x0);
  //    command(0x40);  // SETSTARTLINE
  //    command(0xD9);  // SETPRECHARGE
  //    command(0xF1);
  //    command(0xDB);  // SETVCOMDETECT
  //    command(0x40);
  //    command(0xA4);  // DISPLAYALLON_RESUME
  //    command(0xA6);  // NORMALDISPLAY
  command(0xAF);    //DISPLAYON

}

//size x1 chars
void drawChar(char fig, unsigned char y, unsigned char x)
{

  command(0x21);       //col addr
  command(7 * x);      //col start
  command(7 * x + 4);  //col end
  command(0x22);       //0x22
  command(y);          // Page start
  command(y);          // Page end

  Wire.beginTransmission(addr);
  Wire.write(0x40);
  for (unsigned char i = 0; i < 5; i++) {
    Wire.write(font[5 * (fig - 32) + i]);
  }
  Wire.endTransmission();

}
//size x2 chars
void drawChar2(char fig, unsigned char y, unsigned char x)
{
  unsigned char i, line, btm, top;    //

  command(0x20);       // vert mode
  command(0x01);

  command(0x21);       //col addr
  command(13 * x);     //col start
  command(13 * x + 9); //col end
  command(0x22);       //0x22
  command(y);          // Page start
  command(y + 1);      // Page end

  Wire.beginTransmission(addr);
  Wire.write(0x40);

  for (i = 0; i < 5; i++) {
    line = font[5 * (fig - 32) + i]; //line=font[5*(fig-32)+i];
    btm = 0; top = 0;
    // expend char
    if (line & 64) {
      btm += 192;
    }
    if (line & 32) {
      btm += 48;
    }
    if (line & 16) {
      btm += 12;
    }
    if (line & 8) {
      btm += 3;
    }

    if (line & 4) {
      top += 192;
    }
    if (line & 2) {
      top += 48;
    }
    if (line & 1) {
      top += 12;
    }

    Wire.write(top);   //top page
    Wire.write(btm);   //second page
    Wire.write(top);
    Wire.write(btm);

  }
  Wire.endTransmission();

  command(0x20);      // horizontal mode
  command(0x00);

}
void ledsclear() {
  leds.clear();  // Minden LED kikapcsolása
  leds.show();   // LED-ek frissítése
  ledState = 0;  // Az aktuális LED számának nullázása
}

A programot itt tesztelheted: https://wokwi.com/projects/440336519022628865

Az OLED kijelzőt kivettem a kódból, mivel a Neopixel led kijelzés teljesen jónak bizonyul, nincs szükség az OLED-re.
A D13 lábon a led a programozó módot jelzi, így a rejtett gomb lenyomása után világít, ebből tudjuk, hogy a következő beütött kód lesz eltárolva az EPROM-ban.

I removed the OLED display from the code, since the Neopixel LED display proved to be completely sufficient, there is no need for the OLED.
The LED on pin D13 indicates programming mode, so after pressing the hidden button it lights up, letting us know that the next entered code will be stored in the EPROM.

Kód: Egész kijelölése

/*
  Kódos ajtónyitó rendszer
  Verzió: v1.0
  Dátum: 2025-08-26
  Hardver: Arduino Pro Mini, 4x3 mátrix billentyűzet, relé, NeoPixel LED-ek
  Leírás:
    - 4 jegyű kód alapján vezérli a relét
    - Programozó módban új kód menthető EEPROM-ba
    - LED-ek és buzzer adnak visszajelzést
    - D13 LED világít programozó módban, normál módban sötét
*/

#include <EEPROM.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN 11   // A neopixel LED adatvezeték csatlakozója az Arduino-n
#define LED_COUNT 4  // A használt LED-ek száma
Adafruit_NeoPixel leds(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
int ledState = 0;

unsigned char key, mem[4], num[4], ir = 0;
bool pMode = false;

void setup() {
  pinMode(7, OUTPUT);   // relé
  pinMode(8, OUTPUT);   // COL1
  pinMode(9, OUTPUT);   // COL2
  pinMode(10, OUTPUT);  // COL3
  pinMode(13, OUTPUT);  // programozó LED
  pinMode(12, OUTPUT);  // buzzer
  pinMode(2, INPUT_PULLUP); // ROW4
  pinMode(3, INPUT_PULLUP); // ROW3
  pinMode(4, INPUT_PULLUP); // ROW2
  pinMode(5, INPUT_PULLUP); // ROW1
  pinMode(6, INPUT_PULLUP); // nyomógomb pMode

  leds.begin();

  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);

  // EEPROM-ból beolvassuk a tárolt kódot
  for (unsigned char i = 0; i < 4; ++i) {
    num[i] = EEPROM.read(i);
  }

  digitalWrite(13, LOW); // alapból nem világít (nem programozó módban)
}

void loop() {
  // Programozó mód kapcsoló
  if (!digitalRead(6)) {
    pMode = true;
    digitalWrite(13, HIGH); // programozó LED bekapcsol
  }

  // Ha bármelyik gomb lenyomva
  if (!digitalRead(5) || !digitalRead(4) || !digitalRead(3) || !digitalRead(2)) {
    int pressed = get_key();
    if (pressed != -1) {
      tone(12, 1000, 50);
      mem[ir] = pressed;

      // LED visszajelzés kék
      if (ir < LED_COUNT) {
        leds.setPixelColor(ledState, 0, 0, 255);
        leds.show();
        ledState++;
      }

      // Ha megvan a 4 szám
      if (ir == 3 && pMode == false) {
        if (mem[0] == num[0] && mem[1] == num[1] && mem[2] == num[2] && mem[3] == num[3]) {
          // Helyes kód
          digitalWrite(7, HIGH);
          for (int i = 0; i < 4; i++) {
            leds.setPixelColor(i, 0, 255, 0); // zöld
          }
          leds.show();
          tone(12, 1000, 150);
          delay(150);
          tone(12, 1500, 150);
          delay(2500);  // relé ennyi ideig húz be
          digitalWrite(7, LOW);
          ledsclear();
        } else {
          // Hibás kód
          for (int i = 0; i < 4; i++) {
            leds.setPixelColor(i, 255, 0, 0); // piros
          }
          leds.show();
          tone(12, 1000, 150); delay(200);
          tone(12, 1500, 150); delay(200);
          tone(12, 2000, 150); delay(200);
          tone(12, 1500, 150); delay(200);
          tone(12, 1000, 150); delay(300);
          ledsclear();
        }
      }

      // Programozó mód: új kód mentése EEPROM-ba
      if (ir == 3 && pMode == true) {
        for (unsigned char j = 0; j < 4; j++) {
          EEPROM.write(j, mem[j]);
          num[j] = mem[j];
        }
        ledsclear();
        pMode = false;
        digitalWrite(13, LOW); // kilépés programozó módból
      }

      ir++;
      if (ir == 4) {
        ir = 0;
      }

      // várunk, amíg felengedik a gombot
      while (!digitalRead(5) || !digitalRead(4) || !digitalRead(3) || !digitalRead(2)) {}
      delay(100);
    }
  }
}

int get_key() {
  int detectedKey = -1;
  int lastKey = -1;
  unsigned long startTime = millis();

  // max 50 ms-ig figyelünk, stabil érték kell
  while (millis() - startTime < 50) {
    int currentKey = -1;

    // Oszlop 1
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    if (!digitalRead(5)) currentKey = 1;
    if (!digitalRead(4)) currentKey = 4;
    if (!digitalRead(3)) currentKey = 7;

    // Oszlop 2
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(10, HIGH);
    if (!digitalRead(5)) currentKey = 2;
    if (!digitalRead(4)) currentKey = 5;
    if (!digitalRead(3)) currentKey = 8;
    if (!digitalRead(2)) currentKey = 0;

    // Oszlop 3
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(8, HIGH);
    if (!digitalRead(5)) currentKey = 3;
    if (!digitalRead(4)) currentKey = 6;
    if (!digitalRead(3)) currentKey = 9;

    // Ha kétszer egymás után ugyanaz jött -> stabil
    if (currentKey == lastKey && currentKey != -1) {
      detectedKey = currentKey;
      break;
    }

    lastKey = currentKey;
    delay(5);
  }

  // reseteljük az oszlopokat
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);

  if (detectedKey != -1) {
    key = detectedKey;
  }

  return detectedKey;
}

void ledsclear() {
  leds.clear();
  leds.show();
  ledState = 0;
}

A programot itt tesztelheted: https://wokwi.com/projects/440337392279086081

Válasz küldése

Ki van itt

Jelenlévő fórumozók: nincs regisztrált felhasználó valamint 1 vendég