====== ミニ・オルガン(SDカード対応)(PIC18F2550) ======
===== 概要 =====
音譜をテキストファイルに記入し、それを自動演奏させるオルガンを製作しました。
===== 動作原理 =====
<プログラムの流れ>
- ポートや内臓モジュールを初期化します。
- SDカードを初期化します。
- スタートスイッチが押下されるのを待ちます。
- ファイル(ファイル名は、“organ.txt" 固定)をオープンします。
- カンマ区切り単位で音譜を読み込みます。
- 読み込んだ音譜の周波数で音を発生させます。(ポートのON/OFFをソフトで処理)
- ファイルの最後まで5.6.を繰り返します。
- 3.へ戻ります。
<演奏までの流れ>
- パソコン上のテキストエディタで、音譜を作成し、テキストファイルに記入し、SDカードに保存します。
- SDカードを、ミニ・オルガンのSDカードスロットに挿入します。
- 電源をONにします。
- SDカードの初期化が成功するとLEDが3回点滅します。失敗すると点滅したままになります。
- スタートスイッチを押下すると、演奏がスタートします。演奏中はLEDが点灯します。
<表記>
音階の周波数および音譜の表記は、次の表のようになります。(音譜間はカンマ区切り)
{{:imgpaste:202004:admin-20200430-193106.png?500}}
<その他の表記>
DO :ド
DO-:ドー
-:休止記号
<表記例:ドレミファソラシ>
DO,RE,MI,FA,SO,RA,SI
<表記例:1オクターブ上のドレミファソラシ>
DO2,RE2,MI2,FA2,SO2,RA2,SI2
===== 回路図 =====
{{:imgpaste:202004:admin-20200430-193145.png}}
===== ソースコード =====
//**********************************************************************
/*
「簡易自動演奏オルガン(SDC対応)」
*/
//**********************************************************************
#define SW PORTE.F3
#define LED PORTA.F0
#define CR 0x0d
#define LF 0x0a
#define DO 262
#define RE 294
#define MI 330
#define FA 349
#define SO 392
#define RA 440
#define SI 494
#define DO2 523
#define RE2 587
#define MI2 659
#define FA2 699
#define SO2 784
#define RA2 880
#define SI2 988
//**********************************************************************
void init_sdc()
{
static short cnt;
//SDC(MMC)の初期化
Spi_Init_Advanced(MASTER_OSC_DIV64, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH);
if (Mmc_Fat_Init(&PORTC, 6)) {
while (1) {
LED = 1;
Delay_ms(100);
LED = 0;
Delay_ms(100);
}
}
Spi_Init_Advanced(MASTER_OSC_DIV16, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH);
for (cnt = 0; cnt < 3; cnt++) {
LED = 1;
Delay_ms(300);
LED = 0;
Delay_ms(300);
}
}
//**********************************************************************
void SwitchONcheck()
{
while (Button(&PORTE, 3, 1, 0) == 0)
;
while (Button(&PORTE, 3, 1, 1) == 0)
;
}
//**********************************************************************
void doremiProc(int freq, long time)
{
static int cnt, tmp;
//
switch (freq) {
case DO:
tmp = time / (1000000 / DO);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / DO / 2);
PORTC.F2 = 0;
Delay_us(1000000 / DO / 2);
}
break;
case RE:
tmp = time / (1000000 / RE);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / RE / 2);
PORTC.F2 = 0;
Delay_us(1000000 / RE / 2);
}
break;
case MI:
tmp = time / (1000000 / MI);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / MI / 2);
PORTC.F2 = 0;
Delay_us(1000000 / MI / 2);
}
break;
case FA:
tmp = time / (1000000 / FA);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / FA / 2);
PORTC.F2 = 0;
Delay_us(1000000 / FA / 2);
}
break;
case SO:
tmp = time / (1000000 / SO);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / SO / 2);
PORTC.F2 = 0;
Delay_us(1000000 / SO / 2);
}
break;
case RA:
tmp = time / (1000000 / RA);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / RA / 2);
PORTC.F2 = 0;
Delay_us(1000000 / RA / 2);
}
break;
case SI:
tmp = time / (1000000 / SI);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / SI / 2);
PORTC.F2 = 0;
Delay_us(1000000 / SI / 2);
}
break;
case DO2:
tmp = time / (1000000 / DO2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / DO2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / DO2 / 2);
}
break;
case RE2:
tmp = time / (1000000 / RE2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / RE2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / RE2 / 2);
}
break;
case MI2:
tmp = time / (1000000 / MI2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / MI2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / MI2 / 2);
}
break;
case FA2:
tmp = time / (1000000 / FA2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / FA2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / FA2 / 2);
}
break;
case SO2:
tmp = time / (1000000 / SO2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / SO2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / SO2 / 2);
}
break;
case RA2:
tmp = time / (1000000 / RA2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / RA2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / RA2 / 2);
}
break;
case SI2:
tmp = time / (1000000 / SI2);
for (cnt = 0; cnt < tmp; cnt++) {
PORTC.F2 = 1;
Delay_us(1000000 / SI2 / 2);
PORTC.F2 = 0;
Delay_us(1000000 / SI2 / 2);
}
break;
}
}
//**********************************************************************
void organProc()
{
//変数の定義
static char buf[10], character, cnt;
static unsigned long fsize, length;
//MMCのファイルのオープン
Mmc_Fat_Assign("organ.txt", 0);
Mmc_Fat_Reset(&fsize);
length = 0;
cnt = 0;
//
while (length < fsize) {
Mmc_Fat_Read(&character);
length++;
//
switch (character) {
case ',':
case CR:
buf[cnt] = 0x00;
cnt = 0;
if (strstr(buf, "DO2") != 0x00) {
doremiProc(DO2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "RE2") != 0x00) {
doremiProc(RE2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "MI2") != 0x00) {
doremiProc(MI2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "FA2") != 0x00) {
doremiProc(FA2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "SO2") != 0x00) {
doremiProc(SO2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "RA2") != 0x00) {
doremiProc(RA2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "SI2") != 0x00) {
doremiProc(SI2, buf[3] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "DO") != 0x00) {
doremiProc(DO, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "RE") != 0x00) {
doremiProc(RE, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "MI") != 0x00) {
doremiProc(MI, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "FA") != 0x00) {
doremiProc(FA, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "SO") != 0x00) {
doremiProc(SO, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "RA") != 0x00) {
doremiProc(RA, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "SI") != 0x00) {
doremiProc(SI, buf[2] == '-' ? 750000 : 500000);
break;
}
if (strstr(buf, "-") != 0x00) {
Delay_ms(100);
break;
}
break;
case ' ':
break;
case LF:
Delay_ms(1000);
break;
default:
buf[cnt] = character;
cnt++;
break;
}
}
}
//**********************************************************************
void main()
{
//コンパレータは使用しない。
CMCON = 0b00000111;
//A/D変換の設定
ADCON1.PCFG3 = 1;
ADCON1.PCFG2 = 1;
ADCON1.PCFG1 = 1;
ADCON1.PCFG0 = 1;
//
OSCCON.IRCF2 = 1;
OSCCON.IRCF1 = 1;
OSCCON.IRCF0 = 1;
//ポートの設定
TRISA = 0b0000000000;
TRISB = 0b00000001;
TRISC = 0b00000000;
//SDC(MMC)の初期化
init_sdc();
//
while (1) {
SwitchONcheck();
LED = 1;
organProc();
LED = 0;
}
}
//**********************************************************************
===== 動作確認 =====
左側から、スタート用プッシュスイッチ、LED、PIC18F2550、乾電池(単三2本)、SDカード、圧電スピーカ
{{:imgpaste:202004:admin-20200430-193320.png?500}}
音譜の例です。“organ.txt"をメモ帳で開いたところです。
{{:imgpaste:202004:admin-20200430-193332.png?500}}
<チューリップ>
DO,RE,MI-,-,DO,RE,MI-,-,SO,MI,RE,DO,RE,MI,RE-,-,DO,RE,MI-,-,DO,RE,MI-,-,SO,MI,RE,DO,RE,MI,DO-,-,SO,
SO,MI,SO,RA,RA,SO-,-,MI,MI,RE,RE,DO-
<かえるの歌>
DO,RE,MI,FA,MI,RE,DO-,-,MI,FA,SO,RA,SO,FA,MI-,-,DO,-,-,DO,-,-,DO,-,-,DO,-,-,DO,DO,RE,RE,MI,MI,FA,FA,
MI-,RE-,DO-
如何でしょうか?
もう少し滑らか(自然)に演奏させるには、表記をもっと工夫する必要がありますが、用途によってはこれで十分なのでは。。。 ^_^
このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]]
This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]]