#include #include "pico/stdlib.h" #include "hardware/pwm.h" #include "hardware/clocks.h" #include #define LED_PIN PICO_DEFAULT_LED_PIN // LED #define PWM_SUB_PIN 2 // サブ用 (GPIO2) // PWM信号のクロック分周比 #define PWM_CLOCK_DIVIDER 100.0f // LEDの明るさを更新する周波数 (Hz) // この周波数でPWM割り込みが発生する #define EFFECT_UPDATE_FREQ_HZ 1000 // サイン波ルックアップテーブルのサイズ #define SINE_LUT_SIZE 256 static uint slice_num = 0; static uint sub_slice = 0; static uint16_t wrap = 0; // サイン波の値を格納するルックアップテーブル static uint16_t sine_lut[SINE_LUT_SIZE]; void pwm_irq_handler(void) { // 割り込みフラグをクリア pwm_clear_irq(slice_num); // 0.5Hzの呼吸エフェクトを実現するためのカウンタ // (EFFECT_UPDATE_FREQ_HZ回で1周期 = 1秒) static uint effect_counter = 0; // カウンタをルックアップテーブルのインデックスにマッピング uint lut_index = (effect_counter * SINE_LUT_SIZE) / EFFECT_UPDATE_FREQ_HZ; uint16_t level = sine_lut[lut_index]; // 計算済みの値をPWMデューティ比として設定 pwm_set_gpio_level(LED_PIN, level); pwm_set_gpio_level(PWM_SUB_PIN, level); if(++effect_counter >= EFFECT_UPDATE_FREQ_HZ) { effect_counter = 0; } } int main() { stdio_init_all(); gpio_set_function(LED_PIN,GPIO_FUNC_PWM ); gpio_set_function(PWM_SUB_PIN,GPIO_FUNC_PWM ); pwm_config c = pwm_get_default_config(); // クロック分周を設定 pwm_config_set_clkdiv(&c, PWM_CLOCK_DIVIDER); // PWMのWRAP値(カウンタの最大値)を計算・設定 // これにより、PWM割り込みが EFFECT_UPDATE_FREQ_HZ で発生するようになる wrap = (uint16_t)((clock_get_hz(clk_sys) / PWM_CLOCK_DIVIDER) / EFFECT_UPDATE_FREQ_HZ); pwm_config_set_wrap(&c, wrap); // プログラム開始時にサイン波のルックアップテーブルを生成 for (int i = 0; i < SINE_LUT_SIZE; ++i) { // 0からPIまでの半周期のサイン波を計算 double sin_val = sin((double)i * M_PI / (double)SINE_LUT_SIZE); // 計算結果をPWMのデューティ比にスケーリングしてテーブルに格納 sine_lut[i] = (uint16_t)((double)wrap * sin_val); } // LEDのスライスを設定 slice_num = pwm_gpio_to_slice_num(LED_PIN); pwm_init(slice_num, &c, false); // サブのスライスを設定 sub_slice = pwm_gpio_to_slice_num(PWM_SUB_PIN); pwm_init(sub_slice, &c, false); // 割り込み設定 // 割り込みハンドラは片方のスライス(slice_num)にのみ設定すれば、 // 両方のGPIOを同時に制御できる pwm_clear_irq(slice_num); pwm_set_irq_enabled(slice_num, true); irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_irq_handler); irq_set_enabled(PWM_IRQ_WRAP, true); // 初期輝度を50%に設定 pwm_set_gpio_level(LED_PIN, wrap/2); pwm_set_gpio_level(PWM_SUB_PIN, wrap/2); // 両方のPWMスライスを同時に有効化 pwm_set_enabled(slice_num, true); pwm_set_enabled(sub_slice, true); while (true) { tight_loop_contents(); } }