⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3player2_c.txt

📁 在高档AVR单片机ATmega8上实现MP3播放功能
💻 TXT
📖 第 1 页 / 共 3 页
字号:
				if (--PlayMusic == 0){
					PlayMusic = MusicCount;
				}
			}
			Cluster = 0;	// 妒の呵介から
		} else {	// FF or その妒の浩栏姜位
			PlayMusic++;	// 肌の妒
			Cluster = 0;
		}
		if (BattVolt < BATT_START){
			beep(1, BEEP_LOW);	// 弹瓢排暗笆布になったら妒粗に焚桂不
		}
	}
}


//*********************************************************
//	スイッチが澄悸に庶されるまで略つ
//*********************************************************
void switch_wait(void){

	sei();
	for (;;) {
		WDR;
		SLEEP;
		SLEEP;
		if (!(SwitchFlag & ((1<<SW_FF)|(1<<SW_REW)|(1<<SW_STOP)))){
			SLEEP;
			SLEEP;
			if (!(SwitchFlag & ((1<<SW_FF)|(1<<SW_REW)|(1<<SW_STOP)))){
				break;
			}
		}
	}
}


//*********************************************************
//	MMC/SDカ〖ドの介袋步
//*********************************************************
uchar InitCard(void){
	uchar	c;

	outp(0x52, SPCR);	// SPIマスタ, CPOL=0, クロック 8MHz/64=125kHz
	sbi(PORTB, SPI_CS);	// CS=H

	// MMC/SD SPIモ〖ド败乖涟のクロック流慨
	for (c=0; c < 10; c++){
		SPI_in();
	}

	// SPIモ〖ド败乖コマンド
	cbi(PORTB, SPI_CS);		// CS=L
	c = SPI_command(0, 0);
	while ((c != 1)&&(c != 0xFF)){
		SLEEP;
		c = SPI_command(0, 0);
	}
	while (c == 1){
		c = SPI_command(1, 0);
	}
	sbi(PORTB, SPI_CS);	// CS=H

	outp(0x50, SPCR);	// SPIマスタ, CPOL=0, クロック 8MHz/4=2MHz
	sbi(SPSR, SPI2X);	// クロックを2擒 4MHz

	return c;
}


//*********************************************************
//	VFAT攫鼠粕み艰り
//*********************************************************
uchar read_VFAT_info(void){
	ulong	sec;
	uint	bpb;
	uint	n;

	// VFAT攫鼠粕み艰り。セクタ墓は 512bytesで疯め虑ちしている
	read_32(446);										// MBR粕み哈み
	bpb = (uint)DataBuff[8] + ((uint)DataBuff[9]<<8);	// BPB黎片セクタ
	read_32((ulong)bpb * 512);							// 粕み哈み
	n = (uint)DataBuff[11] + ((uint)DataBuff[12] << 8);	// セクタ墓
	if (n != 512){
		return 2;	// 1セクタが 512bytesでない
	}
	SectorsPerCluster = DataBuff[13];		// クラスタあたりのセクタ眶
	FATstart = bpb + (uint)DataBuff[14]
		+ ((uint)DataBuff[15] << 8);		// 徒腆セクタ眶
	RootDirEntriesCount = (uint)DataBuff[17]
		+ ((uint)DataBuff[18] << 8);		// ル〖トディレクトリエントリ眶
	n = (uint)DataBuff[22] + ((uint)DataBuff[23] << 8);	// FATのセクタ眶
	if (n == 0){
		return 1;	// FAT32らしい
	}
	DIRstart = (uint)FATstart + (uint)DataBuff[16] * n;	// FATの眶∵セクタ眶
	n = RootDirEntriesCount / 16;	// ル〖トディレクトリに涩妥なセクタ眶
	if (RootDirEntriesCount % 16){
		n++;	// 前のため、途りが叫たら磊り惧げ。奶撅は稍妥だと蛔うが
	}
	DataStart = (ulong)DIRstart + (ulong)n;		// デ〖タ呈羌挝拌

	sec = (ulong)DataBuff[19] + ((ulong)DataBuff[20] << 8);	// 另セクタ眶
	if (sec == 0){
		read_32((ulong)bpb * 512 + 32);		// 粕み哈み
		sec = (ulong)DataBuff[0] + ((ulong)DataBuff[1] << 8)
			+ ((ulong)DataBuff[2] << 16) + ((ulong)DataBuff[3] << 24);
	}
	sec -= FATstart;
	sec /= SectorsPerCluster;
	if (sec >= 0x1000){
		FATtype = 1;	// FAT16
	} else {
		FATtype = 0;	// FAT12
	}

	return 0;
}


//*********************************************************
//	MP3ファイルを淋す
//	苞眶¨
//		num	この眶だけ斧つけたら提る
//		この眶笆布であってもディレクトリエントリを链て拇べ姜わったら提る
//	提り猛¨
//		斧つけた眶
//		DataBuff[0×31]	呵稿に斧つかった MP3のディレクトリ攫鼠
//*********************************************************
uint search_MP3(uint num){
	uint	ent;
	ulong	sec;
	uchar	i, j;
	uint	n;

	n = 0;
	sec = (ulong)DIRstart * 512;
	for (ent = 0; ent < RootDirEntriesCount; ){
		if (SPI_read_open(sec))	return n;
		for (i = 0; i < 16; i++){
			for (j = 0; j < 32; j++){
				DataBuff[j] = SPI_in();
			}
			if (DataBuff[0] == 0)	break;	// 踏蝗脱挝拌浮叫
			if (((DataBuff[26] != 0)||(DataBuff[27] != 0))&&	// クラスタ戎规
				(DataBuff[0] != 0xE5)&&						// 猴近マ〖ク
				(!(DataBuff[11] & 0x18))&&					// 奶撅ファイル
				(DataBuff[8]=='M')&&(DataBuff[9]=='P')&&(DataBuff[10]=='3')){
															// 橙磨灰MP3
				n++;
				if (--num == 0)	break;
			}
			ent++;
		}
		for (++i; i < 16; i++){
			for (j = 0; j < 32; j++){
				SPI_in();	// セクタ尸の荒りを粕み嘉て
			}
		}
		SPI_read_close();
		if (DataBuff[0] == 0)	break;	// 踏蝗脱挝拌浮叫
		if (num == 0)	break;
		sec += 512;	// 肌のセクタ
	}
	return n;
}


//****************************************
//	MP3ファイルを浩栏
//	fn:		妒戎规
//	clst:	遍琳倡幌クラスタ。==0 の眷圭は呵介から
//	remainsec: 浩栏デ〖タ荒りセクタ眶
//****************************************
char play_music(uint fn, uint clst, long remainsec){
	ulong	sec;
	uint	remain;
	uint	cn;
	uint	i;

	if (fn != search_MP3(fn)){
		return -1;	// 妒が痰い
	}

	MusicSize = (ulong)DataBuff[28] + ((ulong)DataBuff[29]<<8)
			  + ((ulong)DataBuff[30]<<16) + ((ulong)DataBuff[31]<<24);

	if (clst){
		// 庞面から浩栏
		Cluster = clst;
		RemainSec = remainsec;
		remain = MusicSize - (remainsec * 512);
	} else {
		// 呵介から浩栏
		Cluster = (uint)DataBuff[26] + ((uint)DataBuff[27] << 8);
		RemainSec = MusicSize / 512;
		remain = MusicSize % 512;
	}

	if ((Cluster == 0xFFFF)||(Cluster < 2)){
		return -2;	// クラスタ佰撅
	}

	// 肌のクラスタを拇べておく
	NextCluster = next_cluster(Cluster, 0, 0);

	StopSw = 0;
	RewSw = 0;
	FfSw = 0;

	cn = SectorsPerCluster;
	sec = (((ulong)Cluster - 2) * (ulong)SectorsPerCluster + DataStart)	* 512;

	MP3_init();
	Timer = 100;	// READYタイマ〖セット

	while (RemainSec > 0){
		uchar	data;
		char	bit;

		if (SPI_read_open(sec))	return -2;
		cli();				// 充哈み敦贿
		SPI_out(0xFF);		// 1byte誊のクロック流叫 & WAIT

		for (i = 0; i < 512; i++){

			while (!(inp(PIND)&(1<<MP3_DREQ))){	// VS1001 BUSYチェック

				WDR;			// ウォッチドッグタイマ〖リセット
				Timer = 100;	// READYタイマセット

				if (NextCluster == 0){
					// 肌のクラスタを拇べる
					NextCluster = next_cluster(Cluster, sec, i);
				} else {
					sei();	// 充り哈み钓材
					SLEEP;
					cli();	// 充哈み敦贿
				}
			}

			data = inp(SPDR);
			outp(0xFF, SPDR);	// SD/MMCカ〖ドへ肌のデ〖タリクエスト

			if (data & 0x80){
				sbi(PORTD, MP3_SI);
			} else {
				cbi(PORTD, MP3_SI);
			}
			sbi(PORTD, MP3_BSYNC);	// BSYNC = H
			sbi(PORTD, MP3_DCLK);
			data <<= 1;
			cbi(PORTD, MP3_DCLK);
			cbi(PORTD, MP3_BSYNC);	// BSYNC = L

			for (bit = 0; bit < 7; bit++){
				if (data & 0x80){
					sbi(PORTD, MP3_SI);
				} else {
					cbi(PORTD, MP3_SI);
				}
				sbi(PORTD, MP3_DCLK);
				data <<= 1;
				cbi(PORTD, MP3_DCLK);
			}
		}
		sei();	// 充り哈み钓材
		SPI_read_close();

		--RemainSec;
		
		if (--cn > 0){
			sec += 512;	// 肌のセクタ

			if (Debug && (cn == 1)){
				uint n;
				n = BattVolt;
				WriteHex(n>>8);
				WriteHex(n);
				WriteCom(' ');
				WriteHex(Cluster>>8);
				WriteHex(Cluster);
				WriteCom('\n');
			}
		} else {
			// 肌のクラスタ
			if (NextCluster == 0){
				Cluster = next_cluster(Cluster, 0, 0);
			} else {
				Cluster = NextCluster;
				NextCluster = 0;
			}

			if ((Cluster == 0xFFFF)||(Cluster < 2)){
				// 佰撅クラスタが浮叫されたので动扩姜位
				remain = 0;
				break;
			}

			sec = (((ulong)Cluster - 2) * (ulong)SectorsPerCluster
				   + DataStart) * 512;
			cn = SectorsPerCluster;

		}

		check_batt();	// バッテリ〖チェック

		if (Timer == 0){	// READYタイムアウトしたら
			if (NoBusyRetry > 0){	// リトライしてもダメなら
				beep(1, BEEP_LOW);	// 你不ビ〖プ1搀
				NoBusyRetry = 0;
				FfSw = 0;
				return 2;		// FF胺いで姜位 ⅹ 肌の妒へ
			} else {
				NoBusyRetry = 1;
				RewSw = 0;
				return 3;		// REW胺いで姜位 ⅹ その妒の呵介からリトライ
			}
		}

		// STOP, FFボタンチェック
		if (StopSw > 2){
			beep(1, BEEP_HIGH);
			NoBusyRetry = 0;
			return 1;
		} else if (FfSw > 2){
			beep(1, BEEP_HIGH);
			NoBusyRetry = 0;
			return 2;
		} else if (RewSw > 2){
			beep(1, BEEP_HIGH);
			NoBusyRetry = 0;
			return 3;
		}
	}

	NoBusyRetry = 0;

	// 1セクタ(512bytes)踏塔の尸を浩栏
	if ((remain > 0)&&(remain < 512)){
		uchar	data;
		char	bit;

		if (SPI_read_open(sec))	return -2;
		cli();				// 充哈み敦贿
		SPI_out(0xFF);		// 1byte誊のクロック流叫□WAIT

		for (i = 0; i < 512; i++){
			data = inp(SPDR);
			outp(0xFF, SPDR);
			if (remain-- > 0){
				while (!(inp(PIND)&(1<<MP3_DREQ))){
					// VS1001 BUSY
					WDR;		// ウォッチドッグタイマクリア
					sei();			// 充り哈み钓材
					SLEEP;
					cli();			// 充哈み敦贿
				}
				sbi(PORTD, MP3_BSYNC);	// BSYNC = H
				for (bit=0; bit<8; bit++){
					if (data & 0x80){
						sbi(PORTD, MP3_SI);
					} else {
						cbi(PORTD, MP3_SI);
					}
					sbi(PORTD, MP3_DCLK);
					data <<= 1;
					cbi(PORTD, MP3_DCLK);
					cbi(PORTD, MP3_BSYNC);	// BSYNC = L
				}
			}
		}

		sei();	// 充り哈み钓材
		SPI_read_close();
	}

	return 0;
}


//****************************************
//	肌のクラスタを滇める
//****************************************
uint next_cluster(uint c, ulong sec, uint remain){
	ulong	addr;
	uint	data;
	ulong	fatadr;
	uint	i;

	if (FATtype == 0){
		// FAT12
		addr = (ulong)FATstart * 512 + (ulong)c + (c >> 1);
		if ((addr & 511) == 511){
			if (sec != 0){
				// 粕み哈みオ〖プン面なら粕み嘉て
				for (i = remain; i < 512; i++)	SPI_in();
				SPI_read_close();

				data = read_word(addr) & 0x00FF;
				data |= ((read_word(addr+1) & 0x00FF) << 8);

				// 浩刨オ〖プン、笆涟の疤弥まで粕み嘉て
				if (SPI_read_open(sec))	return 0;
				SPI_in();
				for (i = 0; i < remain; i++)	SPI_in();
			} else {
				// セクタをまたぐ
				data = read_word(addr) & 0x00FF;
				data |= ((read_word(addr+1) & 0x00FF) << 8);
			}
		} else {
			fatadr = addr & 0xFFFFFE00;
			if ((sec != 0)&&(fatadr != FatCacheAddr)){
				// 粕み哈みオ〖プン面で FATバッファ痰跟なら粕み嘉て
				for (i = remain; i < 512; i++)	SPI_in();
				SPI_read_close();

				data = read_word(addr);

				// 浩刨オ〖プン、笆涟の疤弥まで粕み嘉て
				if (SPI_read_open(sec))	return 0xFFFF;
				SPI_in();
				for (i = 0; i < remain; i++)	SPI_in();
			} else {
				data = read_word(addr);
			}
		}
		if (c & 1){
			c = data >> 4;
		} else {
			c = data & 0x0fff;
		}
		if (c >= 0x0ff8)	c = 0xFFFF;
	} else {
		// FAT16
		addr = (ulong)FATstart * 512 + (ulong)c * 2;
		fatadr = addr & 0xFFFFFE00;
		if ((sec != 0)&&(fatadr != FatCacheAddr)){
			// 粕み哈みオ〖プン面で FATバッファ痰跟なら粕み嘉て
			for (i = remain; i < 512; i++)	SPI_in();
			SPI_read_close();

			c = read_word(addr);

			// 浩刨オ〖プン、笆涟の疤弥まで粕み嘉て
			if (SPI_read_open(sec))	return 0;
			SPI_in();
			for (i = 0; i < remain; i++)	SPI_in();
		} else {
			c = read_word(addr);
		}
		if (c >= 0xFFF8)	c = 0xFFFF;
	}

	return c;
}


//****************************************
//	MMC/SDカ〖ドから 2byteを粕む
//	セクタ董肠のアクセスはできないので
//	惧疤供镍で雇胃すること
//****************************************
uint read_word(ulong addr){
	uint	w;
	uint	b;
	uchar	*p;

	b = addr & 511;
	addr &= 0xFFFFFE00;

	if (addr != FatCacheAddr){
		if (SPI_read_open(addr))	return 0;
		for (p = FatCache; p < (FatCache + 512); ){
			*p++ = SPI_in();
		}
		SPI_read_close();
		FatCacheAddr = addr;
	}

	w = (uint)FatCache[b++];
	w |= ((uint)FatCache[b] << 8);

	return w;
}


//*******************************************************
//	バッテリ〖排暗を拇べ、你すぎればシャットダウンする
//*******************************************************
int check_batt(void){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -