打印

CDROM控制器源码

[复制链接]
2299|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ledrgb|  楼主 | 2008-7-30 22:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
// ATAPI-CDROM 驱动程序 //
// //[龙图开发网: http://www.longtoo.com ]
// 这源码为ATAPI基本驱动程序,main()中只有 //
// Play功能。 //
// 本程序为共享版本,但不得用于商业性质。  //
//-------------------------------------------//
#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 //
// //[龙图开发网: http://www.longtoo.com ]

//------------------------------------------//
//用变量设置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 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; //未知错误 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)
{
InitCDROM(); TestUnitReady();
ReadTOC(0xAA);
ReadTOC(0x01);
PlayMSF();
ReadSub();//测试用 dmsec(1000);
while(1);
} void dmsec(unsigned int msec) //1ms延时 11.0592MHz /不是太精确
{
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; 在这开中断[龙图开发网: http://www.longtoo.com ]

} 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<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中断
} 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置回
dmsec(3); //延时[龙图开发网: http://www.longtoo.com ]
//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)
{
//---------------------------------
// 复位[龙图开发网: http://www.longtoo.com ]
//---------------------------------
DBL = 0xFF;
DBM = 0xFF;
RST = 0; //拉低RST,延时使CDROM复位
dmsec(100); //延时
RST = 1; //复位完成拉高RST
dmsec(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)
{
//---------------------------------
// 执行自身诊断[龙图开发网: http://www.longtoo.com ]

//---------------------------------
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++;
}

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

16

帖子

0

粉丝