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

Měření osciloskopem

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
Hlavičkový soubor dipleje
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.
