Tento článek popisuje metodu propojení maticové klávesnice 4x4, jako je ta znázorněná na obrázku, s Picem. Existují i jiné metody pro vytvoření tohoto rozhraní (byla by to například pěkná aplikace pro koprocesory PIO — bude popsáno dole). Tato metoda je podle mého nejjednodušší a vystačíme si se znalostmi z programování GPIO.


Čtení klávesnice
Konfigurace GPIO
Pro skenování klávesnice a detekci stisknutí tlačítek nakonfigurujeme každý z GPIO připojených k řádkům klávesnice (9-12, jak je znázorněno na schématu) jako výstupy a každý z GPIO připojených ke sloupcům klávesnice (13-16, jak je znázorněno na schématu) nakonfigurujeme jako vstupy. Pro každý ze vstupních pinů povolíme interní pull-down rezistory. Pro začátek nastavíme všechny připojené výstupní GPIO na nízkou úroveň.
Použitím C SDK pro RP2040 vypadají všechny tyto konfigurace následovně:
#define BASE_KEYPAD_PIN 9
// Inicializujeme celou klávesnici
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)) ;
Skenování klávesnice
RP2040 nám umožňuje získat stav všech GPIO portů pomocí funkce gpio_get_all().
Tato funkce vrací 32bitové celé číslo bez znaménka, jehož každý bit představuje stav (vysoký nebo nízký) přidruženého GPIO portu (bit 0 je GPIO 0, bit 1 je GPIO 1 atd.).
Klávesnici prohledáme tak, že postupně nastavíme GPIO připojené ke sloupcům matice na vysokou úroveň a poté přečteme stavy všech 7 GPIO připojených ke klávesnici.
Pro usnadnění zavoláme gpio_get_all(), poté posuneme výsledek doprava o 9 (takže stav GPIO 9 bude v bitu 0) a poté maskujeme pomocí 0xff. Tímto způsobem nám zůstane 8bitové číslo, kde každý bit v tomto čísle představuje jeden z pinů klávesnice. První čtyři jsou připojeny k řádkům a další 4 ke sloupcům.
keypad = ((gpio_get_all() >> BASE_KEYPAD_PIN) & 0xFF) ;
Předpokládejme, že nastavíme GPIO 9 a nestiskneme žádné klávesy. Pak žádný z pinů sloupce není zkratován s piny řádku a všechny zůstanou na nízké úrovni. Bit spojený s GPIO 9 bude na vysoké úrovni (protože jsme ho nastavili na vysokou úroveň), ale žádný z ostatních. Takže když skenujeme klávesnici, dostaneme hodnotu 0b0000001 neboli 0x01. Toto je skenovací kód, který odpovídá „nestisknutí“.
Předpokládejme místo toho, že nastavíme GPIO 9 na vysokou úroveň a stiskneme klávesu 1. Jakou hodnotu bychom od klávesnice očekávali? Bit spojený s GPIO 9 bude mít vysokou hodnotu (protože jsme ho nastavili na vysokou hodnotu) a bit spojený s GPIO 13 bude také vysoký, protože stisknutí klávesy 1 ji zkratovalo na GPIO 9. Binární hodnota pro klávesnici tedy bude 0b00010001, neboli 0x11 v hexadecimální soustavě.
Předpokládejme, že bychom místo toho stiskli 2. Pak by bity klávesnice spojené s GPIO 9 a 14 byly vysoké. Dostali bychom skenovací kód 0b00100001, neboli 0x21.
Dále předpokládejme, že bychom stiskli 3. Pak by bity klávesnice spojené s GPIO 9 a 15 byly vysoké. Dostali bychom skenovací kód 0b01000001, neboli 0x41.
Nakonec předpokládejme, že bychom stiskli A. Pak by bity klávesnice spojené s GPIO 9 a 15 byly vysoké. Dostali bychom skenovací kód 0b10000001, neboli 0x81.
Pokud bychom dostali jiný skenovací kód než 0x01, 0x11, 0x21, 0x41 nebo 0x81, pak to znamená, že uživatel stiskl dvě klávesy současně.
Můžete rozšířit kódy kláves, aby vyhovovaly těmto případům, ale prozatím je budeme považovat za „neplatné stisknutí“.
Níže uvedená tabulka uvádí tyto případy pro řádek 0 a rozšiřuje se o skenovací kódy pro další tři řádky klávesnice.
| GPIO16 | GPIO15 | GPIO14 | GPIO13 | GPIO12 | GPIO11 | GPIO10 | GPIO9 | řídící kód | sken kód | význam |
|---|---|---|---|---|---|---|---|---|---|---|
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0x1 |
0x01 |
nestisknuto |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
0x1 |
0x11 |
stisknuto 1 |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
0x1 |
0x21 |
stisknuto 2 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
0x1 |
0x41 |
stisknuto 3 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0x1 |
0x81 |
stisknuto A |
x |
x |
x |
x |
0 |
0 |
0 |
1 |
0x1 |
jiné |
neplatné stisknutí |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0x2 |
0x02 |
nestisknuto |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
0 |
0x2 |
0x12 |
stisknuto 4 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
0 |
0x2 |
0x22 |
stisknuto 5 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
0x2 |
0x42 |
stisknuto 6 |
1 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0x2 |
0x82 |
stisknuto B |
x |
x |
x |
x |
0 |
0 |
1 |
0 |
0x2 |
jiné |
neplatné stisknutí |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0x4 |
0x04 |
nestisknuto |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
0x4 |
0x14 |
stisknuto 7 |
0 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
0x4 |
0x24 |
stisknuto 8 |
0 |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0x4 |
0x44 |
stisknuto 9 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0x4 |
0x84 |
stisknuto C |
x |
x |
x |
x |
0 |
1 |
0 |
0 |
0x4 |
jiné |
neplatné stisknutí |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0x8 |
0x08 |
nestisknuto |
0 |
0 |
0 |
1 |
1 |
0 |
0 |
0 |
0x8 |
0x18 |
stisknuto * |
0 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0x8 |
0x28 |
stisknuto 0 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
0 |
0x8 |
0x48 |
stisknuto # |
1 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
0x8 |
0x88 |
stisknuto D |
x |
x |
x |
x |
1 |
0 |
0 |
0 |
0x8 |
jiné |
neplatné stisknutí |
Všimněte si, že můžeme provést rychlou kontrolu, zda bylo stisknuto nějaké tlačítko, maskováním klávesnice pomocí 0xFF a kontrolou, zda je výsledek nenulový. Pokud je výsledek nenulový, znamená to, že byl stisknut jeden nebo více GPIO sloupců (16, 15, 14 a/nebo 13). Poté můžeme porovnat celý skenovací kód s platnými skenovacími kódy a určit, které tlačítko bylo stisknuto.
#define BASE_KEYPAD_PIN 9
#define KEYROWS 4
#define NUMKEYS 16
// 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) ;
// 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) ;
Po spuštění výše uvedeného kódu bude hodnota proměnné i == -1 pro nestisknutí nebo neplatné stisknutí, v opačném případě bude mít hodnotu stisknuté klávesy (0 pro klávesu 0, 1 pro klávesu 1, …, 10 pro klávesu A,
11 pro klávesu B, 12 pro klávesu C, 13 pro klávesu D a 14 pro klávesu * a 15 pro klávesu #).
Praktický test
Praktický test uděláme tak, že si budeme stisknuté klávesy zobrazovat pomocí stdio.
U klávesnice na horním obrázku nejsou klasické spínače, ale odporové s hodnotou přechodového odporu okolo \(45\Omega\), rezistory R1 až R4 jsem nahradil hodnotou \(470\Omega\), protože byly po ruce.
Možná by v zapojení odpory R1 až R4 nemusely být, protože proud do výstupního pinu je omezen implicitně na 2mA.
| pin | význam | barva v mé konstrukci |
|---|---|---|
1 |
1. řádek |
oranžová |
2 |
2. řádek |
žlutá |
3 |
3. řádek |
zelená |
4 |
4. řádek |
modrá |
5 |
1. sloupec |
fialová |
6 |
2. sloupec |
šedá |
7 |
3. sloupec |
bílá se šedým pruhem |
8 |
4. sloupec |
černá |

/* Testování maticové klávesnice 4x4
(c) Jirka Chráska 2025, <jirka@lixis.cz>
*/
#include <stdio.h>
#include <pico/stdlib.h>
#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);
// 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;
}
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','*','#'};
stdio_init_all();
sleep_ms(2000);
printf("Test klávesnice.\n");
keypad_init();
while( true ) {
klavesa = keypad_read();
if( klavesa != -1 && klavesa != predchozi_klavesa ) {
printf("Stisknuta klávesa %c\n",c[klavesa]);
predchozi_klavesa = klavesa;
}
else {
predchozi_klavesa = -1;
}
sleep_ms(200);
}
}
Po uplynutí 200 ms se bude stisk klávesy opakovat, budu-li ji stále držet.
cmake_minimum_required(VERSION 3.13)
set(PICO_BOARD pico)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(keypad4x4 C CXX ASM)
pico_sdk_init()
add_executable (keypad4x4 mkeypad4x4.c)
target_link_libraries(keypad4x4 LINK_PUBLIC
pico_stdlib
)
pico_add_extra_outputs(keypad4x4)
pico_enable_stdio_usb(keypad4x4 1)
pico_enable_stdio_uart(keypad4x4 0)
Test klávesnice.
Stisknuta klávesa 1
Stisknuta klávesa 2
Stisknuta klávesa 5
Stisknuta klávesa 5
Stisknuta klávesa 6
Stisknuta klávesa 8
Stisknuta klávesa 7
Stisknuta klávesa 7
Stisknuta klávesa 7
Stisknuta klávesa 7
Stisknuta klávesa 7
Stisknuta klávesa 7
Stisknuta klávesa 8
Stisknuta klávesa 8
Stisknuta klávesa 8
Stisknuta klávesa 8
Stisknuta klávesa 9
Stisknuta klávesa 9
Stisknuta klávesa 9
Stisknuta klávesa 9
Stisknuta klávesa C
Stisknuta klávesa C
Stisknuta klávesa C
Stisknuta klávesa C
Stisknuta klávesa A
Stisknuta klávesa A
Stisknuta klávesa 3
Stisknuta klávesa 2
Stisknuta klávesa 5
Stisknuta klávesa 1
Stisknuta klávesa 4
Stisknuta klávesa 5
Stisknuta klávesa 6
Stisknuta klávesa 7
Stisknuta klávesa 8
Stisknuta klávesa D
Stisknuta klávesa #
Stisknuta klávesa #
Stisknuta klávesa *
Stisknuta klávesa *
Stisknuta klávesa *
Stisknuta klávesa 5

Závěr
Tato konstrukce a program neumožňuje rozpoznat stisknutí dvou tlačítek najednou.
Maticovou klávesnici budu moci použít třeba k vylepšení Generátoru obdélníkových pulsů proměnné frekvence a střídy, protože bude mnohem jednoduší zadat kmitočet a střídu pomocí číselných hodnot a ne pomocí tlačítek.
Obsluha maticové klávesnice implementovaná pomocí PIO
Zde je implementace toho samého programu pomocí PIO stavového stroje a přerušení. Přerušení je vyvoláno při odchytnutí stisku klávesy.
/* keyboard.c
(c) Jirka Chráska 2025, jirka@lixis.cz
ovladač klávesnice 4x4 pomocí PIO
BSD 3 clause license
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "keyboard.pio.h"
static PIO pio = pio0;
static uint sm;
static uint8_t pio_irq;
static uint offset;
static bool klavesa = false;
char pismeno = '\0';
static char klavesy[4][4] = {
'1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'*', '0', '#', 'D'
};
// obsluha přerušení vyvolaná při stisku klávesy
static void pio_irq_obsluzna_funkce( void )
{
while( !pio_sm_is_rx_fifo_empty( pio, sm ) ) {
if( pio_sm_get_rx_fifo_level(pio, sm) == 2 ) {
uint32_t x,y;
x = pio_sm_get( pio, sm );
y = pio_sm_get( pio, sm );
int i, j;
for( i=0; i<4; i++) {
if( x >> i == 1) break;
}
for( j=0; j<4; j++) {
if( y >> j == 1 ) break;
}
pismeno = klavesy[j][i];
klavesa = true;
}
}
irq_clear(pio_irq);
}
int main( void )
{
stdio_init_all();
sleep_ms(2000);
gpio_init(25);
gpio_set_dir(25,true);
gpio_put(25,1);
printf("Test klávesnice 4x4.\n");
printf("Stiskněte klávesu na počítači.\n");
getchar();
gpio_put(25,0);
queue_init( &fifo, sizeof(uint32_t), FIFO_SIZE);
offset = pio_add_program(pio, &keyboard_program);
sm = pio_claim_unused_sm(pio, true);
keyboard_program_init(pio, sm, offset, 9, 13);
// najdeme volné přerušení
pio_irq = pio_get_irq_num(pio, 0);
if( irq_get_exclusive_handler( pio_irq ) ) {
pio_irq++;
if( irq_get_exclusive_handler( pio_irq ) ) {
panic("Nenalezen volný interrupt.");
}
}
printf("pio_irq=%d\n",pio_irq);
// nastavíme přerušení
irq_add_shared_handler( pio_irq, pio_irq_obsluzna_funkce, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY ); // přidáme sdílenou obsluhu
irq_set_enabled( pio_irq, true ); // spustíme
const uint irq_index = pio_irq - pio_get_irq_num( pio, 0 ); // obdržíme číslo přerušení
pio_set_irqn_source_enabled( pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source( sm ), true); // nastavíme pio, aby nám řekl, když je něco v RX frontě
printf("irq_index=%d\n",irq_index);
while(1) {
gpio_put(25,1);
sleep_ms(100);
gpio_put(25,0);
sleep_ms(100);
if( klavesa == true ) {
printf("Stisknuta klávesa '%c'\n",pismeno);
klavesa = false;
}
}
}
; klavesnice
; (c) Jirka Chráska 2025; <jirka@lixis.cz>
.program keyboard
;
.define KEYBOARD_IRQ 0
.wrap_target
nastav_radek_1:
set pins, 1 [31] ; nastavím 1. řádek klávesnice na vysokou úroveň a čekám 31 tiků hodin
set X, 0x1 ; do registru X dám jedničku (to bude posléze souřadnice x)
in pins, 4 ; přečtu sloupcové piny
mov Y, isr ; přečtenou hodnotu pinů si uložím do registru Y (to bude posléze souřadnice y)
jmp !Y, nastav_radek_2 ; když je Y nulové (nic není v tomto řádku stisknuto) poklačuji dalším řádkem
jmp rx_fifo ; v Y mám souřadnici stisknuté klávesy, skáču na odeslání dat
nastav_radek_2:
set pins, 2 [31] ; nastavím 2. řádek klávesnice na vysokou úroveň a čekám 31 tiků hodin
set X, 0x2 ; do registru X dám dvojku (to bude posléze souřadnice x)
in pins, 4 ; přečtu sloupcové piny
mov Y, isr ; přečtenou hodnotu pinů si uložím do registru Y (to bude posléze souřadnice y)
jmp !Y, nastav_radek_3 ; když je Y nulové (nic není v tomto řádku stisknuto) poklačuji dalším řádkem
jmp rx_fifo ; v Y mám souřadnici stisknuté klávesy, skáču na odeslání dat
nastav_radek_3:
set pins, 4 [31] ; nastavím 3. řádek klávesnice na vysokou úroveň a čekám 31 tiků hodin
set X, 0x4 ; do registru X dám čtyřku (to bude posléze souřadnice x)
in pins, 4 ; přečtu sloupcové piny
mov Y, isr ; přečtenou hodnotu pinů si uložím do registru Y (to bude posléze souřadnice y)
jmp !Y, nastav_radek_4 ; když je Y nulové (nic není v tomto řádku stisknuto) poklačuji dalším řádkem
jmp rx_fifo ; v Y mám souřadnici stisknuté klávesy, skáču na odeslání dat
nastav_radek_4:
set pins, 8 [31] ; nastavím 4. řádek klávesnice na vysokou úroveň a čekám 31 tiků hodin
set X, 0x8 ; do registru X dám osmičku (to bude posléze souřadnice x)
in pins, 4 ; přečtu sloupcové piny
mov Y, isr ; přečtenou hodnotu pinů si uložím do registru Y (to bude posléze souřadnice y)
jmp !Y nastav_radek_1 ; nic není stisknuto, vracím se na 1. řádek
rx_fifo: ; poslání dat (souřadnic klávesy) a vyvolání IRQ
push ; pošlu souřadnici y (sloupec)
in X, 4 [2] ; řádek si vytáhnu z registru X
push ; pošlu souřadnici x (řádek)
irq KEYBOARD_IRQ rel
wait 0 pin 0 ; čekám, až budou klávesy uvolněny
wait 0 pin 1
wait 0 pin 2
wait 0 pin 3
.wrap
% c-sdk {
#include "hardware/clocks.h"
#include "hardware/gpio.h"
static inline void keyboard_program_init (PIO pio, uint sm, uint offset, uint row_pin, uint col_pin) {
// řádkové piny jsou nastaveny jako výstupní
pio_gpio_init(pio, row_pin);
pio_gpio_init(pio, row_pin+1);
pio_gpio_init(pio, row_pin+2);
pio_gpio_init(pio, row_pin+3);
pio_sm_set_consecutive_pindirs(pio, sm, row_pin, 4, true);
// sloupcové piny (vstupní)
pio_sm_set_consecutive_pindirs(pio, sm, col_pin, 4, false);
// Konfigurace stavového stroje
pio_sm_config c = keyboard_program_get_default_config (offset);
// konfigurace vstupního posuvného registru (Input Shift Register)
sm_config_set_in_shift (&c,
false, // posunujeme doprava
false, // autopush je vypnut
32); //
// piny pro funkci IN
sm_config_set_in_pins( &c, col_pin );
// piny pro funkci SET
sm_config_set_set_pins( &c, row_pin, 4 );
// Tik hodin stavového stroje nastavíme na 4 kHz
float div = clock_get_hz (clk_sys) / 4000;
sm_config_set_clkdiv (&c, div);
// Konfiguraci šoupneme do stavového stroje
pio_sm_init (pio, sm, offset, &c);
// Stavový stroj spustíme
pio_sm_set_enabled (pio, sm, true);
}
%}
cmake_minimum_required(VERSION 3.13)
set(PICO_BOARD pico)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(keyboard C CXX ASM)
pico_sdk_init()
add_executable (keyboard keyboard.c)
pico_generate_pio_header(keyboard ${CMAKE_CURRENT_LIST_DIR}/keyboard.pio)
target_link_libraries(keyboard LINK_PUBLIC
pico_stdlib
hardware_pio
)
pico_add_extra_outputs(keyboard)
pico_enable_stdio_usb(keyboard 1)
pico_enable_stdio_uart(keyboard 0)
Test klávesnice 4x4.
Stiskněte klávesu na počítači.
pio_irq=7
irq_index=0
Stisknuta klávesa 'A'
Stisknuta klávesa '6'
Stisknuta klávesa '*'
Stisknuta klávesa '0'
Stisknuta klávesa '#'
Stisknuta klávesa 'D'
Stisknuta klávesa '5'
Stisknuta klávesa '1'
Stisknuta klávesa '3'
Stisknuta klávesa '3'
Stisknuta klávesa '3'
Stisknuta klávesa '3'
Stisknuta klávesa 'B'
Stisknuta klávesa 'B'
Stisknuta klávesa '7'
Stisknuta klávesa '7'
Stisknuta klávesa '4'
Stisknuta klávesa '4'
Stisknuta klávesa '9'
Stisknuta klávesa '9'
Stisknuta klávesa '*'
Stisknuta klávesa '0'
Stisknuta klávesa '4'
Stisknuta klávesa '8'
Stisknuta klávesa '5'
Stisknuta klávesa '9'
Stisknuta klávesa '6'
Stisknuta klávesa 'C'
Stisknuta klávesa 'B'
Stisknuta klávesa '7'
Stisknuta klávesa '*'
Stisknuta klávesa '*'
Ten samý program na odchytávání klávesnice pomocí PIO v MicroPythonu
V Pythonu je program trochu stručnější. Dělá to samé, co program v Céčku.
# ovladač klávesnice 4x4 tlačítka
# (c) Jirka Chráska 2025, jirka@lixis.cz
from machine import Pin
import rp2
@rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW,)*4)
def keypad():
wrap_target()
label("set_row_1")
set(pins, 1) [31] # nastavíme row_1 na 1 a čekáme na stisk
set(x,0x1)
in_(pins,4)
mov(y, isr)
jmp(not_y,"set_row_2")
jmp("rx_fifo")
label("set_row_2")
set(pins, 2) [31]
set(x,0x2)
in_(pins,4)
mov(y, isr)
jmp(not_y,"set_row_3")
jmp("rx_fifo")
label("set_row_3")
set(pins, 4) [31]
set(x,0x4)
in_(pins,4)
mov(y, isr)
jmp(not_y,"set_row_4")
jmp("rx_fifo")
label("set_row_4")
set(pins, 8) [31]
set(x,0x8)
in_(pins,4)
mov(y, isr)
jmp(not_y,"set_row_1")
label("rx_fifo")
push() # do fronty dáme souřadnici y(sloupec)
in_(x,4)[2]
push() # a potom do fronty dáme souřadnici x(řádek )
irq(rel(0))
wait(0,pin,0) # počkáme, až bude klávesa uvolněna
wait(0,pin,1)
wait(0,pin,2)
wait(0,pin,3)
wrap() # celkem 31 instrukcí
keys=[["1","2","3","A"],
["4","5","6","B"],
["7","8","9","C"],
["*","0","#","D"]]
def keypad_irq(sm):
y=sm.get()
x=sm.get()
for i in range(4):
if x >> i == 1:
break;
for j in range(4):
if y >> j == 1:
break;
print(keys[i][j])
smkeypad=rp2.StateMachine(0, keypad, freq=2000, set_base=Pin(9), in_base=Pin(13))
smkeypad.irq(keypad_irq)
smkeypad.active(1)