导航: 老古网老古论坛XMOS公共讨论区XMOS开源项目区单片机程序设计嵌入式系统广告区域
→ATAPI-CDROM 驱动程序 C51源码[guest]

 *第21843篇: ATAPI-CDROM 驱动程序 C51源码

  
楼 主:guest 2004年5月12日22:22
 ATAPI-CDROM 驱动程序 C51源码
ATAPI-CDROM 驱动程序 C51源码

更多相关资料请访问


//-------------------------------------------//
//           ATAPI-CDROM 驱动程序            //
//                                           //
// 这源码为ATAPI基本驱动程序,main()中只有   //
// Play功能。                                //
// 本程序为共享版本,但不得用于商业性质。   //
//                                           //
// 不提供任何无偿的技术支持。         //
// 使用或转载时请保留些版权信息。            //
// 更多升级版本请留意:                       //
//   主页:            //
//      论坛:            //
//                                           //
// 联系方式:pnzwzw@cdle.net                 //
//           pnzwzw@163.com                  //
//                                           //
//版权所有  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

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; 在这开中断
}

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); //延时
   //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复位
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)
  {
//---------------------------------
// 执行自身诊断
//---------------------------------
   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++;
  }
}
 

  
2楼:jkljkl 2008年7月3日14:43
 3q
3 q

>>>>>>对该主题发表你的看法

本主题贴数2,分页: [第1页]


[上一篇主题]:推荐一个双串口调试程序

[下一篇主题]:请教:单片机C语言里的乘法运算