⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zcontrol.c

📁 &#8226 控制器(CPU): Atmel AT90S8515 AVR &#8226 MP3解码器: STA013 &#8226 音频 DAC: CS4334 &#8226 IDE 接口
💻 C
字号:
/*
    Copyright 2003 Nasif Akand (nasif@yifan.net)
    http://go.to/zipamp
    http://zipamp.virtualave.net

    This file is part of ZipAmp MP3 software.

    ZipAmp is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    ZipAmp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this code; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

//This module performs different control operation for ZipAmp
//Nasif Akand

//If using CodeVision then following includes aren't needed.
#include "zcontrol.h"
//#include "zfat.h"
//#include "zata.h"
//#include "ztype.h"
//#include "i2c.h"
//#include "<delay.h>" //CodeVision AVR internal delay routines
                                                                         
   
//mask for cyclic buffer of clusterBuffer, check zata.h for clustBuf size
#define clustBufMask	ClusterBufSize-1 


void readFile(word wordToRead){ //
//Reads the current file word by word, no cluster buffering, used for generic file reading
 if ((sectorPos==Sectors_Per_Cluster)) { //if whole cluster is already read then 
   currentCluster=findNextCluster();  	 //a new cluster must be read by looking into FAT
   readPos=0;                            
   sectorPos=0;
 }                           
 ATA_Read_Sectors_LBA(clust2LBA(currentCluster)+sectorPos,wordToRead); //read # of words;
 filePos += (wordToRead<<1); //filepos = filepos+ (wordtoread*2)
}


void read() {
//This function is similar to above but reads 256 bytes at a time
//It is only used with cluster buffering for MP3 playback. 
 
 //The code below has been repeated many times. A function was
 //was not written because of speed considerations.
 if (sectorPos==Sectors_Per_Cluster) { //Check if a cluster has been already read.
  if (readClusterBuffer()!=1) { //If cluster buffer is empty.
   currentCluster=findNextCluster(); //find next cluster
  }              
  sectorPos=0; //reset parameters
  readPos=0;                        
  headMoved=0;
 }
 //if head wasn't moved when we reached at sector end then move head.
 //That will happen when readPos and headMoved both are 0.
 if ((readPos|headMoved)==0) ATA_Move_Head(clust2LBA(currentCluster)+sectorPos);
 
 ATA_Read(128); 	//Read 128 words
 filePos += 256;	//Increment file position.
}


byte writeClusterBuffer() {
//Fills up the cyclic buffer of clusterBuffer
//Writes clusterBuffer.cluster with next cluster address of the current file chain
//Returns 1 if buffering was successful, otherwise 0 if buffer is already full.

 dword tempClust;
 if (((clusterBufferWritePos+1)& clustBufMask) != clusterBufferReadPos) { //if buffer is not full
  tempClust=currentCluster;
  if (clusterBufferWritePos!=clusterBufferReadPos) 
   //If buffer is not empty then get the previous cluster from buffer to find Next cluster
   currentCluster=clusterBuffer.cluster[(clusterBufferWritePos-1) & clustBufMask];

  //findNextCluster function will looks at currentCluster
  clusterBuffer.cluster[clusterBufferWritePos]=findNextCluster();    
  
  //increment buffer write pos and AND with mask
  clusterBufferWritePos = (clusterBufferWritePos+1) & clustBufMask;
  currentCluster=tempClust;
  return 1;
 }
 else return 0; //Buffer is full, can't buffer anymore
}

byte readClusterBuffer() {
//Reads next cluster from cluster buffer if it is not empty  
//Returns 1 if successfull, 0 if failed. 
//Cluster address is returned in currentCluster.
 if (clusterBufferWritePos != clusterBufferReadPos) { //if not empty buffer
  currentCluster=clusterBuffer.cluster[clusterBufferReadPos];
  clusterBufferReadPos = (clusterBufferReadPos+1) & clustBufMask;
  return 1;
 }
 else return 0;
}                         

byte DecodeID3Frame(dword FrameStrVal,byte offset) {
//Decodes ID3v2 tag.
//This is very crude way to decode ID3 tags. It was done to fit the code in AVR 8515.
//This function only looks at first 256bytes of MP3 file for ID3v2 tags. If its not there
//then we are out of luck. Do not take this function as your guide to ID3 tag decoding. 
//It was only written to decode TIT2 and TPE1 frames.
//FrameStrVal is value of ID3 frame name string in binary. e.g. TIT2 = 0x54495432
//offset is the storage offset in fileName string.
//Returns 0 if decoding failed, otherwise it returns the offset at fileName string.

  byte i;
  dword strn;  //storage for binary ID3v2 frame name.
  readPos=0;   //need to read a sector, set readPos=0  
  
  //Read the first 256 bytes of MP3 file. This is where we will look for ID3v2 tag.
  ATA_Read_Sectors_LBA(clust2LBA(currentCluster),128); 

  readPos=0;

  while (readPos<220) { 
  //looks in first 256 bytes, we actually finish by 220 bytes so that we don't cross array
  //boundary when we are doing following instructions in the loop.

   if (sectorBuffer.data[readPos]=='T') //Check if its start of TIT2 or TPE1 frame
    for(i=0; i<4; i++) strn=(strn<<8)+sectorBuffer.data[readPos+i]; //Load the bytes into strn for comparision
    
   if (strn!=FrameStrVal) goto FAIL; //Check if its the frame that we are looking for
    mp3Pos=sectorBuffer.data[readPos+7]; //mp3Pos is used to store Frame length
    readPos += 11; //Increment readPos by frame record size (11 bytes) so we can start reading text data.
    mp3Pos += offset; //Increment mp3Pos with offset so that we are ready to copy into fileName string.
    while ((offset<41)&&(offset<mp3Pos)) { //If there is more space left in the string.
     fileName[offset++]=sectorBuffer.data[readPos++];
    }
    offset--; //Decrement offset by 1
    fileName[offset]=0; //Set last fileName char to NULL.
    return offset; //finished reading frame, so retrn.

FAIL:   //We reach here only if we didn't find the frame that we were looking for.
   readPos++;
  }
  return 0; //We failed, so return 0.
}


void SongSelect() {
//This function finds an MP3 file based on current play mode.
//Saves player status. Fixes the LCD display.

 byte offset,i=0;
 
 if (playMode==1) { //If its Random mode.
  dirReadOffset.fileNum=0;
  currentFileNum=randomKey(); //get random file number
 }
 
 
 if (getDirEntry(1)!=0) { //get an MP3 file.

  offset=DecodeID3Frame(TPE1,0); //Decode frame TPE1, and store in fileName offset 0
  i=0;                                                                   
  //If we found TPE1 then put " - " character.
  if (offset>0) while((offset<41)&&(i<3)) fileName[offset++]=dash[i++];  
  DecodeID3Frame(TIT2,offset); //Decode frame TIT2, and store in fileName offset position.
  
  saveConfig();  //Save the ZipAmp status in hard drive.
  firstCluster=currentCluster; //Remember the starting cluster of the file.
  clusterBufferReadPos=0; clusterBufferWritePos=0; //Clear cluster buffer
  while (writeClusterBuffer()!=0); //Now Fillup the cluster buffer.
 
  UnBusy(); //Clear the busy led
  filePos=0; //Reset all parameters
  readPos=0;
  sectorPos=0;
  mp3Pos=0;

  printFileName(); //Print file name on LCD
  printInfo(); //Print other information
  intFlag=0; //LCD fixed, so clear interrupt flag.
 }        

 gotoxy(0,19); //Put the LCD cursor on position of play/stop character.
}

void STA013Setup() {                                                                   
//Sets up STA013 after initial power up or reset.

 byte success; byte i;
 dword extension;
 
 //Setup STA013
 STA013Reset();	//Give reset pulse to STA013
 i2cInit();
 if (i2cReadAddress(1)!=0xAC) { //Check if STA013 is there
  Halt(6); //STA013 decoder not found.
 }         
 
 success=0;
 currentFileNum=0;

 do { //Find STA013.BIN

  if (getDirEntry(0)==0) Halt(5); //root directory finished and STA013.BIN not found. Generate error.
  extension=0;
  for(i=0; i<3; i++) extension=(extension<<8)+fileExtension[i]; //Load extension chars into dword variable
  
  //If extension is BIN and fileName starts with either 's' or 'S',
  //then we assume filename is STA013.BIN. Whole filename comparision will take
  //lot of code, therefore this assumption is made. User therefore must
  //not save any other file that is BIN and starts with S.
  if ((extension==0x0042494E)&& //if it is 0BIN
      ((fileName[0] & 0x53)==0x53)) // 'S' & 's' == 'S'
  
     success=1; //we found STA013.BIN
 }                                    
 while ((success==0));

 success=0;
 readPos=0;	//reset to read start of STA013.BIN
 sectorPos=0;	//reset sector position to begin reading for start;

 do { //Load STA013.BIN
  readFile(1); //Read 1 word, 1st byte is I2C address, 2nd byte is data.
  i2cInit();
  success = i2cWriteAddress(sectorBuffer.data[0],sectorBuffer.data[1]);
 }
 while ((filePos<FileSize)&&(success==1));
 
 //  Load failed. Generate error. 
 if (success==0) Halt(7);                               
 
 i2cInit();

 i2cWriteAddress(0x7D,11);	//Set tone attenuation level -16.5dB. 
 				//This is required. Otherwise sound will crack when we do bass/treble boost.
 i2cWriteAddress(0x72,1);	//Run, (its not play)

}

void SetBassTreble() {
//Sets the STA013 bass treble registers depending on soundMode.
//Loads the pre-defined bass/treble values from BassTrebleTable array (look at ztype.h)

 byte i;
 for(i=0;i<6;i++) 
  //Bass treble I2C address starts at 0x77
  i2cWriteAddress(i+0x77,BassTrebleTable[soundMode,i]);

}


void STAPlay() {
//Play/Stop MP3 playback on STA013.
 i2cInit();
 i2cWriteAddress(0x13,(play & 1));
} 



word randomKey() {
//Generate random number between 0 to totalFiles-1
//Uses 16 bit timer/counter for random number.
//Random number is found by moding 16 bit counter TCNT1 with totalFiles.

 word temp;
 temp = TCNT1H;	
 temp = (temp<<8) + TCNT1L;
 return (temp % totalFiles);
}

void printError(byte errorCode) {
//Print error based on errorCode on LCD from ErrStr array (look at ztype.h)
 byte i=0;
 while (ErrStr[errorCode,i]!=0) writechar(ErrStr[errorCode,i++]);
}

void Halt(byte errorCode) {
//Halt ZipAmp if error was encountered.
 LCDclrscr();
 printError(0); //Print first line of error
 printError(errorCode);//Print the error line
 while(1); //Infinite loop.
}

void printFileName() {
//Print file name on LCD

 byte i=0;                 
 LCDclrscr();

 gotoxy(1,0);
 while((fileName[i]!=0)&&(fileName[i]!='.')) {
  if (i==20) gotoxy(2,0);
  writechar(fileName[i++]);
 }            
 gotoxy(3,0);
 for (i=1; i<dirString[0]; i++) writechar(dirString[i]);
 
}

void printInfo() {
//Print other info on LCD.
 byte i;                  

 //Display fileNumber
 gotoxy(0,0);
 for(i=0;i<9;i++) writechar(' ');
 gotoxy(0,0);
 writeNumber(currentFileNum);
 writechar('/');
 writeNumber(totalFiles);
 
 gotoxy(0,10); //Fix LCD display for sound mode
 for(i=0;i<4;i++) 
  writechar(SoundModeDisplay[soundMode,i]);                                         

 //Diplay play mode characters 
 writechar(' ');
 for (i=0; i<3; i++) writechar(PlayModeDisplayStrTable[playMode,i]);
 writechar(' ');

 //Display stop/play/pause characters
 if (play==2) writechar(255); //player stopped
 else writechar(5-play); 
 blink();
 gotoxy(0,19);
}

//End of zcontrol.h

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -