📄 fei.pr~
字号:
#include <mega16.h>
#include <delay.h>
#define A0 PA.5
#define A1 PA.4
#define A2 PA.3
#define CS0 PB.0
#define CS1 PA.2
#define WR PA.7
#define RD PA.6
#define RST PB.4
//#define CDCOM P0 //CDROM控制线
#define INTRQ PB.5//INTRQ
#define DBM PD //CDROM数据线高8位
#define DBL PC //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
unsigned char const ReadSubP[]={0x42,0x02,0x40,0x01,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadSub命令信息包
unsigned char const ReadTOCP[]={0x43,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadTOC命令信息包
unsigned char const PlayMSFP[]={0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //MSF播放命令信息包
unsigned int PacketTemp[24]; //信息包暂存RAM,用写数据和读数据的暂存
unsigned char REGBL=0, REGBM=0; //用于暂存读取寄存器的值
unsigned char PacketSize; //用于保存CDROM定义的信息包长度,有12,16
unsigned char CDStatusREG; //可位寻址变量保存CDROM的状态寄存器值 ; //可位寻址变量保存CDROM的状态寄存器值; //可位寻址变量保存CDROM的状态寄存器值
bit ERR = CDStatusREG^0; //错误 ;unsigned char ERR=CDStatusREG&c0x01
bit DRQ = CDStatusREG^3; //数据请求 ;unsigned char DRQ=CDStatusREG&0x08
bit DRDY = CDStatusREG^6; //设备就绪 ;unsigned char DRDY=CDStatusREG&0x40
bit BSY = CDStatusREG^7; //忙 ;unsigned char BSY=CDStatusREG&0x80
unsigned char bdata CDErr=0; //保存各种错误标识 ?
bit INITERR = CDErr^0; //初始化错误
bit TESTERR = CDErr^1; //CDROM自身诊断错误
bit 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){
unsigned char CDCOM;
InitCDROM();
TestUnitReady();
ReadTOC(0xAA);
ReadTOC(0x01);
PlayMSF();
ReadSub();//测试用
delay_ms(1000);
while(1);
}
//写寄存器
void WriREG(unsigned char LSB, unsigned char MSB, unsigned char REG){
CDCOM = REG; //设要写的REG
//EA=0;//程序中有中断程序时应先关中断
A0=CDCOM&0xFE;
A1=(CDCOM>>1)&0xFE;
A2=(CDCOM>>2)&0xFE;
CS0=(CDCOM>>3)&0xFE;
CS1=(CDCOM>>4)&0xFE;
WR=(CDCOM>>5)&0xFE;
RD=(CDCOM>>6)&0xFE;
RST=(CDCOM>>7)&0xFE;
CS1 = 1;
DBL = LSB;
DBM = MSB; //写数据
WR = 0;
WR = 1;
CS1 = 0; //WD,CS1置回
DBL = 0xFF;
DBM = 0xFF;
delay_ms(3); //延时
//EA=1; 在这开中断
} //读寄存器
void RedREG(unsigned char REG){
CDCOM = REG; //设要读的寄存器
A0=CDCOM&0xFE;
A1=(CDCOM>>1)&0xFE;
A2=(CDCOM>>2)&0xFE;
CS0=(CDCOM>>3)&0xFE;
CS1=(CDCOM>>4)&0xFE;
WR=(CDCOM>>5)&0xFE;
RD=(CDCOM>>6)&0xFE;
RST=(CDCOM>>7)&0xFE;
//EA=0;//程序中有中断程序时应先关中断
CS1 = 1;
RD = 0; //开始读数据线
REGBL = DBL; //从数据线上读状态寄存器值
REGBM = DBM;
RD = 1;
CS1 = 0; //RD,CS1置回
delay_ms(3); //延时
//EA=1; 在这开中断
}
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<12; Tempcyc++)
{
CDCOM = REG_Data; //设控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1
//EA=0;//程序中有中断程序时应先关中断
A0=CDCOM&0xFE;
A1=(CDCOM>>1)&0xFE;
A2=(CDCOM>>2)&0xFE;
CS0=(CDCOM>>3)&0xFE;
CS1=(CDCOM>>4)&0xFE;
WR=(CDCOM>>5)&0xFE;
RD=(CDCOM>>6)&0xFE;
RST=(CDCOM>>7)&0xFE;
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;
delay_ms(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置回
delay_ms(3); //延时
//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){
//---------------------------------
// 复位
//---------------------------------
DBL = 0xFF;
DBM = 0xFF;
RST = 0; //拉低RST,延时使CDROM复位
delay_ms(100); //延时
RST = 1; //复位完成拉高RST
delay_ms(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){
//---------------------------------
// 执行自身诊断
//---------------------------------
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++;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -