Jednoduchý kódový zámek. Kombinace keypadu 4x4 a displeje SSD1306. Otevřený zámek je signalizován svítící LED na Picu.

Zdrojové kódy

CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(kodzamek C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

pico_sdk_init()
include($ENV{LIB_SSD1306_UTF8_PATH}/pico_lib_ssd1306_utf8_import.cmake)

add_executable(kodzamek
    kodzamek.c
)

target_include_directories(kodzamek PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}
    ${ssd1306_utf8_SOURCE_DIR}/src
)

target_link_libraries(kodzamek
    pico_stdlib
    hardware_i2c
    ssd1306_utf8
    )
pico_enable_stdio_usb(kodzamek 1)
pico_enable_stdio_uart(kodzamek 0)

pico_add_extra_outputs(kodzamek)
kodzamek.c
/* kodzamek.c
 * Jednoduchý kódový zámek
 * (c) Jirka Chráska 2026, <jirka@lixis.cz>
 */

#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "ssd1306.h"
#include "font.h"
#include <stdio.h>
#include <string.h>

// pro OLED displej SSD1306
#define DISPLAY_WIDTH   128			// šířka displeje
#define DISPLAY_HEIGHT  32			// výška displeje
#define I2C_ADDRESS     0x3C		// i2c adresa
#define I2C_FREQ        1000000		// rychlost i2c sběrnice
// rychlost i2c sběrnice může být až 2000000
#define SDA_PIN         4			// datový pin
#define SDC_PIN         5			// hodinový pin
#define I2C             i2c0		// i2c hardware

// struktura pro OLED displej včetně framebufferu
static ssd1306_t disp;

// všechny použité fonty
extern bitmapFONT font_spleen_8x16;

#define BASE_KEYPAD_PIN 9
#define KEYROWS         4
#define NUMKEYS         16

// Inicializujeme celou klávesnici
void keypad_init() 
{
    gpio_init_mask((0xFF << BASE_KEYPAD_PIN));
    // Nastavíme řádkové piny (GP9, GP10, GP11 a GP12) jako výstupní
    gpio_set_dir_out_masked((0xF << BASE_KEYPAD_PIN));
    // Nastavíme všechny výstupní piny na nízkou úroveň
    gpio_put_masked((0xF << BASE_KEYPAD_PIN), (0x0 << BASE_KEYPAD_PIN));
    // Zapneme pro vstupní sloupcové piny pull-down rezistory (je to nastaveno implicitně)
    gpio_pull_down((BASE_KEYPAD_PIN + 4));
    gpio_pull_down((BASE_KEYPAD_PIN + 5));
    gpio_pull_down((BASE_KEYPAD_PIN + 6));
    gpio_pull_down((BASE_KEYPAD_PIN + 7));
}

int keypad_read()
{
// klávesa na klávesnici            0     1     2     3     4     5     6     7     8     9     
//                                  A     B     C     D     *     #
unsigned int keycodes[NUMKEYS]  = { 0x28, 0x11, 0x21, 0x41, 0x12, 0x22, 0x42, 0x14, 0x24, 0x44, 
                                    0x81, 0x82, 0x84, 0x88, 0x18, 0x48};
unsigned int scancodes[KEYROWS] = { 0x01, 0x02, 0x04, 0x08} ;
unsigned int button = 0xF0 ;
unsigned int keypad;
int i;

    // Skenujeme klávesnici
    for (i=0; i<KEYROWS; i++) {
        // Nastavíme řádek na jedničku
        gpio_put_masked((0xF << BASE_KEYPAD_PIN), (scancodes[i] << BASE_KEYPAD_PIN));
        // potřebujeme malou prodlevu
        sleep_us(1) ; 
        // Čteme kód klávesy
        keypad = ((gpio_get_all() >> BASE_KEYPAD_PIN) & 0xFF);
        //printf("keypad=%x\n",keypad);
        // Vyskočíme, pokud je nějaké tlačítko stisknuto
        if (keypad & button) break;
    }
    // Pokud jsme našli tlačítko . . .
    if (keypad & button) {
        // Ověříme kód klávesy.
        for (i=0; i<NUMKEYS; i++) {
            if (keypad == keycodes[i]) break ; // podařilo se
        }
        // Pokud se nám ověření klávesy nepodařilo, vrátíme neplatný kód klávesy
        if (i==NUMKEYS) (i = -1);
    }
    // Cokoliv jiného znamená neplatný kód klávesy nebo nestisknuté tlačítko.
    else (i=-1) ;
return i;
}

// nastavení I2C sběrnice
void setup_i2c(void)
{
    i2c_init(I2C, I2C_FREQ);
    gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(SDC_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(SDA_PIN);
    gpio_pull_up(SDC_PIN);
    // pauza je nutná kvůli displeji. Pokud není displej se někdy nerozsvítí
    sleep_ms(200);
}

void zapnuti_displeje( void )
{
    ssd1306_init(&disp, DISPLAY_WIDTH, DISPLAY_HEIGHT, I2C_ADDRESS, I2C); // inicializace
    ssd1306_poweron(&disp); // zapnutí displeje
    ssd1306_clear(&disp);   // vymazání displeje
    ssd1306_contrast(&disp,0x50);
    ssd1306_show(&disp); // zobrazíme na displeji
}

#define BUF_LEN 128
#define ZAMEK_PIN 25

int main()
{
int klavesa = -1;
int predchozi_klavesa = -1;
char c[NUMKEYS] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C' ,'D', '*', '#'};
const char tajne[] = "2931";
char buffer[BUF_LEN+1];
int index = 0;

    memset(buffer, '\0', BUF_LEN+1);
    stdio_init_all();
    sleep_ms(1000);
    printf("Kódový zámek.\n");
    keypad_init();

    // nastavení zámku
    gpio_init(ZAMEK_PIN);
    gpio_set_dir(ZAMEK_PIN,GPIO_OUT);
    gpio_put(ZAMEK_PIN,1);
    sleep_ms(300);
    gpio_put(ZAMEK_PIN,0);

    // nastavení displeje SSD1306
    setup_i2c();
    zapnuti_displeje();
    sleep_ms(10);
    // vymazání framebufferu
	ssd1306_clear(&disp);
    ssd1306_draw_utf8_string(&disp, 0, 0, &font_spleen_8x16, "Zadejte PIN");
    ssd1306_draw_utf8_string(&disp, 0, 16, &font_spleen_8x16, "----");
    ssd1306_show(&disp); // zobrazíme písmenka na displeji
                    
    while( true ) {
        klavesa = keypad_read();
        if( klavesa != -1 && klavesa != predchozi_klavesa ) {
            printf("Stisknuta klávesa %c, index = %d\n",c[klavesa], index);
            predchozi_klavesa = klavesa;    
            if(c[klavesa] == '#' ) { // vynulování bufferu
                index = 0;
                memset(buffer,'\0',BUF_LEN+1);    
            } else if(c[klavesa] == '*') { // výmaz posledního znaku
                if( index > 0 ) {
                    buffer[index-1] = '\0';
                    index--;
                }
            } else {
                if( index < BUF_LEN ) {
                    buffer[index] = c[klavesa];
                    index++;
                    buffer[index] = '\0';
                    // vymazání framebufferu
                } else {
                    index = 0;
                    memset(buffer, '\0', BUF_LEN);
                }
            }
        } 
        else {
            predchozi_klavesa = -1;
        }
        if(strcmp(buffer,tajne) == 0 ) { // otevřít zámek
            ssd1306_clear(&disp);
            ssd1306_draw_utf8_string(&disp, 0, 0, &font_spleen_8x16, "Otevřeno.");
            ssd1306_draw_utf8_string(&disp, 0, 16, &font_spleen_8x16, buffer);
            ssd1306_show(&disp); // zobrazíme písmenka na displeji
            gpio_put(ZAMEK_PIN,1);
        } else {
            ssd1306_clear(&disp);
            ssd1306_draw_utf8_string(&disp, 0, 0, &font_spleen_8x16, "Zadejte PIN");
            if( strlen(buffer) == 0 ) {
                ssd1306_draw_utf8_string(&disp, 0, 16, &font_spleen_8x16, "----");
            } else {
                ssd1306_draw_utf8_string(&disp, 0, 16, &font_spleen_8x16, buffer);
            }
            ssd1306_show(&disp); // zobrazíme písmenka na displeji
            gpio_put(ZAMEK_PIN,0);
        }
        sleep_ms(200);
    }
}

Obrázky

IMG 20260601 222451

Konstrukce studentů

Radek Čtvrtečka

IMG 20260612 131311

Dominik Weselak

IMG 20260615 141717

Šimon Píša

IMG 20260615 141638

Jan Přibyl

IMG 20260615 134156

Tomáš Trojna

IMG 20260615 132450

Marek Touc

IMG 20260615 132441