12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- #include <stdio.h>
- #include "pico/stdlib.h"
- #include "hardware/pwm.h"
- #include "hardware/clocks.h"
- #include <math.h>
- #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();
- }
- }
|