音楽を奏でるソース・コード
今回は、フローチャートに従って、ソース・コードを書きます。
ここでは、CodeWarriorを使い、 C:\Projects\CW\RS08C4という場所に RS08C4というプロジェクトを 作成してプログラムを記述していきます。 プロジェクトの作成および設定は、これまでと同じなので、省略します。
#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
//==============================================================
// SOPTレジスタの設定
//==============================================================
const byte SOPT_INIT
= 0b00100010;
// |||||||+-- RSTPE=0 (PTA2をRESET*として使用しない)
// ||||||+--- BKGDPE=1 (PTA3をBKGDとして使用する)
// |||+++---- Reserved
// ||+------- STOPE=1 (STOP命令を使用可能にする)
// |+-------- COPT=0 (COPの周期)
// +--------- COPE=0 (COP機能を使用しない)
//==============================================================
//==============================================================
// MTIMCLKレジスタの設定
// MTIMモジュールのクロックとして周波数250kHz、周期4usecの
// クロックを使用します。
//==============================================================
const byte MTIMCLK_INIT
= 0b00000100;
// ||||++++-- PS=0100 (x16 プリスケーラを使用する)
// ||++------ CLKS=00 (BUSCLKを使用する)
// ++-------- Reserved
//==============================================================
//==============================================================
// SRTISCレジスタの設定
// RTIモジュールの周期を8msecに設定します。
//==============================================================
const byte SRTISC_INIT
= 0b01000001;
// |||||+++-- RTIS=001 (8msec周期に設定する)
// ||||+----- Reserved
// |||+------ RTIE=0 (割り込みは使わない)
// ||+------- RTICLKS=0 (1kHz内蔵発振器を使う)
// |+-------- RTIACK=1 (RTIFフラグをクリアする)
// +--------- RTIF=0 (書き込み無効)
//==============================================================
//==============================================================
// 楽譜構造体の宣言
//==============================================================
typedef struct {
const byte length; // 音符の長さ
const byte period; // MTIMMODに与える音程
} Sono; // 音符構造体
typedef const Sono * __paged SonoP; // 音符へのポインタ
typedef SonoP Phrase; // 小節の構造
typedef const Phrase * __paged PhraseP; // 小節へのポインタ
typedef PhraseP Music; // 楽譜の構造
typedef const Music * __paged MusicP; // 楽譜へのポインタ
//==============================================================
// 音程データの宣言
// MTIMモジュールのクロックとして周波数250kHz、周期4usecの
// クロックを使用します。下限周波数は、489Hzです。
//==============================================================
const long P_base = 250000L / 2; // 250kHz
const byte P_H2 = (P_base/ 494)-1; // 494Hz
const byte P_D3s = (P_base/ 622)-1; // 622Hz
const byte P_E3 = (P_base/ 659)-1; // 659Hz
const byte P_F3s = (P_base/ 740)-1; // 740Hz
const byte P_G3s = (P_base/ 831)-1; // 831Hz
const byte P_A3 = (P_base/ 880)-1; // 880Hz
const byte P_H3 = (P_base/ 988)-1; // 988Hz
const byte P_C4s = (P_base/1109)-1; // 1109Hz
const byte P_D4s = (P_base/1245)-1; // 1245Hz
const byte P_E4 = (P_base/1319)-1; // 1319Hz
const byte P_F4s = (P_base/1480)-1; // 1480Hz
const byte P_G4s = (P_base/1661)-1; // 1661Hz
#pragma CONST_SEG __PAGED_SEG PAGED_ROM
//==============================================================
// 楽譜データ
// ショパン「別れの曲」
//==============================================================
const byte TEMPO = 9; // 曲のテンポ
const Sono phrase_adieu1[] = {
8*TEMPO, P_H2,
8*TEMPO, P_E3, // 1
4*TEMPO, P_D3s,
4*TEMPO, P_E3,
0,0
};
const Sono phrase_adieu2[] = {
20*TEMPO, P_F3s, // 2;10
4*TEMPO, P_G3s,
4*TEMPO, P_G3s,
4*TEMPO, P_F3s,
20*TEMPO, P_G3s, // 3;11
4*TEMPO, P_A3,
4*TEMPO, P_A3,
4*TEMPO, P_G3s,
12*TEMPO, P_C4s,
4*TEMPO, P_H3,
4*TEMPO, P_A3, // 4;12
4*TEMPO, P_G3s,
4*TEMPO, P_D3s,
4*TEMPO, P_E3,
20*TEMPO, P_F3s, // 5;13
4*TEMPO, P_G3s,
4*TEMPO, P_G3s,
4*TEMPO, P_F3s,
16*TEMPO, P_E3,
0,0
};
const Sono phrase_adieu3[] = {
4*TEMPO, P_G3s, // 6
4*TEMPO, P_A3,
4*TEMPO, P_F3s,
4*TEMPO, P_G3s,
4*TEMPO, P_A3,
4*TEMPO, P_H3,
4*TEMPO, P_G3s,
4*TEMPO, P_A3,
8*TEMPO, P_C4s, // 7
16*TEMPO, P_F3s,
4*TEMPO, P_G3s,
20*TEMPO, P_F3s, // 8
4*TEMPO, P_G3s,
4*TEMPO, P_F3s,
16*TEMPO, P_H3,
8*TEMPO, P_G3s, // 9
4*TEMPO, P_D3s,
4*TEMPO, P_E3,
0,0
};
const Sono phrase_adieu4[] = {
4*TEMPO, P_H3, // 14
4*TEMPO, P_C4s,
4*TEMPO, P_C4s,
4*TEMPO, P_H3,
4*TEMPO, P_A3,
4*TEMPO, P_H3,
4*TEMPO, P_G3s,
4*TEMPO, P_A3,
4*TEMPO, P_D4s, // 15
4*TEMPO, P_E4,
4*TEMPO, P_E4,
4*TEMPO, P_D4s,
4*TEMPO, P_C4s,
4*TEMPO, P_D4s,
4*TEMPO, P_H3,
4*TEMPO, P_C4s,
4*TEMPO, P_E4, // 16
4*TEMPO, P_F4s,
4*TEMPO, P_D4s,
4*TEMPO, P_E4,
4*TEMPO, P_F4s,
4*TEMPO, P_G4s,
4*TEMPO, P_E4,
4*TEMPO, P_F4s,
0,0
};
const Sono phrase_adieu5[] = {
20*TEMPO, P_G4s, // 17
4*TEMPO, P_F4s,
4*TEMPO, P_E4,
4*TEMPO, P_C4s,
16*TEMPO, P_D4s, // 18
4*TEMPO, P_E4,
4*TEMPO, P_D4s,
4*TEMPO, P_C4s,
4*TEMPO, P_G3s,
16*TEMPO, P_H3, // 19
4*TEMPO, P_C4s,
4*TEMPO, P_H3,
4*TEMPO, P_A3,
4*TEMPO, P_E3,
16*TEMPO, P_G3s, // 20
8*TEMPO, P_G3s,
0,0
};
const Phrase music_adieu[] = {
phrase_adieu1,
phrase_adieu2,
phrase_adieu3,
phrase_adieu2,
phrase_adieu4,
phrase_adieu5,
(Phrase)0
};
//==============================================================
// 大域変数
//==============================================================
byte sono_count; // 音の長さカウンタ
SonoP sono_point; // 音符ポインタ
PhraseP phrase_point; // 小節ポインタ
//==============================================================
// 初期設定
//==============================================================
void initialize(void) {
// TRIMレジスタを設定する
ICSTRM_TRIM =
((const NV_ICSTRMSTR * __paged)CONVERT_TO_PAGED(0x00003FFA))
->Bits.TRIM;
ICSSC_FTRIM =
((const NV_FTRIMSTR * __paged)CONVERT_TO_PAGED(0x00003FFB))
->Bits.FTRIM;
SOPT = SOPT_INIT; // SOPTレジスタを初期化する
PTAD_PTAD0 = 0; // PTA0の初期出力値を設定する
PTADD_PTADD0 = 1; // PTA0を出力に設定する
// 音程関連の初期設定
MTIMCLK = MTIMCLK_INIT; // MTIMCLKレジスタを初期化する
MTIMMOD = 1; // 最短周期に初期設定する
MTIMSC_TSTP = 0; // タイマを起動する
// 音の長さ関連の初期設定
SRTISC = SRTISC_INIT; // SRTISCレジスタを初期化する
// 楽譜関連の初期設定
phrase_point = music_adieu; // 最初の小節を設定する
sono_point = *phrase_point; // 最初の音符を設定する
sono_count = 1; // 最短の音の長さを設定する
}
//==============================================================
// MTIMモジュールによる時間待ち
//==============================================================
void wait_moment(void) {
// MTIMモジュールによる時間待ち
while (!MTIMSC_TOF) ; // TOFフラグがセットされるのを待つ
MTIMSC_TOF = 0; // TOFフラグをクリアする
}
//==============================================================
// 圧電スピーカ出力を反転する
//==============================================================
void reverse_port(void) {
PTAD_PTAD0 = ~PTAD_PTAD0; // ポート出力を反転する
}
//==============================================================
// 音符を変更する
// 楽譜データから音符を取り出して、音程と長さを設定する。
// そして、ポインタを次の音符に進める。
//==============================================================
void update_sono(void) {
// 音符を取り出す
sono_count = sono_point->length; // 音の長さを設定する
MTIMMOD = sono_point->period; // 音程を設定する
// 次の音符に進む
sono_point++;
if (sono_point->length == 0) {
// 小節の最後に達したら、次の小節に進む
phrase_point++;
if (*phrase_point == 0) {
// 楽譜の最後に達したら、楽譜の最初の小節に戻る
phrase_point = music_adieu;
}
// 小節の最初の音符を指示する
sono_point = *phrase_point;
}
}
//==============================================================
// メイン関数
//==============================================================
void main(void) {
EnableInterrupts; /* enable interrupts */
/* include your code here */
initialize(); // 初期設定
for(;;) {
wait_moment(); // 時間待ち
reverse_port(); // 出力を反転する
if (SRTISC_RTIF) { // RTIイベントが発生していたら
SRTISC_RTIACK = 1; // RTIFフラグをクリアする
if (--sono_count <= 0) { // 音の長さが設定値に達したら
update_sono(); // 音符を変更する
}
}
} /* loop forever */
/* please make sure that you never leave main */
}
このプログラムも大半が前回までに作成したプログラムからの流用です。
次回は、変更のあった部分について解説していきます。
田中範明
