?? demo.c
字號:
//-------------------------------------------//
// ATAPI-CDROM 驅動程序 //
// //
// 這源碼為ATAPI基本驅動程序,main()中只有 //
// 幾個基本功能,為演示版,存在一些很多BUG //
// //
// 本程序為共享版本,但不得用于商業性質。 //
// //
// 不提供任何無償的技術支持。 //
// 使用或轉載時請保留些版權信息。 //
// 更多升級版本請留意: //
// 主頁: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 + -