A tiny MML parserを使用して電子オルゴールを作成してみました。
- // CH32V003J4M6 pin map
- // +------+
- // -+1 8+-SWIO
- // GND-+2 7+-PC4/TIM1_CH4
- // -+3 6+-
- // VDD-+4 5+-
- // +------+
- #include "ch32v003fun.h"
- #include <stdio.h>
- #include "mml.h"
- #include "note.h"
- #include "song.h"
- const unsigned int sys_clock = 48000000; // System clock(48kHz)
- const unsigned int tim1_psc = 8; // プリスケーラ
- // TIM1をコンペアアプトプットモードで初期化
- // Output pin CH4(PC4)
- void t1com_init(void)
- {
- // クロック供給 GPIOC and TIM1
- RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_TIM1;
- // PC4 is T1CH4, 10MHz Output alt func, push-pull
- GPIOC->CFGLR &= ~(0xf << (4 * 4));
- GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
- // TIM1のリセット
- RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
- RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
- // ATRLRレジスタ オートリロード
- TIM1->CTLR1 |= TIM_ARPE;
- // プリスケーラ設定
- TIM1->PSC = tim1_psc;
- // カウンタ値の上限設定
- TIM1->ATRLR = 1023;
- // データ(ATRLR)の手動リロード 初期化
- TIM1->SWEVGR |= TIM_UG;
- // CH4 正側で出力
- TIM1->CCER |= TIM_CC4E | TIM_CC4P;
- // CH4 コンペアマッチでトグル出力(CC4S = 00, OC4M = 011)
- TIM1->CHCTLR2 |= TIM_OC4M_0 | TIM_OC4M_1;
- // コンペアマッチ値の指定 ATRLRより大きくするとマッチしない(出力が変化しない)
- TIM1->CH4CVR = TIM1->ATRLR + 1; // no compare macth
- // TIM1 出力許可
- TIM1->BDTR |= TIM_MOE;
- // TIM1 動作開始
- TIM1->CTLR1 |= TIM_CEN;
- }
- // 設定した周波数の矩形波(デューティ50%)を出力
- // frq : 周波数
- // tim : 出力する時間[msec]
- void tone(unsigned int frq, unsigned int tim)
- {
- if (frq != 0)
- {
- // 出力周波数設定
- TIM1->ATRLR = sys_clock / frq / tim1_psc / 2 - 1;
- TIM1->CH4CVR = 0x0;
- }
- else
- {
- // 出力停止
- TIM1->ATRLR = 1023;
- TIM1->CH4CVR = TIM1->ATRLR + 1; // no compare macth
- }
- Delay_Ms(tim);
- // 出力停止
- TIM1->ATRLR = 1023;
- TIM1->CH4CVR = TIM1->ATRLR + 1; // no compare macth
- }
- #define SOUND_SYSTEM_TONE(FREQ, MS) do { tone((FREQ),(MS)); } while (0)
- #define SOUND_SYSTEM_REST(MS) do { tone( 0 ,(MS)); } while (0)
- const uint16_t notefreq[] = {
- 32, 34, 36, 38, 41, 43, 46, 48, 51, 55, 58, 61,
- 65, 69, 73, 77, 82, 87, 92, 97, 103, 110, 116, 123,
- 130, 138, 146, 155, 164, 174, 184, 195, 207, 220, 233, 246,
- 261, 277, 293, 311, 329, 349, 369, 391, 415, 440, 466, 493,
- 523, 554, 587, 622, 659, 698, 739, 783, 830, 880, 932, 987,
- 1046, 1108, 1174, 1244, 1318, 1396, 1479, 1567, 1661, 1760, 1864, 1975,
- 2093, 2217, 2349, 2489, 2637, 2793, 2959, 3135, 3322, 3520, 3729, 3951,
- 4186, 4434, 4698, 4978, 5274, 5587, 5919, 6271, 6644, 7040, 7458, 7902,
- 8372, 8869, 9397, 9956, 10548, 11175, 11839, 12543, 13289, 14080, 14917, 15804,
- 16744, 17739, 18794, 19912, 21096, 22350, 23679, 25087, 26579, 28160, 29834, 31608,
- 33488, 35479, 37589, 39824, 42192, 44701, 47359, 50175,
- };
- static uint32_t get_note_length_ms(NOTE *p, uint32_t note_ticks)
- {
- return (60000) * note_ticks / p->bpm / p->bticks;
- }
- void note_init(NOTE *p, int bpm, int bticks)
- {
- p->bpm = bpm;
- p->bticks = bticks;
- }
- void note_tone(NOTE *p, int number, int ticks)
- {
- uint16_t freq = notefreq[number];
- uint32_t ms = get_note_length_ms(p, ticks);
- SOUND_SYSTEM_TONE(freq, ms);
- }
- void note_rest(NOTE *p, int ticks)
- {
- uint32_t ms = get_note_length_ms(p, ticks);
- SOUND_SYSTEM_REST(ms);
- }
- NOTE note;
- MML mml;
- MML_OPTION mml_opt;
- static void mml_callback(MML_INFO *p, void *extobj)
- {
- switch (p->type)
- {
- case MML_TYPE_TEMPO:
- {
- MML_ARGS_TEMPO *args = &(p->args.tempo);
- note_init(¬e, args->value, mml_opt.bticks);
- }
- break;
- case MML_TYPE_NOTE:
- {
- MML_ARGS_NOTE *args = &(p->args.note);
- note_tone(¬e, args->number, args->ticks);
- }
- break;
- case MML_TYPE_REST:
- {
- MML_ARGS_REST *args = &(p->args.rest);
- note_rest(¬e, args->ticks);
- }
- break;
- }
- }
- void setup()
- {
- // Initialize the MML module.
- mml_init(&mml, mml_callback, 0);
- MML_OPTION_INITIALIZER_DEFAULT(&mml_opt);
- // Initialize the note module.
- int tempo_default = 120;
- note_init(¬e, tempo_default, mml_opt.bticks);
- }
- void loop()
- {
- const char *song_table[] = {
- song_over_world,
- song_level_clear,
- };
- int i;
- for (i = 0; i < sizeof(song_table) / sizeof(song_table[0]); i++)
- {
- // Setup the MML module.
- mml_setup(&mml, &mml_opt, (char *)song_table[i]);
- // Fetch the MML text command.
- while (mml_fetch(&mml) == MML_RESULT_OK)
- {
- }
- }
- }
- int main(void)
- {
- SystemInit();
- Delay_Ms(100);
- t1com_init();
- setup();
- while (1)
- {
- loop();
- }
- }
参考
※コメント投稿者のブログIDはブログ作成者のみに通知されます