|
@@ -5,29 +5,42 @@
|
|
#include <math.h>
|
|
#include <math.h>
|
|
|
|
|
|
#define LED_PIN PICO_DEFAULT_LED_PIN // LED
|
|
#define LED_PIN PICO_DEFAULT_LED_PIN // LED
|
|
-#define PWM_SUB_PIN 2 // サブ用
|
|
|
|
|
|
+#define PWM_SUB_PIN 2 // サブ用 (GPIO2)
|
|
|
|
|
|
-#define PWM_FREQ 1000
|
|
|
|
-#define PWM_DIVIDER 100.0f
|
|
|
|
|
|
+// PWM信号のクロック分周比
|
|
|
|
+#define PWM_CLOCK_DIVIDER 100.0f
|
|
|
|
+// LEDの明るさを更新する周波数 (Hz)
|
|
|
|
+// この周波数でPWM割り込みが発生する
|
|
|
|
+#define EFFECT_UPDATE_FREQ_HZ 1000
|
|
|
|
+// サイン波ルックアップテーブルのサイズ
|
|
|
|
+#define SINE_LUT_SIZE 256
|
|
|
|
|
|
-#define PI 3.14159265358979323846
|
|
|
|
-
|
|
|
|
-uint slice_num = 0;
|
|
|
|
-uint sub_slice = 0;
|
|
|
|
-uint16_t wrap = 0;
|
|
|
|
|
|
+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)
|
|
void pwm_irq_handler(void)
|
|
{
|
|
{
|
|
- static uint counter = 0;
|
|
|
|
-
|
|
|
|
|
|
+ // 割り込みフラグをクリア
|
|
pwm_clear_irq(slice_num);
|
|
pwm_clear_irq(slice_num);
|
|
- if(counter++ >= PWM_FREQ) {
|
|
|
|
- counter = 0;
|
|
|
|
|
|
+
|
|
|
|
+ // 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;
|
|
}
|
|
}
|
|
- double amp = fabs(sin(PI * ((double)counter/(double)PWM_FREQ)));
|
|
|
|
- uint16_t cc = (uint16_t)((double)wrap * amp);
|
|
|
|
- pwm_set_gpio_level(LED_PIN, cc);
|
|
|
|
- pwm_set_gpio_level(PWM_SUB_PIN, cc);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
int main()
|
|
int main()
|
|
@@ -38,10 +51,20 @@ int main()
|
|
gpio_set_function(PWM_SUB_PIN,GPIO_FUNC_PWM );
|
|
gpio_set_function(PWM_SUB_PIN,GPIO_FUNC_PWM );
|
|
|
|
|
|
pwm_config c = pwm_get_default_config();
|
|
pwm_config c = pwm_get_default_config();
|
|
- pwm_config_set_clkdiv(&c, PWM_DIVIDER);
|
|
|
|
- wrap = (clock_get_hz(clk_sys) / PWM_DIVIDER) / PWM_FREQ;
|
|
|
|
|
|
+ // クロック分周を設定
|
|
|
|
+ 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);
|
|
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のスライスを設定
|
|
// LEDのスライスを設定
|
|
slice_num = pwm_gpio_to_slice_num(LED_PIN);
|
|
slice_num = pwm_gpio_to_slice_num(LED_PIN);
|
|
pwm_init(slice_num, &c, false);
|
|
pwm_init(slice_num, &c, false);
|
|
@@ -49,16 +72,19 @@ int main()
|
|
sub_slice = pwm_gpio_to_slice_num(PWM_SUB_PIN);
|
|
sub_slice = pwm_gpio_to_slice_num(PWM_SUB_PIN);
|
|
pwm_init(sub_slice, &c, false);
|
|
pwm_init(sub_slice, &c, false);
|
|
|
|
|
|
- // 念のためにIRQをクリアしておく
|
|
|
|
|
|
+ // 割り込み設定
|
|
|
|
+ // 割り込みハンドラは片方のスライス(slice_num)にのみ設定すれば、
|
|
|
|
+ // 両方のGPIOを同時に制御できる
|
|
pwm_clear_irq(slice_num);
|
|
pwm_clear_irq(slice_num);
|
|
- //
|
|
|
|
pwm_set_irq_enabled(slice_num, true);
|
|
pwm_set_irq_enabled(slice_num, true);
|
|
- irq_set_exclusive_handler(PWM_DEFAULT_IRQ_NUM(), pwm_irq_handler);
|
|
|
|
- irq_set_enabled(PWM_DEFAULT_IRQ_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(LED_PIN, wrap/2);
|
|
pwm_set_gpio_level(PWM_SUB_PIN, wrap/2);
|
|
pwm_set_gpio_level(PWM_SUB_PIN, wrap/2);
|
|
|
|
|
|
|
|
+ // 両方のPWMスライスを同時に有効化
|
|
pwm_set_enabled(slice_num, true);
|
|
pwm_set_enabled(slice_num, true);
|
|
pwm_set_enabled(sub_slice, true);
|
|
pwm_set_enabled(sub_slice, true);
|
|
|
|
|