日志档案

发表于 2008-4-10 17:57:03

2

标签: 电脑光驱  CD  C语言程序  

电脑光驱改做CD的C语言程序

电脑光驱改做CD的C语言程序
感觉比较新颖,就发了哈.我是在网上下的.

 

//-------------------------------------------//
//           ATAPI-CDROM 驱动程序            //
//                                           //
// 这源码为ATAPI基本驱动程序,main()中只有   //
// 几个基本功能,为演示版,存在一些BUG       //
//                                           //
// 本程序为共享版本,但不得用于商业性质。   //
//                                           //
// 不提供任何无偿的技术支持。         //
// 使用或转载时请保留些版权信息。            //
// 更多升级版本请留意:                       //
//      主页:
http://www.cdle.net            //
//      论坛:
http://bbs.cdle.net            //
//                                           //
//               //
//                                           //
//版权所有
http://www.cdle.net 2001-2004 明浩//
//-------------------------------------------//
#include

#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  {
   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  {
   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++;
  }
}

下载区:

rar

 

系统分类: 单片机   |   用户分类: 单片机   |   来源: 原创   |   【推荐给朋友】

    阅读(156)    回复(0)  

投一票您将和博主都有获奖机会!