Zkonstruujeme blikající maják na sanitku.

Schéma zapojení

Schéma zapojení v programu KiCAD

majak schema

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

IMG 20250220 023555

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

IMG 20260222 221738

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)

tkult1

tkult2

Nikola Smělá