Zkonstruujeme blikající maják na sanitku.
Schéma zapojení
Schéma zapojení v programu KiCAD

Funkce použité v programu
void gpio_init_mask( uint32_t maska ) (1)
static void gpio_set_dir_out_masked( uint32_t maska ) (2)
gpio_set_mask( uint32_t maska ) (3)
gpio_clr_mask( uint32_t maska ) (4)
sleep_ms(uint milisekundy) (5)
| 1 | Počáteční inicializace pinů, které jsou jedničkové v masce. |
| 2 | Nastavení směru pinů na výstupní, které jsou jedničkové v masce. |
| 3 | Rozsvícení pinů, které jsou jedničkové v masce. |
| 4 | Zhasnutí pinů, které jsou jedničkové v masce. |
| 5 | Pauza programu v milisekundách. |
Jak se tyto funkce používají si můžete přečíst zde: Práce s několika GPIO linkami současně
Program
/* Maják na sanitku
* (c) Jirka Chráska 2025; <jirka@lixis.cz>
* licence BSD 3 clause
*/
#include "pico/stdlib.h"
// GPIO0 až GPIO11 budou LED majáku
uint32_t piny_majak = 1 | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5) | (1<<6) | (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11);
// to samé mohu udělat pomocí: uint32_t piny_majak = 0xfff;
// anebo to samé mohu udělat pomocí: uint32_t piny_majak = 0b0000111111111111;
void majak_init()
{
gpio_init_mask( piny_majak ); // nastavení pinů 0 a 11
gpio_set_dir_out_masked( piny_majak ); // na výstupní
gpio_set_mask( piny_majak ); // testovací rozsvícení všech LED
}
// masky pro jednotlivé stavy majáku
uint32_t masky[10] = {0x7, 0xe, 0x1c, 0x38, 0x70, 0xe0, 0x1c0, 0x380, 0x700, 0xe00};
// nebo se to dá zapsat binárně takto
/* uint32_t masky[10] = { 0b000000000111,
0b000000001110,
0b000000011100,
0b000000111000,
0b000001110000,
0b000011100000,
0b000111000000,
0b001110000000,
0b011100000000,
0b111000000000 };
*/
int main( void )
{
int sleep_time = 50; // zpoždění mezi jednotlivými bliky
int i = 0;
unsigned int j = 1;
majak_init();
sleep_ms(1000);
gpio_clr_mask( piny_majak ); // zhasnu maják
while(1) {
for( i=0; i<10; i++ ) {
gpio_set_mask( masky[i] );
sleep_ms(sleep_time);
gpio_clr_mask( masky[i] );
}
for( i=9; i>=0; i-- ) {
gpio_set_mask( masky[i] );
sleep_ms(sleep_time);
gpio_clr_mask( masky[i] );
}
if( (j%5) == 4 ) {
gpio_clr_mask( piny_majak );
sleep_ms( sleep_time );
gpio_set_mask( piny_majak );
sleep_ms( sleep_time );
gpio_clr_mask( piny_majak );
j = 0;
sleep_ms( sleep_time/2 );
gpio_set_mask( piny_majak );
sleep_ms( sleep_time );
gpio_clr_mask( piny_majak );
}
j++;
}
}
cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(majak1 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
add_executable(majak1
majak1.c
)
target_link_libraries(majak1 pico_stdlib)
pico_add_extra_outputs(majak1)
Sestavení programu
$ cd majak1
$ mkdir build
$ cd build
$ cmake ..
$ make -j8
Konstrukce
Konstrukce roku 2025

Fungující prototyp majáku na sanitku
Konstrukce roku 2026

Konstrukce studentů
Artěm Holubnič
Jan Plíhal
Tomáš Kult
../majak_tkult/majak1.c
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/pwm.h"
#define I2C_PORT i2c0
#define ADRESA_DISPLEJE 0x3C
#define PIN_SDA 16
#define PIN_SCL 17
#define PIN_BZUCAK 15
uint32_t piny_majak = 0xfff;
// Definice písmen pro nápis POLICIE
const uint8_t char_P[] = {0x7F, 0x09, 0x09, 0x09, 0x06};
const uint8_t char_O[] = {0x3E, 0x41, 0x41, 0x41, 0x3E};
const uint8_t char_L[] = {0x7F, 0x40, 0x40, 0x40, 0x40};
const uint8_t char_I[] = {0x41, 0x7F, 0x41};
const uint8_t char_C[] = {0x3E, 0x41, 0x41, 0x41, 0x22};
const uint8_t char_E[] = {0x7F, 0x49, 0x49, 0x49, 0x41};
// Funkce pro zvuk sirény
void hraj_ton(uint frekvence) {
if (frekvence == 0) {
pwm_set_gpio_level(PIN_BZUCAK, 0);
return;
}
uint slice_num = pwm_gpio_to_slice_num(PIN_BZUCAK);
uint32_t clock = 125000000;
uint32_t divider = clock / (frekvence * 4096) + 1;
uint32_t top = clock / (divider * frekvence) - 1;
pwm_set_clkdiv(slice_num, divider);
pwm_set_wrap(slice_num, top);
pwm_set_gpio_level(PIN_BZUCAK, top / 2);
}
void oled_prikaz(uint8_t cmd) {
uint8_t buf[2] = {0x00, cmd};
i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, buf, 2, false);
}
void oled_vyluxovat() {
oled_prikaz(0x21); oled_prikaz(0); oled_prikaz(127);
oled_prikaz(0x22); oled_prikaz(0); oled_prikaz(7);
uint8_t clear[2] = {0x40, 0x00};
for(int i=0; i<1024; i++) i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, clear, 2, false);
}
void oled_znak_velky(const uint8_t* bitmap, int sirka, int x, int page) {
if (x < 0 || x > 120) return;
oled_prikaz(0x21); oled_prikaz(x); oled_prikaz(x + (sirka*2) - 1);
oled_prikaz(0x22); oled_prikaz(page); oled_prikaz(page);
for(int i=0; i<sirka; i++) {
uint8_t b = bitmap[i], ex = 0;
if(b&0x01) ex|=0x03; if(b&0x02) ex|=0x0C; if(b&0x04) ex|=0x30; if(b&0x08) ex|=0xC0;
uint8_t d[2] = {0x40, ex};
i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, d, 2, false);
i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, d, 2, false);
}
oled_prikaz(0x21); oled_prikaz(x); oled_prikaz(x + (sirka*2) - 1);
oled_prikaz(0x22); oled_prikaz(page+1); oled_prikaz(page+1);
for(int i=0; i<sirka; i++) {
uint8_t b = bitmap[i], ex = 0;
if(b&0x10) ex|=0x03; if(b&0x20) ex|=0x0C; if(b&0x40) ex|=0x30; if(b&0x80) ex|=0xC0;
uint8_t d[2] = {0x40, ex};
i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, d, 2, false);
i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, d, 2, false);
}
}
void zobraz_policie_scroll(int *x) {
oled_prikaz(0x21); oled_prikaz(0); oled_prikaz(127);
oled_prikaz(0x22); oled_prikaz(3); oled_prikaz(4);
uint8_t clear[2] = {0x40, 0x00};
for(int i=0; i<256; i++) i2c_write_blocking(I2C_PORT, ADRESA_DISPLEJE, clear, 2, false);
int p = 3;
int cur_x = *x;
oled_znak_velky(char_P, 5, cur_x, p); cur_x+=12;
oled_znak_velky(char_O, 5, cur_x, p); cur_x+=12;
oled_znak_velky(char_L, 5, cur_x, p); cur_x+=12;
oled_znak_velky(char_I, 3, cur_x, p); cur_x+=8;
oled_znak_velky(char_C, 5, cur_x, p); cur_x+=12;
oled_znak_velky(char_I, 3, cur_x, p); cur_x+=8;
oled_znak_velky(char_E, 5, cur_x, p);
*x -= 4; // Rychlost textu
if (*x < -100) *x = 127;
}
int main() {
i2c_init(I2C_PORT, 400 * 1000);
gpio_set_function(PIN_SDA, GPIO_FUNC_I2C);
gpio_set_function(PIN_SCL, GPIO_FUNC_I2C);
gpio_pull_up(PIN_SDA); gpio_pull_up(PIN_SCL);
gpio_set_function(PIN_BZUCAK, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(PIN_BZUCAK);
pwm_set_enabled(slice_num, true);
sleep_ms(100);
oled_prikaz(0xAE); oled_prikaz(0x8D); oled_prikaz(0x14);
oled_prikaz(0x81); oled_prikaz(0x40);
oled_prikaz(0x20); oled_prikaz(0x00);
oled_prikaz(0xAF);
oled_vyluxovat();
gpio_init_mask(piny_majak);
gpio_set_dir_out_masked(piny_majak);
uint32_t masky[10] = {0x7, 0xe, 0x1c, 0x38, 0x70, 0xe0, 0x1c0, 0x380, 0x700, 0xe00};
int scroll_x = 127;
int rezim_pocitadlo = 0;
while(1) {
// --- REŽIM 1: KLASICKÉ KROUŽENÍ (5x dokola) ---
for (int r = 0; r < 5; r++) {
hraj_ton(600);
for(int i=0; i<10; i++) {
zobraz_policie_scroll(&scroll_x);
gpio_set_mask(masky[i]);
sleep_ms(50);
gpio_clr_mask(masky[i]);
}
hraj_ton(450);
for(int i=9; i>=0; i--) {
zobraz_policie_scroll(&scroll_x);
gpio_set_mask(masky[i]);
sleep_ms(50);
gpio_clr_mask(masky[i]);
}
}
// --- REŽIM 2: AMERICKÝ STYL (LEVA / PRAVA) ---
for (int r = 0; r < 10; r++) {
// Levá strana blikne 3x
hraj_ton(800);
for(int f=0; f<3; f++) {
zobraz_policie_scroll(&scroll_x);
gpio_set_mask(0x03F); // Prvních 6 LED
sleep_ms(30);
gpio_clr_mask(0x03F);
sleep_ms(30);
}
// Pravá strana blikne 3x
hraj_ton(500);
for(int f=0; f<3; f++) {
zobraz_policie_scroll(&scroll_x);
gpio_set_mask(0xFC0); // Druhých 6 LED
sleep_ms(30);
gpio_clr_mask(0xFC0);
sleep_ms(30);
}
}
}
}
../majak_tkult/CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(majak1 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
add_executable(majak1
majak1.c
)
# Tady je ta změna - přidali jsme hardware_i2c
target_link_libraries(majak1
pico_stdlib
hardware_i2c
hardware_pwm
)
pico_add_extra_outputs(majak1)

