goo blog サービス終了のお知らせ 

忘備録-備忘録

技術的な備忘録

ch32v003で電子オルゴール

2025-01-28 21:53:34 | ch32v003
A tiny MML parserを使用して電子オルゴールを作成してみました。

  1. // CH32V003J4M6 pin map
  2. //     +------+
  3. //    -+1    8+-SWIO
  4. // GND-+2    7+-PC4/TIM1_CH4
  5. //    -+3    6+-
  6. // VDD-+4    5+-
  7. //     +------+

  8. #include "ch32v003fun.h"
  9. #include <stdio.h>
  10. #include "mml.h"
  11. #include "note.h"
  12. #include "song.h"

  13. const unsigned int sys_clock = 48000000; // System clock(48kHz)
  14. const unsigned int tim1_psc = 8;         // プリスケーラ

  15. // TIM1をコンペアアプトプットモードで初期化
  16. // Output pin CH4(PC4)
  17. void t1com_init(void)
  18. {
  19.     // クロック供給 GPIOC and TIM1
  20.     RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_TIM1;
  21.     // PC4 is T1CH4, 10MHz Output alt func, push-pull
  22.     GPIOC->CFGLR &= ~(0xf << (4 * 4));
  23.     GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
  24.     // TIM1のリセット
  25.     RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
  26.     RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
  27.     // ATRLRレジスタ オートリロード
  28.     TIM1->CTLR1 |= TIM_ARPE;
  29.     // プリスケーラ設定
  30.     TIM1->PSC = tim1_psc;
  31.     // カウンタ値の上限設定
  32.     TIM1->ATRLR = 1023;
  33.     // データ(ATRLR)の手動リロード 初期化
  34.     TIM1->SWEVGR |= TIM_UG;
  35.     // CH4 正側で出力
  36.     TIM1->CCER |= TIM_CC4E | TIM_CC4P;
  37.     // CH4 コンペアマッチでトグル出力(CC4S = 00, OC4M = 011)
  38.     TIM1->CHCTLR2 |= TIM_OC4M_0 | TIM_OC4M_1;
  39.     // コンペアマッチ値の指定 ATRLRより大きくするとマッチしない(出力が変化しない)
  40.     TIM1->CH4CVR = TIM1->ATRLR + 1; // no compare macth
  41.     // TIM1 出力許可
  42.     TIM1->BDTR |= TIM_MOE;
  43.     // TIM1 動作開始
  44.     TIM1->CTLR1 |= TIM_CEN;
  45. }

  46. // 設定した周波数の矩形波(デューティ50%)を出力
  47. // frq : 周波数
  48. // tim : 出力する時間[msec]
  49. void tone(unsigned int frq, unsigned int tim)
  50. {
  51.     if (frq != 0)
  52.     {
  53.         // 出力周波数設定
  54.         TIM1->ATRLR = sys_clock / frq / tim1_psc / 2 - 1;
  55.         TIM1->CH4CVR = 0x0;
  56.     }
  57.     else
  58.     {
  59.         // 出力停止
  60.         TIM1->ATRLR = 1023;
  61.         TIM1->CH4CVR = TIM1->ATRLR + 1; // no compare macth
  62.     }
  63.     Delay_Ms(tim);
  64.     // 出力停止
  65.     TIM1->ATRLR = 1023;
  66.     TIM1->CH4CVR = TIM1->ATRLR + 1; // no compare macth
  67. }

  68. #define SOUND_SYSTEM_TONE(FREQ, MS) do { tone((FREQ),(MS)); } while (0)
  69. #define SOUND_SYSTEM_REST(MS) do { tone( 0 ,(MS)); } while (0)

  70. const uint16_t notefreq[] = {
  71.      32, 34, 36, 38, 41, 43, 46, 48, 51, 55, 58, 61,
  72.      65, 69, 73, 77, 82, 87, 92, 97, 103, 110, 116, 123,
  73.     130, 138, 146, 155, 164, 174, 184, 195, 207, 220, 233, 246,
  74.     261, 277, 293, 311, 329, 349, 369, 391, 415, 440, 466, 493,
  75.     523, 554, 587, 622, 659, 698, 739, 783, 830, 880, 932, 987,
  76.    1046, 1108, 1174, 1244, 1318, 1396, 1479, 1567, 1661, 1760, 1864, 1975,
  77.    2093, 2217, 2349, 2489, 2637, 2793, 2959, 3135, 3322, 3520, 3729, 3951,
  78.    4186, 4434, 4698, 4978, 5274, 5587, 5919, 6271, 6644, 7040, 7458, 7902,
  79.    8372, 8869, 9397, 9956, 10548, 11175, 11839, 12543, 13289, 14080, 14917, 15804,
  80.   16744, 17739, 18794, 19912, 21096, 22350, 23679, 25087, 26579, 28160, 29834, 31608,
  81.   33488, 35479, 37589, 39824, 42192, 44701, 47359, 50175,
  82. };

  83. static uint32_t get_note_length_ms(NOTE *p, uint32_t note_ticks)
  84. {
  85.   return (60000) * note_ticks / p->bpm / p->bticks;
  86. }

  87. void note_init(NOTE *p, int bpm, int bticks)
  88. {
  89.   p->bpm = bpm;
  90.   p->bticks = bticks;
  91. }

  92. void note_tone(NOTE *p, int number, int ticks)
  93. {
  94.   uint16_t freq = notefreq[number];
  95.   uint32_t ms = get_note_length_ms(p, ticks);
  96.   SOUND_SYSTEM_TONE(freq, ms);
  97. }

  98. void note_rest(NOTE *p, int ticks)
  99. {
  100.   uint32_t ms = get_note_length_ms(p, ticks);
  101.   SOUND_SYSTEM_REST(ms);
  102. }

  103. NOTE note;
  104. MML mml;
  105. MML_OPTION mml_opt;

  106. static void mml_callback(MML_INFO *p, void *extobj)
  107. {
  108.     switch (p->type)
  109.     {
  110.     case MML_TYPE_TEMPO:
  111.     {
  112.         MML_ARGS_TEMPO *args = &(p->args.tempo);
  113.         note_init(&note, args->value, mml_opt.bticks);
  114.     }
  115.     break;
  116.     case MML_TYPE_NOTE:
  117.     {
  118.         MML_ARGS_NOTE *args = &(p->args.note);
  119.         note_tone(&note, args->number, args->ticks);
  120.     }
  121.     break;
  122.     case MML_TYPE_REST:
  123.     {
  124.         MML_ARGS_REST *args = &(p->args.rest);
  125.         note_rest(&note, args->ticks);
  126.     }
  127.     break;
  128.     }
  129. }

  130. void setup()
  131. {
  132.     // Initialize the MML module. 
  133.     mml_init(&mml, mml_callback, 0);
  134.     MML_OPTION_INITIALIZER_DEFAULT(&mml_opt);
  135.      // Initialize the note module.
  136.     int tempo_default = 120;
  137.     note_init(&note, tempo_default, mml_opt.bticks);
  138. }

  139. void loop()
  140. {
  141.     const char *song_table[] = {
  142.         song_over_world,
  143.         song_level_clear,
  144.     };
  145.     int i;

  146.     for (i = 0; i < sizeof(song_table) / sizeof(song_table[0]); i++)
  147.     {
  148.          // Setup the MML module.
  149.         mml_setup(&mml, &mml_opt, (char *)song_table[i]);
  150.          // Fetch the MML text command.
  151.         while (mml_fetch(&mml) == MML_RESULT_OK)
  152.         {
  153.         }
  154.     }
  155. }

  156. int main(void)
  157. {
  158.     SystemInit();
  159.     Delay_Ms(100);
  160.     t1com_init();

  161.     setup();
  162.     while (1)
  163.     {
  164.         loop();
  165.     }
  166. }


参考


最新の画像もっと見る

コメントを投稿

サービス終了に伴い、10月1日にコメント投稿機能を終了させていただく予定です。