Zkonstruujeme blikající maják na sanitku. Tlačítkem budeme ovládat zapnutí a vypnutí majáku, případně změnu způsobu blikání.

Schéma zapojení

Schéma zapojení v programu KiCAD

majak schema

Funkce použité v programu

void gpio_set_function( uint pin, GPIO_FUNC_SIO ) (1)
static void gpio_set_dir( uint pin, bool out) (2)
static void gpio_pull_up( uint pin ) (3)
void gpio_init_mask( uint32_t maska )   (4)
static void gpio_set_dir_out_masked( uint32_t maska ) (5)
static void gpio_set_mask( uint32_t maska ) (6)
static void gpio_clr_mask( uint32_t maska ) (7)
void sleep_ms( uint milisekundy)  (8)
uint32_t gpio_get_events( uint gpio ) (9)
void gpio_clear_events( uint gpio, uint32_t events ) (10)
gpio_acknowledge_irq(uint gpio, uint32_t events) (11)
1 Nastavuje pin pro použití jako GPIO.
2 Nastavuje směr pinu na vstupní: out je false, nebo na výstupní; out je true.
3 Připojuje k vstupnímu pinu vnitřní pull-up rezistor.
4 Počáteční inicializace pinů, které jsou jedničkové v masce.
5 Nastavení směru pinů na výstupní, které jsou jedničkové v masce.
6 Rozsvícení pinů, které jsou jedničkové v masce.
7 Zhasnutí pinů, které jsou jedničkové v masce.
8 Pauza programu v milisekundách.
9 Vrací množinu událostí, které nastaly na pinu gpio. Události mohou být GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE | GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH.
10 Vymaže záznamy událostí na pinu gpio. Události mohou být GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE | GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH.
11 Potvrzuje přerušení GPIO na pinu gpio pro zadané události events na volajícím jádru procesoru.

Jak se tyto funkce používají si můžete přečíst v dokumentaci k Pico SDK.

Program

Program je udělán tak, že periodicky čte události na GPIO 22 (tam je připojeno tlačítko) a reaguje na ně — funkce chytni_udalost(). Nepoužívá přerušení. Pin 22 je pomocí interního pull-up rezistoru na vysoké úrovni a stisknutím tlačítka se přizemní. Tím při každém stisknutí tlačítka Pico vygeneruje pro pin 22 událost GPIO_IRQ_EDGE_FALL (pin spadnul na nulu). Pokud funkce chytni_událost() zaznamená událost GPIO_IRQ_EDGE_FALL, tak ji vynuluje a změní stav programu (globální proměná enum STAV tlacitko). Stavy se mění cyklicky z vypnutozapnutoefekt1efekt2efekt3vypnuto. Stavům odpovídají funkce vypnuto_func(), zapnuto_func(), efekt1_func(), efekt2_func() a efekt3_func(), které dělají blikání. Pro každý efekt bliká maják trochu jinak.

majak2.c
/* Maják na sanitku verze 2 s ovládacím tlačítkem
* (c) Jirka Chráska 2025; <jirka@lixis.cz>
* licence BSD 3 clause
*/

#include "pico/stdlib.h"
#include "hardware/structs/iobank0.h"

// GPIO0 až GPIO11 budou LED majáku
// GPIO22 bude pro ovládací tlačítko
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;

// počáteční nastavení LED majáku
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í
	sleep_ms(1000);
	gpio_clr_mask( piny_majak ); // zhasnu maják
}


uint32_t gpio_get_events(uint gpio)
{
	int32_t mask = 0xF << 4 * (gpio % 8);
	return (iobank0_hw->intr[gpio / 8] & mask) >> 4 * ( gpio % 8);
}

void gpio_clear_events(uint gpio, uint32_t events)
{
	gpio_acknowledge_irq(gpio, events);
}

// nastavení tlačítka na GPIO22
void tlacitko_init()
{
	gpio_set_function(22, GPIO_FUNC_SIO);
	gpio_set_dir(22,false);
	gpio_pull_up(22);
	gpio_clear_events(22, GPIO_IRQ_EDGE_FALL );
}

// definice stavu majáku
typedef enum st { vypnuto, zapnuto, efekt1, efekt2, efekt3 } STAV;

STAV tlacitko = vypnuto;
int sleep_time = 100; // čas v milisekundách, určující rychlost blikání

// odchytávání a zpracování událostí na GPIO22
void chytni_udalost()
{
int32_t event = gpio_get_events( 22 );
	sleep_ms(10);
	gpio_clear_events(22, GPIO_IRQ_EDGE_FALL);
	if( event & GPIO_IRQ_EDGE_FALL ) {
		switch( tlacitko ) {
			case vypnuto: tlacitko = zapnuto; break;
			case zapnuto: tlacitko = efekt1; break;
			case efekt1:  tlacitko = efekt2; break;
			case efekt2:  tlacitko = efekt3; break;
			case efekt3:  tlacitko = vypnuto; break;
			default:      tlacitko = zapnuto; break;
		}
	}
}

// rozsvícení všech LED majáku
void zapnuto_func()
{
	gpio_set_mask( piny_majak );
	sleep_ms(sleep_time*20);
}

// vypnutí všech LED majáku
void vypnuto_func()
{
	gpio_clr_mask( piny_majak );
	sleep_ms(sleep_time*20);
}

// maják jezdí zleva doprava a zprava doleva
void efekt1_func()
{
int i;
// masky pro jednotlivé stavy majáku pro efekt1
uint32_t masky[10] = {0x7, 0xe, 0x1c, 0x38, 0x70, 0xe0, 0x1c0, 0x380, 0x700, 0xe00};
	gpio_clr_mask( piny_majak );

	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] );
	}
}

// maják periodicky bliká všemi LED
void efekt2_func()
{
	gpio_clr_mask( piny_majak );
	sleep_ms( sleep_time );
	gpio_set_mask( piny_majak );
	sleep_ms( sleep_time );
}

// v blikání se střídají sudé a liché LED
void efekt3_func()
{
uint32_t masky[2] = {0b101010101010, 0b010101010101};
	gpio_clr_mask( piny_majak );
	gpio_set_mask( masky[0] );
	sleep_ms(sleep_time*2 );
	gpio_clr_mask( masky[0] );
	gpio_set_mask( masky[1] );
	sleep_ms( sleep_time*2 );
	gpio_clr_mask( masky[1] );
	sleep_ms( sleep_time*2 );
	gpio_set_mask( masky[0] );
	sleep_ms(sleep_time*2 );
	gpio_clr_mask( masky[0] );
	gpio_set_mask( masky[1] );
	sleep_ms( sleep_time*2 );
	gpio_clr_mask( masky[1] );
}

int main( void )
{
	majak_init();
	tlacitko_init();
	tlacitko = vypnuto;
	while(1) {
		switch( tlacitko ) {
			case vypnuto:	vypnuto_func();  break;
			case zapnuto:	zapnuto_func();  break;
			case efekt1:	efekt1_func();	 break;
			case efekt2:	efekt2_func();	 break;
			case efekt3:	efekt3_func();	 break;
			default:		vypnuto_func();  break;
		}
		chytni_udalost();
	}
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
# toto je lepší, nemusíme pico_sdk_import.cmake kopírovat
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
#include(pico_sdk_import.cmake)

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

pico_sdk_init()
add_executable(majak2
    majak2.c
)
target_link_libraries(majak2 pico_stdlib)
pico_add_extra_outputs(majak2)
Sestavení programu
$ cd majak2
$ mkdir build
$ cd build
$ cmake ..
$ make -j8

Konstrukce

Fungující prototyp majáku na sanitku s ovládáním