?? demo.bak
字號(hào):
//-------------------------------------------//
// ATAPI-CDROM 驅(qū)動(dòng)程序 //
// //
// 這源碼為ATAPI基本驅(qū)動(dòng)程序,main()中只有 //
// 幾個(gè)基本功能。 //
// 本程序?yàn)楣蚕戆姹荆坏糜糜谏虡I(yè)性質(zhì)。 //
// //
// 不提供任何無(wú)償?shù)募夹g(shù)支持。 //
// 使用或轉(zhuǎn)載時(shí)請(qǐng)保留些版權(quán)信息。 //
// 更多升級(jí)版本請(qǐng)留意: //
// 主頁(yè):http://www.cdle.net //
// 論壇:http://bbs.cdle.net //
// //
// 聯(lián)系方式:pnzwzw@cdle.net //
// pnzwzw@163.com //
// //
//版權(quán)所有 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數(shù)據(jù)線高8位
#define DBL P1 //CDROM數(shù)據(jù)線低8位
//------------------------------------------//
// //
// P0.0--------------------------------P0.7 //
// A0 A1 A2 CS0 CS1 WR RD ACT //
// //
//------------------------------------------//
//用變量設(shè)置P0的值,以方便對(duì)應(yīng)于各寄存器的地址值
#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,用寫數(shù)據(jù)和讀數(shù)據(jù)的暫存
unsigned char REGBL=0, REGBM=0; //用于暫存讀取寄存器的值
unsigned char PacketSize; //用于保存CDROM定義的信息包長(zhǎng)度,有12,16
unsigned char bdata CDStatusREG; //可位尋址變量保存CDROM的狀態(tài)寄存器值
sbit ERR = CDStatusREG^0; //錯(cuò)誤
sbit DRQ = CDStatusREG^3; //數(shù)據(jù)請(qǐng)求
sbit DRDY = CDStatusREG^6; //設(shè)備就緒
sbit BSY = CDStatusREG^7; //忙
unsigned char bdata CDErr=0; //保存各種錯(cuò)誤標(biāo)識(shí)
sbit INITERR = CDErr^0; //初始化錯(cuò)誤
sbit TESTERR = CDErr^1; //CDROM自身診斷錯(cuò)誤
sbit UKERR = CDErr^2; //未知錯(cuò)誤
sbit EJECTING = CDErr^3; //彈出
sbit CDOK = CDErr^4; //CD就緒
sbit PLAYING = CDErr^5;
sbit PAUSEING = CDErr^6;
sbit STOPING = CDErr^7;
unsigned char DEV; //選擇驅(qū)動(dòng)器時(shí)所用的參數(shù)
unsigned char AudioStatus; //當(dāng)前的播放狀態(tài)
unsigned char StartTrackNum; //開始曲目
unsigned char EndTrackNum; //結(jié)束曲目
unsigned char CurrentTrackNum; //當(dāng)前曲目
unsigned char CurrentM, CurrentS, CurrentF; //當(dāng)前MSF值
unsigned char StartM, StartS, StartF; //開始的MSF值
unsigned char EndM, EndS, EndF; //結(jié)束的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就緒才響應(yīng)
{
if (CDOK)
{
dmsec(20); //延時(shí)20ms防抖動(dòng)
if (!PLAYKey)
{
if (PLAYING) //CD正在播放中的處理
{
if (PAUSEING) //繼續(xù)播放
{
Pause(0);
PAUSEING = 0;
}
else //暫停播放
{
Pause(1);
PAUSEING = 1;
}
}
else //CD就緒按play后播放
{
ReadTOC(CurrentTrackNum); //讀當(dāng)前TOC
ReadTOC(0xAA);
PlayMSF(); //播放
PLAYING = 1; //標(biāo)識(shí)
}
}
}
dmsec(2000);
}
if (!STOPKey) //當(dāng)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();//讀狀態(tài)
ERRLED = ~ERR; //ERR指示
}
while(1);
}
//1ms延時(shí) 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; //設(shè)要寫的REG
//EA=0;//程序中有中斷程序時(shí)應(yīng)先關(guān)中斷
CS1 = 1;
DBL = LSB;
DBM = MSB; //寫數(shù)據(jù)
WR = 0;
WR = 1;
CS1 = 0; //WD,CS1置回
DBL = 0xFF;
DBM = 0xFF;
dmsec(3); //延時(shí)
//EA=1; 在這開中斷
}
//讀寄存器
void RedREG(unsigned char REG)
{
CDCOM = REG; //設(shè)要讀的寄存器
//EA=0;//程序中有中斷程序時(shí)應(yīng)先關(guān)中斷
CS1 = 1;
RD = 0; //開始讀數(shù)據(jù)線
REGBL = DBL; //從數(shù)據(jù)線上讀狀態(tài)寄存器值
REGBM = DBM;
RD = 1;
CS1 = 0; //RD,CS1置回
dmsec(3); //延時(shí)
//EA=1; 在這開中斷
}
//Count向CDROM發(fā)送信息包的大小
void SendPacket(unsigned char SkipDRQ)
{
unsigned char TempCyc;
if (!SkipDRQ)
NDRQWait();
WriREG(PacketSize, 0xFF, REG_CyLow); //設(shè)CyLow,CyHig的值不應(yīng)小于傳輸?shù)臄?shù)量否則PacketCommand時(shí)ERR出錯(cuò)
WriREG(0x00, 0xFF, REG_CyHig); //
WriREG(DEV, 0xFF, REG_DriveHead); //選擇Device 0
WriREG(0xA0,0xFF,REG_Command); //發(fā)送A0H,Packet命令,準(zhǔn)備發(fā)送Packet
DRQWait(); //注:有些命令可能返回沒有就緒的錯(cuò)誤,這里沒做考慮
for (TempCyc=0; TempCyc<PacketSize; TempCyc++)
{
CDCOM = REG_Data; //設(shè)控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1
//EA=0;//程序中有中斷程序時(shí)應(yīng)先關(guān)中斷
CS1 = 1; //這時(shí)CS1=1,CS0=0,A0-2=0,為選擇數(shù)據(jù)寄存器Data Register
DBL = PacketTemp[TempCyc*2];
DBM = PacketTemp[TempCyc*2+1]; //寫信息包數(shù)據(jù)
WR = 0;
WR = 1;
CS1 = 0; //WR,CS1置回
DBL = 0xFF;
DBM = 0xFF;
dmsec(3); //延時(shí)
//EA=1; 在這開中斷
}
ReadStatus(); //返回當(dāng)前狀態(tài)
//INTRQWait(); //等待CDROM中斷
}
//返回?cái)?shù)據(jù),Count為返回?cái)?shù)據(jù)的多少
void ResData(unsigned char Count)
{
unsigned char TempCyc;
for (TempCyc=0; TempCyc<Count; TempCyc++)
{
CDCOM = REG_Data; //設(shè)控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1
//EA=0;//程序中有中斷程序時(shí)應(yīng)先關(guān)中斷
CS1 = 1; //這時(shí)CS1=1,CS0=0,A0-2=0,為選擇數(shù)據(jù)寄存器Data Register
RD = 0; //開始讀數(shù)據(jù)線
PacketTemp[TempCyc*2] = DBL;
PacketTemp[TempCyc*2+1] = DBM;
RD = 1;
CS1 = 0; //WR,CS1置回
dmsec(3); //延時(shí)
//EA=1; 在這開中斷
}
}
//讀當(dāng)前CDROM狀態(tài)
void ReadStatus(void)
{
RedREG(REG_Status);//讀狀態(tài)寄存器
CDStatusREG = REGBL; //放入可尋址位方便使用
}
//讀曲目TOC
void ReadTOC(unsigned char Track)
{
unsigned char TempCyc = 0;
LoadPacket(ReadTOCP); //暫存數(shù)據(jù)到RAM
PacketTemp[6] = Track; //要讀取的軌道,值為0H-63H,寫AAH為返回開始區(qū)段值
SendPacket(0); //向CDROM送信息包
ResData(12);//返回?cái)?shù)據(jù)4字節(jié)
StartTrackNum = PacketTemp[2]; //讀首曲目數(shù)字
EndTrackNum = PacketTemp[3]; //讀尾曲目數(shù)字
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); //暫存數(shù)據(jù)到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); //暫存數(shù)據(jù)到RAM
PacketTemp[0] = 0x1B; //START/STOP UNIT Command字節(jié)
PacketTemp[4] = EJ; //EJ=0為停止,1為開始并讀次信道,2為彈出托盤,3為裝載光盤
SendPacket(1); //向CDROM送信息包
}
//暫停或繼續(xù)
void Pause(unsigned char PR)
{
LoadPacket(PlayMSFP); //暫存數(shù)據(jù)到RAM
PacketTemp[0] = 0x4B; //PAUSE/RESUME Command
PacketTemp[8] = ~PR; //PR為1時(shí)暫停
SendPacket(0); //向CDROM送信息包
}
//停止
void Stop(void)
{
LoadPacket(PlayMSFP); //暫存數(shù)據(jù)到RAM
PacketTemp[0] = 0x4E; //STOP/SCAN Command
SendPacket(0); //向CDROM送信息包
}
//前進(jìn)或后退
void Next(unsigned char NP)
{
ReadSub(); //讀當(dāng)前曲目
if (NP) //計(jì)算
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); //暫存數(shù)據(jù)到RAM
SendPacket(0); //向CDROM送信息包
ResData(12);//返回?cái)?shù)據(jù)16字節(jié)
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不在就緒狀態(tài)所以跳過(guò)DRQ檢測(cè)
TempS = CDStatusREG & 0x89; //CDStatusREG & 0x89為判斷ERR,DRQ,BSY中是否有1
}
while(TempS); //PacketCommand失敗時(shí)認(rèn)為CDROM沒就緒,再次發(fā)送Test Unit Ready Command
}
//初始化CDROM
void InitCDROM(void)
{
//---------------------------------
// 復(fù)位
//---------------------------------
DBL = 0xFF;
DBM = 0xFF;
RST = 0; //拉低RST,延時(shí)使CDROM復(fù)位
dmsec(100); //延時(shí)
RST = 1; //復(fù)位完成拉高RST
dmsec(5000); //延時(shí)
//---------------------------------
// 選擇Device 0
//---------------------------------
//Drive/Head寄存器D4位控制設(shè)備的選取
RedREG(REG_DriveHead); //讀Drive/Head寄存器
DEV = REGBL & 0xEF; //讀出Drive/Head寄存器值并把D4位清零
WriREG(DEV, 0xFF, REG_DriveHead); //把值寫回Drive/Head寄存器
//---------------------------------
// 校驗(yàn)CylLow和CyHig寄存器
//---------------------------------
//CDROM正常復(fù)位后CylLow的值為14H,CylHig的值為EBH,不對(duì)是說(shuō)明設(shè)備出錯(cuò)
RedREG(REG_CyLow); //讀CyLow寄存器
if (REGBL == 0x14)
{
RedREG(REG_CyHig); //讀CyHig寄存器
if (REGBL != 0xEB)
INITERR = 1;
}
else
{
INITERR = 1;
}
if (!INITERR)
{
//---------------------------------
// 執(zhí)行自身診斷
//---------------------------------
WriREG(0x90,0xFF,REG_Command); //寫Command寄存器,90H為執(zhí)行設(shè)備診斷
BSYWait();
RedREG(REG_Err); //讀Error寄存器
if ((REGBL != 0x01) && (REGBL != 0x81))
TESTERR = 1; //當(dāng)返回值不等于01H或81H時(shí)則說(shuō)明CDROM自身診斷未通過(guò),這里只考慮Device0
//---------------------------------
// 使能數(shù)據(jù)包(Packer Command)功能
// IDENTIFY PACKET DEVICE
//---------------------------------
WriREG(0xA1,0xFF,REG_Command); //寫A1H,IDENTIFY PACKET DEVICE命令
//INTRQWait(); //等待CDROM中斷
RedREG(REG_Data); //讀一個(gè)字節(jié)的返回?cái)?shù)據(jù)用于判斷CDROM所定義的Packet長(zhǎng)度
REGBL = REGBL << 6;
if (REGBL == 0x00)
PacketSize = 6; //12byte 6word
if (REGBL == 0x40)
PacketSize = 8; //16byte 8word
if (!PacketSize)
UKERR = 1; //當(dāng)不是這兩個(gè)值是為未知錯(cuò)誤
}
TestUnitReady();
ERRLED = 0;
ReadSub(); //讀信息
BSYWait();
ERRLED = 1;
if (CurrentTrackNum==0x01) //當(dāng)前曲目應(yīng)等于1
CDOK = 1;
else
CDOK = 0;
}
//檢測(cè)忙狀態(tài)
void BSYWait(void)
{
do
{
ReadStatus();
}
while(BSY);
}
/*檢測(cè)INTRQ引腳,CDROM中斷
void INTRQWait(void)
{
do
{
INTRQ = 1;
}
while(INTRQ);
}
*/
//檢測(cè)DRQ是否為1,BSY=0
void DRQWait(void)
{
do
{
BSYWait();
DRQ = ~DRQ;
}
while(DRQ);
}
//檢測(cè)DRQ是否為0,BSY=0
void NDRQWait(void)
{
do
{
BSYWait();
}
while(DRQ);
}
//數(shù)據(jù)包送暫存RAM
void LoadPacket(unsigned char code *RT)
{
unsigned char TempCyc;
for (TempCyc=0; TempCyc<12; TempCyc++) //數(shù)據(jù)包送暫存RAM
{
PacketTemp[TempCyc] = *RT;
RT++;
}
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -