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