Druhá verze generátoru obdélníkových pulsů je řízena pomocí událostí.

Zapojení

IMG 20250401 185450

Měření osciloskopem

IMG 20250401 185048

Zdrojové soubory

CMakeLists.txt
cmake_minimum_required(VERSION 3.12)

include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(generator2)

pico_sdk_init()

add_executable(generator2
    generator2.c
    lcd_czech_chars.c
)

target_link_libraries(generator2
    pico_stdlib
    hardware_pwm
    hardware_i2c
)

pico_enable_stdio_usb(generator2 1)
pico_enable_stdio_uart(generator2 0)

pico_add_extra_outputs(generator2)
generator2.c
/* generator2.c
 * Generator PWM pulsu s ovladanim RPi Pico verze 2.0
 * (c) Jirka Chráska 2025, <jirka@lixis.cz> All rights reserved.
 *
 * BSD licence
 */

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include "hardware/gpio.h"
#include "lcd_czech_chars.h"

const uint FREQ_PLUS  = 12; // pin pro tlačítko na přidání frekvence
const uint FREQ_MINUS = 13; // pin pro tlačítko na ubrání frekvence
const uint DUTY_PLUS  = 15; // pin pro tlačítko na přidání střídy
const uint DUTY_MINUS = 14; // pin pro tlačítko na ubrání střídy
const uint PWM_PIN    = 16; // výstup PWM

static int freq = 1000;
static int duty = 50;
static bool zmena = false;

#define JEDNOTKY 500
#define DESITKY  3000
#define STOVKY   6000
#define TISICE   12000

uint32_t pwm_set_freq_duty( uint slice_num, uint chan, uint32_t f, int d)
{
    uint32_t clock     = 125000000;
    uint32_t divider16 = clock / f / 4096 + (clock % (f * 4096) != 0);
    if( divider16 / 16 == 0) {
        divider16 = 16;
    }
    uint32_t wrap = clock * 16 / divider16 / f - 1;
    pwm_set_clkdiv_int_frac( slice_num, divider16/16, divider16 & 0xf );
    pwm_set_wrap( slice_num, wrap );
    pwm_set_chan_level( slice_num, chan, wrap * d/100 );
    return wrap;
}


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

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

int udelej_zmeny()
{
char buffer[40];
    // zmena pwm
    uint slice   = pwm_gpio_to_slice_num (PWM_PIN);
    uint channel = pwm_gpio_to_channel (PWM_PIN);
    pwm_set_freq_duty(slice, channel, freq, duty);
    pwm_set_enabled (slice, true);
    // zobraz na displeji
    snprintf(buffer,40,"Freq: %6d Hz", freq);
    printf("%s ", buffer);
    lcd_home();
    lcd_set_cursor(0,0);
    cz_print(buffer);
    snprintf(buffer,40,"Duty:    %3d %%", duty);
    lcd_set_cursor(1,0);
    cz_print(buffer);
    printf("%s \n", buffer);
    zmena = false;
}

// odchytávání a zpracování událostí tlačítek
void chytni_udalost()
{
uint64_t t1;
uint64_t t2;
uint64_t t;
int32_t event_fp = gpio_get_events( FREQ_PLUS );
int32_t event_fm = gpio_get_events( FREQ_MINUS );
int32_t event_dp = gpio_get_events( DUTY_PLUS );
int32_t event_dm = gpio_get_events( DUTY_MINUS );
	sleep_ms(1);
	if( event_fp & GPIO_IRQ_EDGE_FALL ) { // změna frekvence nahoru
        t1 = time_us_64();
        gpio_clear_events(FREQ_PLUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
        while( !(gpio_get_events(FREQ_PLUS) & GPIO_IRQ_EDGE_RISE)) {
            t2 = (uint64_t) time_us_64();
            t = (t2 - t1)/1000;
            if( t > JEDNOTKY && t <= DESITKY ) {
                freq++;
            }
            if( t > DESITKY && t <= STOVKY ) {
                freq += 10;
            }
            if( t > STOVKY && t <= TISICE ) {
                freq += 100;
            }
            if( t > TISICE ) {
                freq += 1000;
            }
            zmena = true;
            udelej_zmeny();
        }
        if( t<= JEDNOTKY ) {
            freq++;
        }
        zmena = true;
	}
	if( event_fm & GPIO_IRQ_EDGE_FALL ) { //změna frekvence dolů
		t1 = time_us_64();
        gpio_clear_events(FREQ_MINUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
        while( !(gpio_get_events(FREQ_MINUS) & GPIO_IRQ_EDGE_RISE)) {
            t2 = (uint64_t) time_us_64();
            t = (t2 - t1)/1000;
            if( t > JEDNOTKY && t <= DESITKY ) {
                freq--;
            }
            if( t > DESITKY && t <= STOVKY ) {
                freq -= 10;
            }
            if( t > STOVKY && t <= TISICE) {
                freq -= 100;
            }
            if( t > TISICE ) {
                freq -= 1000;
            }
            if( freq <= 0 ) {
                freq = 0;
            }
            zmena = true;
            udelej_zmeny();
        }
        if( t<= JEDNOTKY ) {
            freq--;
        }
        if( freq < 0) {
            freq = 0;
        }
        zmena = true;

	}
	if( event_dp & GPIO_IRQ_EDGE_FALL ) { // změna střídy nahoru
        t1 = time_us_64();
        gpio_clear_events(DUTY_PLUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
        while( !(gpio_get_events(DUTY_PLUS) & GPIO_IRQ_EDGE_RISE)) {
            t2 = (uint64_t) time_us_64();
            t = (t2 - t1)/1000;
            if( t > JEDNOTKY ) {
                duty++;
                if( duty > 99) {
                    duty = 99;
                }
                zmena = true;
                udelej_zmeny();
            }
        }
        if( t<= JEDNOTKY ) {
            duty++;
        }
        if( duty > 99) {
            duty = 99;
        }
        zmena = true;
	}
	if( event_dm & GPIO_IRQ_EDGE_FALL ) { // změna střídy dolů
		t1 = time_us_64();
        gpio_clear_events(DUTY_MINUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
        while( !(gpio_get_events(DUTY_MINUS) & GPIO_IRQ_EDGE_RISE)) {
            t2 = (uint64_t) time_us_64();
            t = (t2 - t1)/1000;
            if( t > JEDNOTKY ) {
                duty--;
                if( duty < 1) {
                    duty = 1;
                }
                zmena = true;
                udelej_zmeny();
            }
        }
        if( t<= JEDNOTKY ) {
            duty--;
        }
        if( duty < 1) {
            duty = 1;
        }
        zmena = true;
	}
    gpio_clear_events(FREQ_MINUS, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
    gpio_clear_events(FREQ_PLUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
    gpio_clear_events(DUTY_PLUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
    gpio_clear_events(DUTY_MINUS, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
}

int main(void)
{
    // konfigurace debugování přes USB
    stdio_init_all();
    sleep_ms(1000);
    // konfigurace displeje
    init_gpio();
    lcd_characters_init();
    lcd_init();
    lcd_clear();

    // nastavení  PWM výstupu
    gpio_set_function(PWM_PIN, GPIO_FUNC_PWM);
    zmena = true;
    udelej_zmeny();

    // nastavení pinu frekvence přidat
    gpio_set_function( FREQ_PLUS, GPIO_FUNC_SIO );
    gpio_set_dir( FREQ_PLUS, false );
    gpio_pull_up( FREQ_PLUS );
	gpio_clear_events(FREQ_PLUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
    // nastavení pinu frekvence ubrat
    gpio_set_function( FREQ_MINUS, GPIO_FUNC_SIO );
    gpio_set_dir( FREQ_MINUS, false );
    gpio_pull_up( FREQ_MINUS );
    gpio_clear_events(FREQ_MINUS, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
    // nastavení pinu střída přidat
    gpio_set_function( DUTY_PLUS, GPIO_FUNC_SIO );
    gpio_set_dir( DUTY_PLUS, false );
    gpio_pull_up( DUTY_PLUS );
    gpio_clear_events(DUTY_PLUS,  GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);
    // nastavení pinu střída ubrat
    gpio_set_function( DUTY_MINUS, GPIO_FUNC_SIO );
    gpio_set_dir( DUTY_MINUS, false );
    gpio_pull_up( DUTY_MINUS );
    gpio_clear_events(DUTY_MINUS, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL);

    // nekonečná smyčka
    while(1){
        if( zmena ) {
            udelej_zmeny();
        }
        chytni_udalost();
        sleep_ms(50);
    }
}
Implementace displeje

lcd_czech_chars.c

Hlavičkový soubor dipleje

lcd_czech_chars.h

Problémy vyřešeny

Řízení pomocí tlačítek s událostmi je dobré, při delším stisknutí tlačítka se rychlost změn zvyšuje.