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

📄 fei.pr~

📁 AVR单片机控制实现播放CD音频数据
💻 PR~
字号:

#include <mega16.h>
#include <delay.h>

#define A0 PA.5
#define A1 PA.4
#define A2 PA.3
#define CS0 PB.0
#define CS1 PA.2
#define WR PA.7
#define RD PA.6
#define RST PB.4
//#define CDCOM P0 //CDROM控制线
#define INTRQ PB.5//INTRQ
#define DBM PD //CDROM数据线高8位
#define DBL PC //CDROM数据线低8位
//------------------------------------------//
////
// P0.0--------------------------------P0.7 //
// A0 A1 A2 CS0 CS1 WR RD ACT //
////
//------------------------------------------//
//用变量设置P0的值,以方便对应于各寄存器的地址值
#define REG_Data 0xE0
#define REG_Err 0xE1 //Features
#define REG_Features 0xE1
#define REG_Sector 0xE2
#define REG_CyLow 0xE4
#define REG_CyHig 0xE5
#define REG_DriveHead 0xE6
#define REG_Status 0xE7 //Command
#define REG_Command 0xE7
unsigned char const ReadSubP[]={0x42,0x02,0x40,0x01,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadSub命令信息包
unsigned char const ReadTOCP[]={0x43,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadTOC命令信息包
unsigned char const PlayMSFP[]={0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //MSF播放命令信息包
unsigned int  PacketTemp[24]; //信息包暂存RAM,用写数据和读数据的暂存
unsigned char REGBL=0, REGBM=0; //用于暂存读取寄存器的值
unsigned char PacketSize; //用于保存CDROM定义的信息包长度,有12,16
unsigned char  CDStatusREG; //可位寻址变量保存CDROM的状态寄存器值 ; //可位寻址变量保存CDROM的状态寄存器值; //可位寻址变量保存CDROM的状态寄存器值
bit ERR = CDStatusREG^0; //错误       ;unsigned char ERR=CDStatusREG&c0x01
bit DRQ = CDStatusREG^3; //数据请求   ;unsigned char DRQ=CDStatusREG&0x08
bit DRDY = CDStatusREG^6; //设备就绪  ;unsigned char DRDY=CDStatusREG&0x40
bit BSY = CDStatusREG^7; //忙         ;unsigned char BSY=CDStatusREG&0x80
unsigned char bdata CDErr=0; //保存各种错误标识     ?
bit INITERR = CDErr^0; //初始化错误
bit TESTERR = CDErr^1; //CDROM自身诊断错误
bit UKERR = CDErr^2; //未知错误
unsigned char DEV; //选择驱动器时所用的参数
unsigned char AudioStatus; //当前的播放状态
unsigned char StartTrackNum; //开始曲目
unsigned char EndTrackNum; //结束曲目
unsigned char CurrentTrackNum; //当前曲目
unsigned char CurrentM, CurrentS, CurrentF; //当前MSF值
unsigned char StartM, StartS, StartF; //开始的MSF值
unsigned char EndM, EndS, EndF; //结束的MSF值 
void dmsec(unsigned int msec);
void RedREG(unsigned char REG);
void WriREG(unsigned char LSB, unsigned char MSB, unsigned char REG);
void SendPacket(unsigned char SkipDRQ);
void TestCD(void);
void ReadSub(void);
void ReadTOC(unsigned char Track);
void ResData(unsigned char Count);
void ReadStatus(void);
void InitCDROM(void);
void BSYWait(void);
//void INTRQWait(void);
void DRQWait(void);
void NDRQWait(void);
void LoadPacket(unsigned char code *RT);
void TestUnitReady(void);
//void PlayMSF(void);
void main(void){
	unsigned char CDCOM;
	InitCDROM(); 
	TestUnitReady();
	ReadTOC(0xAA);
	ReadTOC(0x01);
	PlayMSF();
	ReadSub();//测试用
	delay_ms(1000);
	while(1);
} 

//写寄存器
void WriREG(unsigned char LSB, unsigned char MSB, unsigned char REG){ 
	CDCOM = REG; //设要写的REG
	//EA=0;//程序中有中断程序时应先关中断
	A0=CDCOM&0xFE;
	A1=(CDCOM>>1)&0xFE;
	A2=(CDCOM>>2)&0xFE;
	CS0=(CDCOM>>3)&0xFE;
	CS1=(CDCOM>>4)&0xFE;
	WR=(CDCOM>>5)&0xFE;
	RD=(CDCOM>>6)&0xFE;
	RST=(CDCOM>>7)&0xFE;
	CS1 = 1;
	DBL = LSB;
	DBM = MSB; //写数据
	WR = 0;
	WR = 1; 
	CS1 = 0; //WD,CS1置回
	DBL = 0xFF;
	DBM = 0xFF;
	delay_ms(3); //延时
	//EA=1; 在这开中断
} //读寄存器
void RedREG(unsigned char REG){ 
	CDCOM = REG; //设要读的寄存器
	A0=CDCOM&0xFE;
	A1=(CDCOM>>1)&0xFE;
	A2=(CDCOM>>2)&0xFE;
	CS0=(CDCOM>>3)&0xFE;
	CS1=(CDCOM>>4)&0xFE;
	WR=(CDCOM>>5)&0xFE;
	RD=(CDCOM>>6)&0xFE;
	RST=(CDCOM>>7)&0xFE;
	
 	//EA=0;//程序中有中断程序时应先关中断
 	CS1 = 1; 
 	RD = 0; //开始读数据线
 	REGBL = DBL; //从数据线上读状态寄存器值
 	REGBM = DBM;
 	RD = 1; 
 	CS1 = 0; //RD,CS1置回
 	delay_ms(3); //延时
	//EA=1; 在这开中断
} 
void SendPacket(unsigned char SkipDRQ){ //Count向CDROM发送信息包的大小
	unsigned char TempCyc;
	if (!SkipDRQ) 
	NDRQWait();
	WriREG(PacketSize, 0xFF, REG_CyLow); //设CyLow,CyHig的值不应小于传输的数量否则PacketCommand时ERR出错
	WriREG(0x00, 0xFF, REG_CyHig); //
	WriREG(DEV, 0xFF, REG_DriveHead); //选择Device 0   ;选择哪个
	WriREG(0xA0,0xFF,REG_Command); //发送A0H,Packet命令,准备发送Packet
	DRQWait(); //注:有些命令可能返回没有就绪的错误,这里没做考虑
	for (TempCyc=0; Tempcyc<12; Tempcyc++)
	   {
		CDCOM = REG_Data; //设控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1
		//EA=0;//程序中有中断程序时应先关中断 
		A0=CDCOM&0xFE;
   		A1=(CDCOM>>1)&0xFE;
		A2=(CDCOM>>2)&0xFE;
   		CS0=(CDCOM>>3)&0xFE;
   		CS1=(CDCOM>>4)&0xFE;
   		WR=(CDCOM>>5)&0xFE;
		RD=(CDCOM>>6)&0xFE;
		RST=(CDCOM>>7)&0xFE;
		CS1 = 1;//这时CS1=1,CS0=0,A0-2=0,为选择数据寄存器Data Register
		DBL = PacketTemp[TempCyc*2];
   		DBM = PacketTemp[TempCyc*2+1]; //写信息包数据
   		WR = 0;
   		WR = 1; 
   		CS1 = 0; //WR,CS1置回
   		DBL = 0xFF;
   		DBM = 0xFF;
   		delay_ms(3); //延时
   		//EA=1; 在这开中断
    	}
	ReadStatus(); //返回当前状态
	//INTRQWait(); //等待CDROM中断
} 
void ResData(unsigned char Count){ //返回数据,Count为返回数据的多少
	unsigned char TempCyc;
	for (TempCyc=0; TempCyc<Count;Tempcyc++)
	{      
		CDCOM = REG_Data; //设控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1
		//EA=0;//程序中有中断程序时应先关中断
		CS1 = 1;//这时CS1=1,CS0=0,A0-2=0,为选择数据寄存器Data Register
		RD = 0; //开始读数据线
		PacketTemp[TempCyc*2] = DBL;
		PacketTemp[TempCyc*2+1] = DBM;
		RD = 1; 
		CS1 = 0; //WR,CS1置回
		delay_ms(3); //延时
   		//EA=1; 在这开中断 
	}
} 
void ReadStatus(void){ //读当前CDROM状态
	RedREG(REG_Status);//读状态寄存器
	CDStatusREG = REGBL; //放入可寻址位方便使用
}
void ReadTOC(unsigned char Track){
	unsigned char TempCyc = 0;
	LoadPacket(ReadTOCP); //暂存数据到RAM
	PacketTemp[6] = Track; //要读取的轨道,值为0H-63H,写AAH为返回开始区段值
	SendPacket(0); //向CDROM送信息包
	ResData(12);//返回数据4字节
	StartTrackNum = PacketTemp[2]; //读首曲目数字
	EndTrackNum = PacketTemp[3]; //读尾曲目数字
	if (Track == 0xAA){
		EndM = PacketTemp[9]; //读曲目的MSF值
		EndS = PacketTemp[10];
		EndF = PacketTemp[11];
	}
	else{
		StartM = PacketTemp[9]; 
		StartS = PacketTemp[10];
		StartF = PacketTemp[11]; 
	}
} 
void PlayMSF(void){
	LoadPacket(PlayMSFP); //暂存数据到RAM
	PacketTemp[3] = StartM; //写MSF值
	PacketTemp[4] = StartS;
	PacketTemp[5] = StartF;
	PacketTemp[6] = EndM;
	PacketTemp[7] = EndS;
	PacketTemp[8] = EndF;
	SendPacket(0); //向CDROM送信息包
} 
void ReadSub(void){
	LoadPacket(ReadSubP); //暂存数据到RAM
	SendPacket(0); //向CDROM送信息包
	ResData(12);//返回数据16字节
	AudioStatus = PacketTemp[1];
	CurrentTrackNum = PacketTemp[6];
	CurrentM = PacketTemp[9];
	CurrentS = PacketTemp[10];
	CurrentF = PacketTemp[11];
} //检查CDROM是否就绪
void TestUnitReady(void){
	unsigned char TempCyc;
	unsigned char TempS;
	for (TempCyc = 0; TempCyc < 12; TempCyc++)
	PacketTemp[TempCyc] = 0x00; //Packet for Test Unit Ready Command
	do{
		SendPacket(1); //因可能CDROM不在就绪状态所以跳过DRQ检测
		TempS = CDStatusREG & 0x89; //CDStatusREG & 0x89为判断ERR,DRQ,BSY中是否有1
	}
	while(TempS); //PacketCommand失败时认为CDROM没就绪,再次发送Test Unit Ready Command
} 
//初始化CDROM
void InitCDROM(void){
//---------------------------------
// 复位
//---------------------------------
	DBL = 0xFF;
	DBM = 0xFF;
	RST = 0; //拉低RST,延时使CDROM复位
	delay_ms(100); //延时
	RST = 1; //复位完成拉高RST
	delay_ms(10000); //延时
	//---------------------------------
	// 选择Device 0
	//---------------------------------
	//Drive/Head寄存器D4位控制设备的选取
	RedREG(REG_DriveHead); //读Drive/Head寄存器
	DEV = REGBL & 0xEF; //读出Drive/Head寄存器值并把D4位清零
	WriREG(DEV, 0xFF, REG_DriveHead); //把值写回Drive/Head寄存器
	//---------------------------------
	// 校验CylLow和CyHig寄存器
	//---------------------------------
	//CDROM正常复位后CylLow的值为14H,CylHig的值为EBH,不对是说明设备出错
	RedREG(REG_CyLow); //读CyLow寄存器
	if (REGBL == 0x14){
		RedREG(REG_CyHig); //读CyHig寄存器
		if (REGBL != 0xEB)INITERR = 1;
		
	}
	else{
		INITERR = 1;
	}
	if (!INITERR){
		//---------------------------------
		// 执行自身诊断
		//---------------------------------
		WriREG(0x90,0xFF,REG_Command); //写Command寄存器,90H为执行设备诊断
		BSYWait();
		RedREG(REG_Err); //读Error寄存器 
		if ((REGBL != 0x01) && (REGBL != 0x81))
		TESTERR = 1; //当返回值不等于01H或81H时则说明CDROM自身诊断未通过,这里只考虑Device0
		//---------------------------------
		// 使能数据包(Packer Command)功能
		// IDENTIFY PACKET DEVICE
		//---------------------------------
		WriREG(0xA1,0xFF,REG_Command); //写A1H,IDENTIFY PACKET DEVICE命令
		//INTRQWait(); //等待CDROM中断
		RedREG(REG_Data); //读一个字节的返回数据用于判断CDROM所定义的Packet长度
		REGBL = REGBL << 6;
		if (REGBL == 0x00)
		PacketSize = 6; //12byte 6word
		if (REGBL == 0x40)
		PacketSize = 8; //16byte 8word
		if (!PacketSize)
		UKERR = 1; //当不是这两个值是为未知错误
	}
}
 //检测忙状态
void BSYWait(void){
	do{
		ReadStatus();
	}
	while(BSY); 
}
 /*检测INTRQ引脚,CDROM中断
void INTRQWait(void) 
{ do
{
INTRQ = 1;
}
while(INTRQ);
} */
//检测DRQ是否为1,BSY=0
void DRQWait(void){
	do{
		BSYWait();
		DRQ = ~DRQ; 
	}
	while(DRQ); 
} 
//检测DRQ是否为0,BSY=0
void NDRQWait(void){
	do{
		BSYWait();
	}
	while(DRQ); 
} //数据包送暂存RAM
void LoadPacket(unsigned char code *RT){
	unsigned char TempCyc;
	for (TempCyc=0; TempCyc<12; TempCyc++) //数据包送暂存RAM
	{
		PacketTemp[TempCyc] = *RT;
		RT++;
	}
} 


 
              

⌨️ 快捷键说明

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