pwm_sample.c 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #include <stdio.h>
  2. #include "pico/stdlib.h"
  3. #include "hardware/pwm.h"
  4. #include "hardware/clocks.h"
  5. #include <math.h>
  6. #define LED_PIN PICO_DEFAULT_LED_PIN // LED
  7. #define PWM_SUB_PIN 2 // サブ用 (GPIO2)
  8. // PWM信号のクロック分周比
  9. #define PWM_CLOCK_DIVIDER 100.0f
  10. // LEDの明るさを更新する周波数 (Hz)
  11. // この周波数でPWM割り込みが発生する
  12. #define EFFECT_UPDATE_FREQ_HZ 1000
  13. // サイン波ルックアップテーブルのサイズ
  14. #define SINE_LUT_SIZE 256
  15. static uint slice_num = 0;
  16. static uint sub_slice = 0;
  17. static uint16_t wrap = 0;
  18. // サイン波の値を格納するルックアップテーブル
  19. static uint16_t sine_lut[SINE_LUT_SIZE];
  20. void pwm_irq_handler(void)
  21. {
  22. // 割り込みフラグをクリア
  23. pwm_clear_irq(slice_num);
  24. // 0.5Hzの呼吸エフェクトを実現するためのカウンタ
  25. // (EFFECT_UPDATE_FREQ_HZ回で1周期 = 1秒)
  26. static uint effect_counter = 0;
  27. // カウンタをルックアップテーブルのインデックスにマッピング
  28. uint lut_index = (effect_counter * SINE_LUT_SIZE) / EFFECT_UPDATE_FREQ_HZ;
  29. uint16_t level = sine_lut[lut_index];
  30. // 計算済みの値をPWMデューティ比として設定
  31. pwm_set_gpio_level(LED_PIN, level);
  32. pwm_set_gpio_level(PWM_SUB_PIN, level);
  33. if(++effect_counter >= EFFECT_UPDATE_FREQ_HZ) {
  34. effect_counter = 0;
  35. }
  36. }
  37. int main()
  38. {
  39. stdio_init_all();
  40. gpio_set_function(LED_PIN,GPIO_FUNC_PWM );
  41. gpio_set_function(PWM_SUB_PIN,GPIO_FUNC_PWM );
  42. pwm_config c = pwm_get_default_config();
  43. // クロック分周を設定
  44. pwm_config_set_clkdiv(&c, PWM_CLOCK_DIVIDER);
  45. // PWMのWRAP値(カウンタの最大値)を計算・設定
  46. // これにより、PWM割り込みが EFFECT_UPDATE_FREQ_HZ で発生するようになる
  47. wrap = (uint16_t)((clock_get_hz(clk_sys) / PWM_CLOCK_DIVIDER) / EFFECT_UPDATE_FREQ_HZ);
  48. pwm_config_set_wrap(&c, wrap);
  49. // プログラム開始時にサイン波のルックアップテーブルを生成
  50. for (int i = 0; i < SINE_LUT_SIZE; ++i) {
  51. // 0からPIまでの半周期のサイン波を計算
  52. double sin_val = sin((double)i * M_PI / (double)SINE_LUT_SIZE);
  53. // 計算結果をPWMのデューティ比にスケーリングしてテーブルに格納
  54. sine_lut[i] = (uint16_t)((double)wrap * sin_val);
  55. }
  56. // LEDのスライスを設定
  57. slice_num = pwm_gpio_to_slice_num(LED_PIN);
  58. pwm_init(slice_num, &c, false);
  59. // サブのスライスを設定
  60. sub_slice = pwm_gpio_to_slice_num(PWM_SUB_PIN);
  61. pwm_init(sub_slice, &c, false);
  62. // 割り込み設定
  63. // 割り込みハンドラは片方のスライス(slice_num)にのみ設定すれば、
  64. // 両方のGPIOを同時に制御できる
  65. pwm_clear_irq(slice_num);
  66. pwm_set_irq_enabled(slice_num, true);
  67. irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_irq_handler);
  68. irq_set_enabled(PWM_IRQ_WRAP, true);
  69. // 初期輝度を50%に設定
  70. pwm_set_gpio_level(LED_PIN, wrap/2);
  71. pwm_set_gpio_level(PWM_SUB_PIN, wrap/2);
  72. // 両方のPWMスライスを同時に有効化
  73. pwm_set_enabled(slice_num, true);
  74. pwm_set_enabled(sub_slice, true);
  75. while (true) {
  76. tight_loop_contents();
  77. }
  78. }