PAGE TOP

鉄道模型レイアウト・プラモデル展示台用の音(PICでWAV再生)

Nゲージ 踏切の製作」は、遮断機の部分を作っている途中であるが、踏切の音にも、昔ながらの電鈴式の音、JRの音、私鉄の音、構内踏切の音などいろいろあるということで、いろんな音にしてみたり、遮断機の有無などでバリエーションのある踏切を5個量産中。

なのであるが、踏切ばかりでも能がない。

ちょっと脱線してPICマイコンで、鉄道模型のレイアウトやらプラモデルの展示台に内臓して音を出すためのモジュールを作ってみた。

ディーゼルエンジンのアイドリング音、交通信号のカッコー、ピヨピヨやら、単調な音の繰り返しはSDカードに記録した2~3秒くらいの音を繰り返して再生し、BGMの音楽は市販のMP3再生ボード(MK-144)と連動させて。
SDカードにデータを記録することで、交通信号機も昔ながらの「故郷の空」と「通りゃんせ」などが再生できる。

また、鉄道模型のレイアウト用以外にもプラモデルの展示台にも内蔵させることができ、プラモデルにあった音楽が流せる。

使ったPICマイコンは、PIC24FJ64GA002

4つのスイッチにBCDコードがだせるロータリーコードスイッチを使って音楽を切換え、同時に2つのWAVファイルが再生できる。

音声はそれぞれ別の出力ポートに。
汽笛など単発的で繰り返しのない音は3つ目の音声として、一時的に1つの音を止めて出力。

また、このロータリーコードスイッチに応じてMK-144に登録されたMP3ファイルも再生。

等々。

もうちょっと詳しいことは下のソースのヘッダ部分に書いてます。

PIC24FJ64GA002でWAV再生

(写真上) 左の緑のボードは市販のMP3再生ボード(MK-144)を制御するボードMK-148

MK-148上にはMP3ファイルの再生用タクトスイッチが並んでいる。

右のが今回作ったボード。

不要になったMK-148を再利用するために使ったのでアンプはMK-148上の物にミキシング。

2つのボードを並べるとちょっと大きいが、MK-148のタクトスイッチ部分を取り除いたり、MP3の再生機能自体をなくしてWAVファイルの再生だけに特化するともっとコンパクトにできる。

実際にレイアウトにつける時は、このボードは手元において、スピーカー部だけをレイアウト上に置くことになろうかと。
そのときはスイッチは操作しやすいようにつけかえますが。

 

PIC24FJ64GA002でWAV再生

(写真上) やはり、ちぃっちゃいスピーカでは音が・・

プラモデルの展示台等ではコンパクトにしたいのでこれでも大きい方ではあるけど。

ためしに980円のスピーカーを繋いでみると、まあ使えるかも。
・・場所とりますが。

 


追記

ちょっと小さめのものを作ってみました。
鉄道模型レイアウト・プラモデル展示台用の音(PICでWAV再生) 2

 


なお、この動画の中の音にはWAVだけでなく一部MP3ボードで再生したものも含まれています。


ソース

[c]

// ***********************************************
//
// PIC24FJ64GA002
//	8kHz sampling , 16bit モノラル Wav再生
//
//
// ・SDカードからwavファイルを読み込んで再生する
// ・音声はch1とch2の2つに出力する
// ・wavファイルは#0から#2までの最大3つの音声ファイルで1グループを構成する
// ・#0~#2の3つの再生スイッチで、それぞれのファイルを再生する
// ・スイッチに対応するファイルが存在しないときはそのスイッチに対応する音声は再生されない
// ・#0と#1スイッチが押されている間は、それに対応したファイルは繰り返して再生される
// ・#0と#1スイッチはトグルスイッチ、押しボタンスイッチでもよいがトグルスイッチを想定している
// ・#2スイッチが押されたときは、そのファイルが終了するまで再生し、繰り返さない。
//	  ただし、再生終了時に#2スイッチが押されていると再び再生される。
//	  #2の再生を途中で終了させるボタンはない。
//	  途中で終了させたい場合はロータリーコードスイッチを切り替える
// ・#0と#1スイッチはトグルスイッチ、押しボタンスイッチでもよいが押しボタンスイッチを想定している
// ・#0のファイルの音声はch1に出力する
// ・#1と#2のファイルの音声はch2に出力する
//	  #2の方が優先順位は高い。
//	  優先順位が高いものが再生されているときは、優先順位が低いものは再生されない
//	  #1と#2も再生するファイルがない、または再生スイッチが押されていないときは
//	  ch1と同じ音声(#0ファイルの音声)が出力される
// ・wavファイルのグループは最大10グループもてる
// ・グループはBCDコードが出力できるロータリーコードスイッチを使用し、その4bitをPICに入力する
// ・エラー時は内部に記録したチャイム音を再生する
// ・押しボタンで市販のMP3プレーヤーボードMK144の再生、停止を制御する(UART)
//
// ピンアサイン
// #1  MCLR
// #2  RA0/CN2 (MK-144制御用 input スタート/ストップ) 内部プルアップ
// #3  RA1/CN3 (MK-144制御用 input BUSYチェック) 内部プルアップ Low:busy Hi:not busy 
// #4  RB0/RP0/OC1 ch1音声
// #5  RB1/RP1/OC2 ch2音声
// #6  RP2 TX (MK-144制御用 output USART)
// #7  RP3 RX (MK-144制御用 input USART)
// #8  Vss
// #9  OCSI
// #10 OCSO
// #11 SD-CARD DAT3
// #12 RA4/CN0 #0音声再生(input) (active low--lowの間再生) 内部プルアップ
// #13 VDD
// #14 SD-CARD CMD/DI
// #15 SD-CARD CLK
// #16 SD-CARD DAT0
// #17 SD-CARD CD
// #18 SD-CARD WP
// #19 DISVREG (GND)
// #20 VCSP
// #21 RB10/CN16 #1音声再生(input) (active low--lowの間再生) 内部プルアップ
// #22 RB11/CN15 #2音声再生(input) (active low--lowの間再生) 内部プルアップ
// #23 RB12/CN14 (in ロータリーコードスイッチ BCD Bit0) 内部プルアップ
// #24 RB13/CN13 (in ロータリーコードスイッチ BCD Bit1) 内部プルアップ
// #25 RB14/CN12 (in ロータリーコードスイッチ BCD Bit2) 内部プルアップ
// #26 RB15/CN11 (in ロータリーコードスイッチ BCD Bit3) 内部プルアップ
// #27 VDD
// #28 VSS
//
//
// ***********************************************

//	コンパイラ XC16
//	SDカードのI/OはMicrochip C30のMicrochip Memory Disk Drive File Systemを使用
//	(FSIO.hからインクルードされるモジュールも環境に準備しておく)
//

#include <xc.h>
#include <uart.h>

// CONFIG2
#pragma config POSCMOD = XT 		// Primary Oscillator Select (XT Oscillator mode selected)
#pragma config I2C1SEL = PRI		// I2C1 Pin Location Select (Use default SCL1/SDA1 pins)
#pragma config IOL1WAY = OFF		// IOLOCK Protection (IOLOCK may be changed via unlocking seq)
#pragma config OSCIOFNC = OFF		// Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as CLKO (FOSC/2))
#pragma config FCKSM = CSDCMD		// Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled)
#pragma config FNOSC = PRIPLL		// Oscillator Select (Primary Oscillator with PLL module (HSPLL, ECPLL))
#pragma config SOSCSEL = SOSC		// Sec Oscillator Select (Default Secondary Oscillator (SOSC))
#pragma config WUTSEL = LEG 		// Wake-up timer Select (Legacy Wake-up Timer)
#pragma config IESO = OFF			// Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) disabled)

// CONFIG1
#pragma config WDTPS = PS32768		// Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128		// WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = ON			// Watchdog Timer Window (Standard Watchdog Timer enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = OFF 		// Watchdog Timer Enable (Watchdog Timer is disabled)
#pragma config ICS = PGx1			// Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1)
#pragma config GWRP = OFF			// General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF			// General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = OFF 		// JTAG Port Enable (JTAG port is disabled)

#include <stdio.h>
#include <string.h>

#include "FSIO.h"					// SDカード i/o用

// クロック周波数指定(__delay_msとボーレート計算用)
//#define FCY 8000000L				// クロック 8MHz
#define FCY 16000000L				// クロック 16MHz
//#define FCY 32000000L 			// クロック 32MHz

#include <libpic30.h>				//delayマクロ用

#include "chime.h"					// エラーチャイムWAVファイル波形データ

#define FHANDLE 3
#define BUFSIZE 256
#define FILENAMEMAX 12


BYTE sdReadyFlag = FALSE;			// SD i/o 初期化 TRUE(1):OK / FALSE(0); NG
BYTE errorFlag = FALSE; 			// TRUE(1):チャイム鳴動 / FALSE(0)
unsigned int chimeidx = 0;			// エラーチャイム配列参照添字


// i/oバッファ

struct buffer {
	int status; 					// 0:無効 1:データ読み込み済 2:データ出力済
	char data[BUFSIZE]; 			// 読み込みバッファ
	int datasize;					// 有効レングス
	unsigned int outputptr; 		// 出力用添字
};

// WAVファイル 先頭部分
// WAVファイルのフォーマットに合わせて修正

struct wavheader {
	char nu[36];					// (読み飛ばし部分)
	char datachid[4];				// dataチャンクID
	unsigned long chunkleng;		// 波形データレングス
};

// ハンドラ

struct handler {
	char fname[FILENAMEMAX];		// ファイル名
	int playFlag;					// 再生フラグ 0:停止 1:再生
	int repeatFlag; 				// 繰り返しフラグ
									// 0:繰り返しあり
									// 1:繰り返しなし(データ未読み込み)
									// 2:繰り返しなし(初期値/データ読み込み完了)
	FSFILE *fptr;					// ファイルポインタ
	unsigned long remaining;		// 波形データ残りバイト数
	int nextRead;					// i/oバッファ参照用添字(読み込み用)
	int currOut;					// i/oバッファ参照用添字(出力用)
	struct buffer buf[2];			// i/oバッファ
	struct wavheader whdr;			// WAVファイル 先頭部分
} fhandle[FHANDLE];

// ロータリーコードスイッチチェック用
// (0~9までのBCDコードをポートから入力して、再生するファイルグループを指定)
typedef union {
	unsigned char selector;

	struct {
		unsigned selB0 : 1; 		//bit0
		unsigned selB1 : 1; 		//bit1
		unsigned selB2 : 1; 		//bit2
		unsigned selB3 : 1; 		//bit3
		unsigned fu : 4;
	} selectorStatusBits;
} selectorStatus;
selectorStatus sel;

BYTE Mk144Switch = 0;				// Mk144制御スイッチ 0:停止 1:再生
BYTE Mk144SwitchSave = 0;			// Mk144制御スイッチ 0:停止 1:再生

// ファイルグループID(ファイル名の先頭)
char *groupid[] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "xx"};

// UART
//	MK-144の規格 4800bps パリティなし データ8bit ストップビット1 フロー制御なし

const unsigned int UARTMode
		= UART_EN					// UARTモジュール - 有効
		& UART_NO_PAR_8BIT			// パリティなし/データ 8ビット
		& UART_1STOPBIT 			// ストップビット - 1ビット
		& UART_IDLE_CON 			// アイドルモード - Work in IDLE mode
		& UART_MODE_SIMPLEX 		//UxRTSピンモード
		& UART_DIS_WAKE 			// ウェイクアップ - 無効
		& UART_UEN_00				//Port latch control
		& UART_IrDA_DISABLE 		// IrDAエンコーダ 有効/無効
		& UART_DIS_LOOPBACK 		// ループバック - 無効
		& UART_DIS_ABAUD			// 自動ボーレート - 無効
		& UART_UXRX_IDLE_ONE		//Idle state UxRX Idle state is one
		& UART_BRGH_SIXTEEN 		//BRG BRG generates 16 clocks per bit period
		;

const unsigned int UARTSta
		= UART_TX_ENABLE			// 送信 - 有効
		& UART_INT_TX_BUF_EMPTY 	//送信の割り込み条件 送信バッファが空になったとき
		& UART_IrDA_POL_INV_ZERO	//IrDAエンコード
		& UART_SYNC_BREAK_ENABLED
		& UART_TX_ENABLE
		& UART_INT_RX_CHAR			// 受信の割り込み条件 - 受信するたび
		& UART_ADR_DETECT_DIS		// アドレス検出 - 無効
		& UART_RX_OVERRUN_CLEAR 	// 受信バッファオーバーランエラー - クリア
		;

//
// ボーレートクロック
// UARTBaud 8MHz :103  16MHz:207  32MHz: 416

#define BAUDRATE  4800L 						 // ボーレート [bps]
const double UARTBaud = (double) FCY / (16 * BAUDRATE) - 1;

//
// 関数定義
//
void fhandleinit(int);				// ハンドラ初期化
void bhandleinit(int, int); 		// i/oバッファ初期化
void makeFileName(void);			// ファイル名生成
int waveform(int);					// 波形作成
void wavopen(int);					// Wavファイルオープン
void wavread(int);					// Wavファイル波形部読み込み
void mk144ctrl(void);				//MK-144制御
void mk144putcmd(unsigned char);	//MK-144向けコマンド送信

/**
 * メイン関数
 */

int main(void) {
	memset(fhandle, 0x00, sizeof (fhandle));
	selectorStatus check;
	check.selector = 0x00;
	sel.selector = 0x0a;

	CLKDIV = 0;

	AD1PCFG = 0xFFFF;				// I/Oはすべてデジタル
	TRISB = 0xfffc; 				// RB0、RB1を音声出力
	// 内部プルアップ1(CN16 CN15 CN14 CN13 CN12 CN11 CN3 CN2 CN0をON)
	_CN16PUE = _CN15PUE = _CN14PUE = _CN13PUE = _CN12PUE = _CN11PUE = _CN3PUE = _CN2PUE = _CN0PUE = 1;

	CMCON = 0; // コンパレータオフ

	// SDカード用設定
	// SPIのピン割り付け
	RPINR20bits.SDI1R = 7;			// SDI1をRP7に
	RPOR3bits.RP6R = 8; 			// SCK1をRP6に
	RPOR2bits.RP5R = 7; 			// SDO1をRP5に

	// ch1音声用設定
	// タイマ2設定
	T2CON = 0x8000;
	PR2 = 159; //100kHz
	// OC1設定
	RPOR0bits.RP0R = 18;			// OC1をRP0に割付け
	OC1CON = 0x0006;				// タイマ2使用 PWM FAULTなし

	// ch2音声用設定
	// タイマ3設定
	T3CON = 0x8000;
	PR3 = 159; //100kHz
	// OC2設定
	RPOR0bits.RP1R = 19;			// OC2をRP1に割付け
	OC2CON = 0x000e;				// タイマ3使用 PWM FAULTなし

	// タイマ4(音声出力用)モード設定
	T4CON = 0x0000;
	T4CONbits.TCKPS1 = 0;
	T4CONbits.TCKPS0 = 1;
	T4CONbits.TON = 1;

	PR4 = 249;						// 125usec	8kHz
	_T4IP = 5;						// 割り込みレベル
	_T4IF = 0;						// 割り込みフラグクリア
	_T4IE = 1;						// タイマ4割り込み許可

	// MK-144制御用
	// UART用設定
	RPINR18bits.U1RXR = 3;			// UART1 RX を RP3に
	RPOR1bits.RP2R = 3; 			// UART1 TX を RP2に
	U1BRG = UARTBaud;
	U1MODE = UARTMode;
	U1STA = UARTSta;

	// RA0/CN2(MK-144制御ボタン)用CN割り込み設定
	_CN2IE = 1; 					//CN2の割り込みを許可
	_CNIP = 5;						// 割り込みレベル
	_CNIF = 0;						// CN割り込みフラグクリア
	_CNIE = 1;						// CNピン割り込み許可

	int i;

	while (1) {
		// ファイルグループ取得(ロータリーコードスイッチ(Active Low)チェック)
		check.selectorStatusBits.selB0 = !PORTBbits.RB12;
		check.selectorStatusBits.selB1 = !PORTBbits.RB13;
		check.selectorStatusBits.selB2 = !PORTBbits.RB14;
		check.selectorStatusBits.selB3 = !PORTBbits.RB15;

		if (sel.selector != check.selector) {
			// ロータリーコードスイッチが変わった
			sel = check;
			sdReadyFlag = errorFlag = FALSE;
			mk144putcmd(0xEF); //MK-144停止
			Mk144SwitchSave = Mk144Switch = 0;

		}
		if (!sdReadyFlag) {
			// 初期化時、ロータリーコードスイッチ変更時、
			// SDカード抜き差し等でi/oエラー(現仕様はseek時のエラー)となった時のリカバリ
			for (i = 0; i < FHANDLE; i++)
				fhandleinit(i);
			makeFileName();
			while (!sdReadyFlag) {
				// SDi/o 初期化完了まで無限ループ
				sdReadyFlag = FSInit(); // SDi/o 初期化
				errorFlag = !sdReadyFlag;
			}
			for (i = 0; i < FHANDLE; i++)
				wavopen(i);
		}

		// 再生スイッチ(Active Low)チェック
		fhandle[0].playFlag = !PORTAbits.RA4;
		fhandle[1].playFlag = !PORTBbits.RB10;
		fhandle[2].playFlag = !PORTBbits.RB11;
		for (i = 0; i < FHANDLE; i++) {
			if (2 == fhandle[i].repeatFlag && fhandle[i].playFlag)
				fhandle[i].repeatFlag = 1;
			wavread(i);
		}
		mk144ctrl(); //MK-144制御
	}
}

/**
 * ハンドラ初期化
 * @param int i 初期化するハンドラ(fhandle)の番号
 */
void fhandleinit(int i) {
	fhandle[i].fname[0] = 0x00;
	fhandle[i].playFlag = 0;
	// ファイル#0、#1は繰り返し再生 #2は繰り返さない
	fhandle[i].repeatFlag = (0 == i || 1 == i) ? 0 : 2;

	if (NULL != fhandle[i].fptr)
		FSfclose(fhandle[i].fptr);
	fhandle[i].fptr = NULL;
	fhandle[i].remaining = 0L;
	fhandle[i].nextRead = 0;
	fhandle[i].currOut = 0;
	bhandleinit(i, 0);
	bhandleinit(i, 1);
}

/**
 * i/oバッファ初期化
 * @param int  i 初期化するハンドラ(fhandle)の番号
 * @param int  j 初期化するi/oバッファ(buf)の番号
 */
void bhandleinit(int i, int j) {
	fhandle[i].buf[j].status = 0;
	fhandle[i].buf[j].datasize = 0;
	fhandle[i].buf[j].outputptr = 0;
}

/**
 * ファイル名生成
 *
 * ファイル名は、
 * groupid[ロータリーコードスイッチの値で修飾]
 * +
 * 音声再生スイッチの番号(1~3)
 * +
 * '.wav'
 *
 * ロータリーコードスイッチが1の時 :
 *#1音声再生スイッチに対応するファイル名は '01' + '1' + '.wav'
 * → '011.wav'
 *#2音声再生スイッチに対応するファイル名は '01' + '2' + '.wav'
 * → '012.wav'
 *#3音声再生スイッチに対応するファイル名は '01' + '3' + '.wav'
 * → '013.wav'
 *
 */
void makeFileName(void) {
	int i;
	char wk[] = "0.wav";
	for (i = 0; i < FHANDLE; i++) {
		strcpy(fhandle[i].fname, groupid[sel.selector]);
		wk[0] = '0' + (char) (i + 1);
		strcat(fhandle[i].fname, wk);
	}
}

/**
 * タイマ4割り込み処理関数
 */
void __attribute__((interrupt, no_auto_psv)) _T4Interrupt(void) {
	unsigned int e, ch1, ch2;

	if (errorFlag) {
		// エラー時のチャイム
		// chime配列は偶数バイトで作成しておくこと
		e = chime[chimeidx] | (chime[chimeidx + 1] << 8);
		e = e + 32768;
		e = e >> 8;
		e = e & 0xff;
		chimeidx += 2;
		if (chimeidx > (sizeof chime))
			chimeidx = 0;
		OC1RS = (PR2 + 1) * e / 256; // ch1:RP0出力
		OC2RS = (PR3 + 1) * e / 256; // ch2:RP1出力
	} else {
		// ch1は常にファイル#0を再生
		ch1 = waveform(0);
		ch1 = (0 == ch1) ? 128 : ch1; // ch1が0なら無音
		OC1RS = (PR2 + 1) * ch1 / 256; // ch1:RP0出力

		// ch2は、再生指示のあるものをファイル#2、#1、#0の順に判定していずれかを出力
		ch2 = waveform(2);
		if (0 != ch2) {
			// ファイル#2をRP1に出力
			OC2RS = (PR3 + 1) * ch2 / 256;
		} else {
			// ファイル#1か#0をRP1に出力
			ch2 = waveform(1);
			OC2RS = (0 != ch2) ? ((PR3 + 1) * ch2 / 256) : ((PR3 + 1) * ch1 / 256);
		}
	}
	_T4IF = 0; // 割り込みフラグクリア
}

/**
 * 波形作成
 * @param int  i: ハンドラ(fhandle)参照用添字
 * @return int 0:出力データなし その他:波形データ
 */
int waveform(int i) {
	unsigned int d;
	unsigned char wk1, wk2;

	if (1 != fhandle[i].buf[fhandle[i].currOut].status ||
			(!fhandle[i].playFlag && 0 == fhandle[i].repeatFlag)) {
		fhandle[i].buf[fhandle[i].currOut].status = 2;
		fhandle[i].currOut = (0 == fhandle[i].currOut) ? 1 : 0;
		return 0;
	}
	if (fhandle[i].buf[fhandle[i].currOut].outputptr >= (fhandle[i].buf[fhandle[i].currOut].datasize))
		wk1 = wk2 = 0x00;
	else {
		wk1 = fhandle[i].buf[fhandle[i].currOut].data[ fhandle[i].buf[fhandle[i].currOut].outputptr++];
		wk2 = (fhandle[i].buf[fhandle[i].currOut].outputptr >= (fhandle[i].buf[fhandle[i].currOut].datasize)) ?
				0x00 : fhandle[i].buf[fhandle[i].currOut].data[ fhandle[i].buf[fhandle[i].currOut].outputptr++];
	}

	if (fhandle[i].buf[fhandle[i].currOut].outputptr >= (fhandle[i].buf[fhandle[i].currOut].datasize)) {
		fhandle[i].buf[fhandle[i].currOut].status = 2;
		fhandle[i].currOut = (0 == fhandle[i].currOut) ? 1 : 0;
	}
	d = wk1 | (wk2 << 8);
	d = d + 32768;
	d = d >> 8;
	d = d & 0xff;
	return d;

}

/**
 * Wavファイルオープン
 * @param int  i ハンドラ(fhandle)参照用添字
 */
void wavopen(int i) {
	if (NULL == fhandle[i].fptr && (0x00 != fhandle[i].fname[0])) {
		fhandle[i].fptr = FSfopen(fhandle[i].fname, "r"); // ファイルオープン
		if (NULL == fhandle[i].fptr) {
			fhandle[i].fname[0] = 0x00; // ファイル名無効化(次からオープンしない)
			return;
		}

		// ヘッダ部分読み込み
		if (FSfread(&fhandle[i].whdr, 1, (size_t)sizeof (struct wavheader), fhandle[i].fptr)
				== (size_t)sizeof (struct wavheader)) {
			if (0 == strncmp(fhandle[i].whdr.datachid, "data", 4)) {
				if (0L != fhandle[i].whdr.chunkleng) {
					fhandle[i].remaining = fhandle[i].whdr.chunkleng;
					errorFlag = FALSE;
					return;
				}
			}
		}
		fhandleinit(i);
		errorFlag = TRUE;
	}
}

/**
 * Wavファイル波形部読み込み
 * @param int  i: ハンドラ(fhandle)参照用添字
 */
void wavread(int i) {
	unsigned long readsize;

	if (sdReadyFlag &&
			(!errorFlag) &&
			(NULL != fhandle[i].fptr) &&
			(1 != fhandle[i].buf[fhandle[i].nextRead].status)) {

		if (!fhandle[i].playFlag && 1 != fhandle[i].repeatFlag) {
			// 再生停止中
			fhandle[i].remaining = 0L; // 再スタートは最初から
			return;
		}
		if (0L == fhandle[i].remaining) {
			// 波形部を全て読み込んでいたら、波形部先頭に移動
			if (0 != FSfseek(fhandle[i].fptr, (long) sizeof (struct wavheader), SEEK_SET)) {
				errorFlag = TRUE;
				sdReadyFlag = FALSE; // 要リカバリ
				return;
			}
			fhandle[i].remaining = fhandle[i].whdr.chunkleng;
		}
		bhandleinit(i, fhandle[i].nextRead);
		readsize = (fhandle[i].remaining >= BUFSIZE) ? BUFSIZE : fhandle[i].remaining;

		// BUFSIZEバイトファイルリード
		fhandle[i].buf[fhandle[i].nextRead].datasize =
				(int) FSfread(fhandle[i].buf[fhandle[i].nextRead].data, 1, (size_t) readsize, fhandle[i].fptr);
		fhandle[i].remaining -= (unsigned long) fhandle[i].buf[fhandle[i].nextRead].datasize;
		fhandle[i].buf[fhandle[i].nextRead].status = 1;
		// 次回読み込みバッファ切り替え
		fhandle[i].nextRead = (0 == fhandle[i].nextRead) ? 1 : 0;
		if (1 == fhandle[i].repeatFlag && 0 == fhandle[i].remaining)
			fhandle[i].repeatFlag = 2;
	}
}

/**
 * CN入力変化割り込み(Mk144制御用)
 */
void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void) {
	__delay_ms(20);//チャタリング防止
	if (!PORTAbits.RA0) {
		// onになった
		Mk144Switch = !Mk144Switch;
	}
	_CNIF = 0; // 割り込みフラグクリア
}

/**
 * MK-144制御
 */
void mk144ctrl(void) {
	unsigned char folder;

	if (Mk144Switch != Mk144SwitchSave) {
		Mk144SwitchSave = Mk144Switch;
		if (Mk144SwitchSave) {
			mk144putcmd(0xEF); //停止
	 // mk-144のルートディレクトリはフォルダ1
		   //ロータリーコードスイッチが0、1の時はルートディレクトリ参照
			folder = (0 == sel.selector) ? 1 : sel.selector;
			folder += 240;
			mk144putcmd(folder); //フォルダ指定
			mk144putcmd(0x01); //ファイル1再生
			mk144putcmd(0xEC); //再生
		} else {
			mk144putcmd(0xEF); //停止
		}
	}
}

/**
 * MK-144向けコマンド送信
 * @param unsigned char cmd 送信文字
 */
void mk144putcmd(unsigned char cmd) {
	while (BusyUART1());
	U1TXREG = (unsigned int) cmd;
	__delay_ms(20);
}


[/c]

chime.h
エラー時にならすチャイムの音のWAVファイルの波形データ部を記述したファイルです。

PICでWav再生にある手順で作成しています。


回路等

  • ソース中のピンアサインに従って入出力を接続してください(^^;
  • 音声の出力(#4、#5)の出力はLM386などのオーディオ・パワーアンプに繋いでください。

趣味の部屋 スマホ/タブレットサイト 趣味の部屋 PCサイト