logo资料库

基于STC12单片机的WAV播放器.doc

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
基于 STC12 单片机的 WAV 播放器 物电学院电信二班 小组成员:张景宝、李镇宇、周方嫒 一、 设计特点 1、 采用 PWM 调制方式,使硬件简单,实现容易。 2、 由于没有专用解码芯片,所以只能播放 WAV 音轨。 3、 通过软件自动适应音乐采样率。 4、 设计电池接口,可便携。 5、 声音大小可通过硬件调整。 二、 基本原理 将 PCM 文件结合采样率调制到 PWM,采取适当滤波,驱动耳机即可还 原音乐文件。 三、 硬件设计 1、 电源部分 2、 SD 卡部分 3、 音频接口部分
4、 CPU 部分 四、 软件设计 1、 编译平台:KEIL V9.0 2、 使用资源情况 9 级优化
3、 SD 卡低层驱动 /************************************************************* - 功能描述:向 SD 卡写命令 - 隶属模块:SD 卡模块 - 函数属性:内部 - 参数说明:SD 卡的命令是 6 个字节,pcmd 是指向命令字节序列的指针 - 返 回 说 明 : 命 令 写 入 后 , SD 卡 的 回 应 值 , 调 用 不 成 功 , 将 返 回 0xff *************************************************************/ u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc) { unsigned char r1; unsigned char Retry = 0; // SPI_ReadWriteByte(0xff); //片选端置低,选中 SD 卡 SD_CS=0; //打开片选 //发送 SPI_ReadWriteByte(cmd | 0x40); //分别写入命令 SPI_ReadWriteByte(arg >> 24); SPI_ReadWriteByte(arg >> 16); SPI_ReadWriteByte(arg >> 8); SPI_ReadWriteByte(arg); SPI_ReadWriteByte(crc); //等待响应,或超时退出 while((r1 = SPI_ReadWriteByte(0xFF))==0xFF) { Retry++; if(Retry > 200) { break; } }
//关闭片选 //在总线上额外增加 8 个时钟,让 SD 卡完成剩下的工作 SPI_ReadWriteByte(0xFF); SD_CS=1; //打开片选 //返回状态值 return r1; } /************************************************************* - 功能描述:初始化 SD 卡,使用 CMD1 - 隶属模块:SD 卡模块 - 函数属性:内部 - 参数说明:无 - 返回说明:调用成功,返回 0x00,否则返回 INIT_CMD1_ERROR (sd.h 中有定义) *************************************************************/ u8 SD_Init() { unsigned char time,temp,i; SPI_Init(); SPI_SetSpeed(3); //设置到低速模式 SD_CS=1; //打开片选 for(i=0;i<0x0A;i++) //初始时,首先要发送最少 74 个时钟信号,这是必须的!!! { SPI_ReadWriteByte(0xff); //120 个时钟 } SD_CS=0; //打开片选 time=0; do { temp=SD_SendCommand(CMD0, 0 ,0x95);//写入 CMD0 复位 SD 卡 time++; if(time==200) { SD_CS=1; //打开片选 } }while(temp!=0x01); time=0; do { temp=SD_SendCommand(CMD1, 0 , 0xff); //写入 CMD1 激活 SD 卡 time++; if(time==200)
{ SD_CS=1; //打开片选 } }while(temp!=0); SPI_SetSpeed(0); temp = SD_SendCommand(CMD59, 0, 0x01); if(temp != 0x00) { return temp; //命令错误,返回 r1 } temp=SD_SendCommand(CMD16,512,0xff); if(temp!=0x00) { return temp ; //命令错误,返回 r1 } SD_CS=1; //打开片选 SPI_ReadWriteByte(0xff); //按照 SD 卡的操作时序在这里补 8 个时钟 return 0; } /*----------------------------------------------------------*/ /* Initialize Disk Drive /*----------------------------------------------------------*/ DSTATUS disk_initialize (void) { DSTATUS stat; stat = SD_Init(); return stat; } /*----------------------------------------------------------*/ /* Read Partial Sector /*----------------------------------------------------------*/ DRESULT disk_readp ( BYTE* buff, DWORD sector, WORD offset, WORD count /* Pointer to the destination object */ /* Sector number (LBA) */ /* Offset in the sector */ /* Byte count (bit15:destination) */ ) { */ */
DRESULT res; uchar response=0xff; uint byteLeft,retry=0; byteLeft=512-offset-count; //接收数据后,跳过的字节数 if((offset+count)>512) return RES_PARERR; // 读 取 字 节 超 出 扇 区 if(SD_SendCommand(CMD17, sector<<9,0)) return RES_ERROR; //读命令发送失败 SD_CS_ASSERT; do { //等待起始数据块起始标志 0xfe (0x11111110) response=SPI_ReadWriteByte(0xff); if(retry++ > 0xfffe) //超时错误 { SD_CS_DEASSERT; return RES_ERROR; } }while(response != 0xfe); //等待回应 //跳过 offset(偏移字节数)个数据 if (offset) { do { SPI_ReadWriteByte(0xff); }while (--offset); } if(buff) { do { //接收到的数据块数据存入缓冲区 *buff++=SPI_ReadWriteByte(0xff); }while (--count); } else { } //dummy if (byteLeft) { //跳过 byteLeft 个数据
do { SPI_ReadWriteByte(0xff); }while (--byteLeft); } SPI_ReadWriteByte(0xff); SPI_ReadWriteByte(0xff); res= RES_OK; SD_CS_DEASSERT; SPI_ReadWriteByte(0xff); return res; } 4、 数据缓冲区设计 BYTE xdata Cache0[SIZE]; BYTE xdata Cache1[SIZE]; LPBYTE data Cache; LPBYTE data AudioCache = Cache0; //忽略 CRC 校验(两个字节) //等待 8 个 clk if(Cache == Cache0) Cache = Cache1; else Cache = Cache0; 5、 音乐还原过程 void Timer0(void) interrupt 1 { CCAP0L = CCAP0H = AudioCache[AudioPos]; AudioPos++; if(AudioPos>=SIZE) { play_f=1; AudioPos = 0; if(AudioCache == Cache0) AudioCache = Cache1; else AudioCache = Cache0; } } 6、 WAV 文件格式与自适应采样率 static DWORD load_header (void) { /* 0:Invalid format, 1:I/O error, >=1024:Number of samples */ DWORD sz, f; BYTE b, al = 0;
if (pf_read(Cache, 12, &rb)) return 1;/* Load file header (12 bytes) */ if (rb != 12 || LD_DWORD(Cache+8) != FCC('W','A','V','E')) return 0; for (;;) { pf_read(Cache, 8, &rb); if (rb != 8) return 0; sz = LD_DWORD(&Cache[4]); /* Get Chunk ID and size */ /* Chunk size */ /* FCC */ switch (LD_DWORD(&Cache[0])) { /* 'fmt ' chunk */ case FCC('f','m','t',' ') : if (sz & 1) sz++; /* Align chunk size */ if (sz > 100 || sz < 16) return 0; /* Check chunk size */ pf_read(Cache, sz, &rb); if (rb != sz) return 0; if (Cache[0] != 1) return 0;/* Check coding type (LPCM) */ b = Cache[2]; if (b != 1 && b != 2) return 0; b = Cache[14]; if (b != 8 && b != 16) return 0; /* Check channels (1/2) */ /* Get content */ /* Check resolution (8/16 bit) */ if (b & 16) al <<= 1; f = LD_DWORD(&Cache[4]);/* Check sampling freqency (8k-48k) */ if (f < 8000 || f > 8000) return 4; TH0 = -(FOSC / 12 / f); break; case FCC('d','a','t','a') : /* 'data' chunk */ if (!al) return 0; /* Check if format valid */ if (sz < 1024 || (sz & (al - 1))) return 0;/* Check size */ if (Fs.fptr & (al - 1)) return 0; /* Check offset */ return sz; /* Start to play */ case FCC('D','I','S','P') : /* 'DISP' chunk */ SendString("disp\n"); case FCC('L','I','S','T') : case FCC('f','a','c','t') : if (sz & 1) sz++; /* 'LIST' chunk */ /* 'fact' chunk */ /* Align chunk size */ pf_lseek(Fs.fptr + sz); break; /* Skip this chunk */ default : /* Unknown chunk */
分享到:
收藏