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

Konstrukce studentů
Radek Čtvrtečka

Dominik Weselak

Šimon Píša

Jan Přibyl

Tomáš Trojna

Marek Touc
