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

📄 demo.bak

📁 家里闲置的光驱又可以发挥一下余热了
💻 BAK
字号:
//-------------------------------------------//
//           ATAPI-CDROM 驱动程序            //
//                                           //
// 这源码为ATAPI基本驱动程序,main()中只有   //
// 几个基本功能。                            //
// 本程序为共享版本,但不得用于商业性质。   //
//                                           //
// 不提供任何无偿的技术支持。         //
// 使用或转载时请保留些版权信息。            //
// 更多升级版本请留意:                       //
//			主页:http://www.cdle.net            //
//      论坛:http://bbs.cdle.net            //
//                                           //
// 联系方式:pnzwzw@cdle.net                 //
//           pnzwzw@163.com                  //
//                                           //
//版权所有 http://www.cdle.net 2001-2004 明浩//
//-------------------------------------------//
#include <at89x51.h>

#define	A0	P0_0
#define	A1	P0_1
#define	A2	P0_2
#define	CS0	P0_3
#define	CS1	P0_4
#define	WR	P0_5
#define	RD	P0_6
#define RST	P0_7
#define CDCOM P0 //CDROM控制线
#define INTRQ	P3_7 //INTRQ
#define DBM	P2 //CDROM数据线高8位
#define DBL P1 //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
#define PLAYKey						P3_2
#define EJECTKey					P3_3
#define STOPKey						P3_5
#define NEXTKey						P3_4
#define PREVIOUSKey				P3_6
#define ERRLED						P3_7

unsigned char code ReadSubP[]={0x42,0x02,0x40,0x01,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadSub命令信息包
unsigned char code ReadTOCP[]={0x43,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadTOC命令信息包
unsigned char code PlayMSFP[]={0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //MSF播放命令信息包
unsigned char data PacketTemp[24]; //信息包暂存RAM,用写数据和读数据的暂存

unsigned char REGBL=0, REGBM=0; //用于暂存读取寄存器的值
unsigned char PacketSize; //用于保存CDROM定义的信息包长度,有12,16
unsigned char bdata CDStatusREG; //可位寻址变量保存CDROM的状态寄存器值
sbit ERR = CDStatusREG^0; //错误
sbit DRQ = CDStatusREG^3; //数据请求
sbit DRDY = CDStatusREG^6; //设备就绪
sbit BSY = CDStatusREG^7; //忙

unsigned char bdata CDErr=0; //保存各种错误标识
sbit INITERR = CDErr^0; //初始化错误
sbit TESTERR = CDErr^1;	//CDROM自身诊断错误
sbit UKERR = CDErr^2; //未知错误
sbit EJECTING = CDErr^3; //弹出
sbit CDOK = CDErr^4; //CD就绪
sbit PLAYING = CDErr^5;
sbit PAUSEING = CDErr^6;
sbit STOPING = CDErr^7;

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 Eject(unsigned char EJ);
void Pause(unsigned char PR);
void Next(unsigned char NP);
void Stop(void);

void main(void)
{
	InitCDROM();

	do
		{
			if (!PLAYKey) //play or pause 要求CD就绪才响应
				{
					if (CDOK)
						{
							dmsec(20); //延时20ms防抖动
							if (!PLAYKey)
								{
									if (PLAYING) //CD正在播放中的处理
										{
											if (PAUSEING) //继续播放
												{
													Pause(0);
													PAUSEING = 0;
												}
											else //暂停播放
												{
													Pause(1);
													PAUSEING = 1;
												}
										}
									else //CD就绪按play后播放
										{
											ReadTOC(CurrentTrackNum); //读当前TOC
											ReadTOC(0xAA);
											PlayMSF(); //播放
											PLAYING = 1; //标识
										}
								}
						}
					dmsec(2000);
				}

			if (!STOPKey) //当CD在播放中
				{
					if (PLAYING)
						{
							dmsec(20);
							if (!STOPKey)
								{
									Pause(1); //暂停
									Stop(); 
									PLAYING = 0;
									PAUSEING = 0;
								}
						}
					dmsec(2000);
				}

			if (!NEXTKey)
				{
					if (PLAYING)
						{
							dmsec(20);
							if (!NEXTKey)
								{
									Next(1);
								}
						}
					dmsec(2000);
				}

			if (!PREVIOUSKey)
				{
					if (PLAYING)
						{
							dmsec(20);
							if (!PREVIOUSKey)
								{
									Next(0);
								}
						}
					dmsec(2000);
				}

			if (!EJECTKey)
				{
					dmsec(20);
					if (!EJECTKey)
						{
							if (EJECTING)
								{
									Eject(3); //装载
									EJECTING = 0;
									dmsec(3000);
									InitCDROM();
								}
							else
								{
									Eject(2);
									EJECTING = 1;
									CDOK = 0;
									PAUSEING = 0;
									PLAYING = 0;
									STOPING = 0;
								}
						}
					dmsec(2000);
				}

		ReadStatus();//读状态
		ERRLED = ~ERR; //ERR指示
		}
	while(1);
}

//1ms延时 11.0592MHz /不是太精确
void dmsec(unsigned int msec) 
{
	unsigned int TempCyc;
	while(msec--)
		{
			for(TempCyc=0; TempCyc<125; TempCyc++);
		}
}

//写寄存器
void WriREG(unsigned char LSB, unsigned char MSB, unsigned char REG)
{
	CDCOM = REG; //设要写的REG
	//EA=0;//程序中有中断程序时应先关中断
	CS1 = 1;
	DBL = LSB;
	DBM = MSB; //写数据
	WR = 0;
	WR = 1; 
	CS1 = 0; //WD,CS1置回
	DBL = 0xFF;
	DBM = 0xFF;
	dmsec(3); //延时
	//EA=1; 在这开中断
}

//读寄存器
void RedREG(unsigned char REG)
{
	CDCOM = REG; //设要读的寄存器
	//EA=0;//程序中有中断程序时应先关中断
	CS1 = 1; 
	RD = 0; //开始读数据线
	REGBL = DBL; //从数据线上读状态寄存器值
	REGBM = DBM;
	RD = 1; 
	CS1 = 0; //RD,CS1置回
	dmsec(3); //延时
	//EA=1; 在这开中断
}

//Count向CDROM发送信息包的大小
void SendPacket(unsigned char SkipDRQ) 
{
	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<PacketSize; 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
			DBL = PacketTemp[TempCyc*2];
			DBM = PacketTemp[TempCyc*2+1]; //写信息包数据
			WR = 0;
			WR = 1; 
			CS1 = 0; //WR,CS1置回
			DBL = 0xFF;
			DBM = 0xFF;
			dmsec(3); //延时
			//EA=1; 在这开中断
		}
	ReadStatus(); //返回当前状态
	//INTRQWait(); //等待CDROM中断
}

//返回数据,Count为返回数据的多少
void ResData(unsigned char 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置回
			dmsec(3); //延时
			//EA=1; 在这开中断	
		}

}

//读当前CDROM状态
void ReadStatus(void)
{
	RedREG(REG_Status);//读状态寄存器
	CDStatusREG = REGBL; //放入可寻址位方便使用
}

//读曲目TOC
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];			
		}
}

//播放MSF
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 Eject(unsigned char EJ)
{
	LoadPacket(PlayMSFP); //暂存数据到RAM
	PacketTemp[0] = 0x1B; //START/STOP UNIT Command字节
	PacketTemp[4] = EJ; //EJ=0为停止,1为开始并读次信道,2为弹出托盘,3为装载光盘
	SendPacket(1); //向CDROM送信息包
}

//暂停或继续
void Pause(unsigned char PR)
{
	LoadPacket(PlayMSFP); //暂存数据到RAM
	PacketTemp[0] = 0x4B; //PAUSE/RESUME Command
	PacketTemp[8] = ~PR; //PR为1时暂停
	SendPacket(0); //向CDROM送信息包
}

//停止
void Stop(void)
{
	LoadPacket(PlayMSFP); //暂存数据到RAM
	PacketTemp[0] = 0x4E; //STOP/SCAN Command
	SendPacket(0); //向CDROM送信息包
}

//前进或后退
void Next(unsigned char NP)
{
	ReadSub(); //读当前曲目
	if (NP) //计算
		NP = CurrentTrackNum + 1;
	else
		NP = CurrentTrackNum - 1;
	if (NP < StartTrackNum)
		NP = StartTrackNum;
	if (NP > EndTrackNum)
		NP = EndTrackNum;
	ReadTOC(NP); //读下一首或前一首的TOC
	PlayMSF(); //播放
}

//读次信道信息
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复位
	dmsec(100); //延时
	RST = 1; //复位完成拉高RST
	dmsec(5000); //延时

//---------------------------------
// 选择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; //当不是这两个值是为未知错误
		}

	TestUnitReady();
	ERRLED = 0;
	ReadSub(); //读信息
	BSYWait();
	ERRLED = 1;
	if (CurrentTrackNum==0x01) //当前曲目应等于1
		CDOK = 1;
	else
		CDOK = 0;
}

//检测忙状态
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 + -