第21章 MP3播放器实验 1 电路图 2 程序移植 本章实现的功能是单片机读取SD卡中的MP3音乐文件进行自动播放。 1 电路图 1号单片机与VS1003的接口电路 程序中比较重要的代码是VS1003的复位操作,每首歌曲播放完毕都需执行一次复位操作,否 则后面播放的音乐会出现模糊不清的问题,复位操作包括硬件复位与软件复位。 void VS_Reset() { /////////// 硬件复位 ////////// unsigned char retry=0; VS_XDCS=1; // 取消数据传输 VS_XCS=1; // 取消指令传输 VS_XRESET=1; delay(10); VS_XRESET=0; // 硬件低电平复位 delay100mS(); // 延时100ms VS_XRESET=1; while(VS_DREQ==0&&retry<200) // 等待DREQ为高 { retry++; delay50us(); }; delay20ms(); /////////// 软件复位 ////////// VS_Write_Reg(0x00,0x08,0x04); // 软件复位,向模式寄存器写入0x0804即可 /////////// 初始化 ////////// VS_Write_Reg(0x03,0x98,0x00); // 时钟设置,3倍频 VS_Write_Reg(0x0b,0x00,0x00); // 音量设置,左右声道均最大音量 VS_XDCS=0; // 打开数据片选,注意此时XCS(片选)为高电平 SPI_WriteByte(0); // 写入数据,这里写入4个字节00或FF,是无关数据,用来启动数据传输 SPI_WriteByte(0); SPI_WriteByte(0); SPI_WriteByte(0); VS_XDCS=1; // 关闭数据片选 if(retry>=200)return 1; // 硬件复位失败 else return 0; // 硬件复位成功 }
部分程序预览:
vs1003.c文件:
- #include "vs1003.h"
- #include "patch.h"
- #include "myfun.h"
- /****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
- ★★★★★★★★★★★★★★★★★★★★★★★★
- 《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
- 作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
- 仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
- QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
- 验证信息:STC15单片机
- 邮箱:xgliyouquan@126.com
- ★★★★★★★★★★★★★★★★★★★★★★★★*/
- unsigned char bdata dat; //dat是可位寻址的变量
- sbit dat7=dat^7;
- sbit dat6=dat^6;
- sbit dat5=dat^5;
- sbit dat4=dat^4;
- sbit dat3=dat^3;
- sbit dat2=dat^2;
- sbit dat1=dat^1;
- sbit dat0=dat^0; //取出dat的各个位
- /******************************************************************
- 功能:IO模拟SPI,发送一个字节
- ******************************************************************/
- void SPI_WriteByte(unsigned char x)
- {
- dat=x; // 将x的值赋给可位寻址的变量dat,以便取出各个位
-
- SPI_SI=dat7; // 取出第7个位,写到数据线上
- SPI_SCLK=0;
- SPI_SCLK=1; // 时钟线产生上升沿,数据被写入
-
- SPI_SI=dat6;
- SPI_SCLK=0;
- SPI_SCLK=1;
-
- SPI_SI=dat5;
- SPI_SCLK=0;
- SPI_SCLK=1;
-
- SPI_SI=dat4;
- SPI_SCLK=0;
- SPI_SCLK=1;
-
- SPI_SI=dat3;
- SPI_SCLK=0;
- SPI_SCLK=1;
-
- SPI_SI=dat2;
- SPI_SCLK=0;
- SPI_SCLK=1;
-
- SPI_SI=dat1;
- SPI_SCLK=0;
- SPI_SCLK=1;
-
- SPI_SI=dat0;
- SPI_SCLK=0;
- SPI_SCLK=1;
- }
- /******************************************************************
- 功能:IO模拟SPI,读取一个字节
- ******************************************************************/
- //unsigned char SPI_ReadByte()
- //{
- // SPI_SO=1;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat7=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat6=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat5=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat4=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat3=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat2=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat1=SPI_SO;
- //
- // SPI_SCLK=1;
- // delay(1);
- // SPI_SCLK=0;
- // delay(1);
- // dat0=SPI_SO;
- //
- // return dat;
- //}
- /******************************************************************
- 功能:向VS1003的功能寄存器中写入数据(两个字节)
- 参数:addr是功能寄存器的地址
- hdat是要写入的高字节
- ldat是要写入的低字节
- ******************************************************************/
- void VS_Write_Reg(unsigned char addr,unsigned char hdat,unsigned char ldat)
- {
- VS_DREQ=1; // 51单片机IO作输入时先置为1
- while(!VS_DREQ); // VS1003的DREQ为高电平时才接收数据
- VS_XCS=0; // 打开命令片选,这样才能对功能寄存器进行读写
- SPI_WriteByte(0x02); // 写入操作码0x02 00000010 (功能寄存器写操作)
- SPI_WriteByte(addr); // 写入寄存器地址
- SPI_WriteByte(hdat); // 写入高字节
- SPI_WriteByte(ldat); // 写入低字节
- VS_XCS=1; // 关闭命令片选
- }
- /******************************************************************
- 功能:从VS1003的功能寄存器中读取数据(2个字节)
- 参数:addr是功能寄存器的地址
- 返回:返回从VS1003的功能寄存器中读到的值
- ******************************************************************/
- //unsigned int VS_Read_Reg(unsigned char addr)
- //{
- // unsigned int temp=0;
- // VS_DREQ=1; // 51单片机IO作输入时先置为1
- // while(!VS_DREQ); // VS1003的DREQ为高电平时才接收数据
- // VS_XCS=0; // 打开命令片选,这样才能对功能寄存器进行读写
- // SPI_WriteByte(0x03); // 读出操作码0x03 00000011(功能寄存器读操作)
- // SPI_WriteByte(addr); // 写入寄存器地址
- // temp=SPI_ReadByte(); // 读高字节
- // temp<<=8;
- // temp|=SPI_ReadByte(); // 读取低字节,与高字节拼成一个整数
- //
- // VS_XCS=1; // 关闭命令片选
- // return temp; // 返回读到的值
- //}
- /******************************************************************
- 功能:VS1003硬件复位+软件复位+初始化(设置时钟频率及音量)
- ******************************************************************/
- unsigned char VS_Reset()
- {
- /////////// 硬件复位 //////////
- unsigned char retry=0;
- VS_XDCS=1; // 取消数据传输
- VS_XCS=1; // 取消指令传输
- VS_XRESET=1;
- delay(10);
- VS_XRESET=0; // 硬件低电平复位
- delay100mS(); // 延时100ms
- VS_XRESET=1;
- while(VS_DREQ==0&&retry<200) //等待DREQ为高
- {
- retry++;
- delay50us();
- };
- delay20ms();
- /////////// 软件复位 //////////
- VS_Write_Reg(0x00,0x08,0x04); // 软件复位,向模式寄存器写入0x0804即可
- /////////// 初始化 //////////
- VS_Write_Reg(0x03,0x98,0x00); // 时钟设置,3倍频
- VS_Write_Reg(0x0b,0x00,0x00); // 音量设置,左右声道均最大音量
-
- VS_XDCS=0; // 打开数据片选,注意此时XCS(片选)为高电平
- SPI_WriteByte(0); // 写入数据,这里写入4个字节00或FF,是无关数据,用来启动数据传输
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- VS_XDCS=1; // 关闭数据片选
- if(retry>=200)return 1; // 硬件复位失败
- else return 0; // 硬件复位成功
- }
- /******************************************************************
- 功能:向VS1003写入一个字节的音频数据(即用于播放的数据)
- 参数:dat是要写入的字节
- ******************************************************************/
- void VS_Send_Dat(unsigned char dat)
- {
- VS_XDCS=0; // 打开数据片选
- VS_DREQ=1;
- while(!VS_DREQ); // VS1003的DREQ为高才能写入数据
- SPI_WriteByte(dat); // 通过SPI向VS1003写入一个字节的音频数据
- VS_XDCS=1; // 关闭数据片选
- }
- /******************************************************************
- 功能:向VS1003写入2048个0,用于清空VS1003的数据缓冲区,在播放完一个完整的音频(如MP3)
- 后,调用函数,清空VS1003数据缓冲区,为下面的音频数据(如下一首MP3)作准备。
- ******************************************************************/
- void VS_Flush_Buffer()
- {
- unsigned int i;
- VS_XDCS=0; // 打开数据片选
- for(i=0;i<2048;i++)
- {
- VS_Send_Dat(0);
- }
- VS_XDCS=1; // 关闭数据片选
- }
- /******************************************************************
- 功能:正弦测试,这是测试VS1003芯片是否正常的有效手段!!
- 参数:x决定了正弦测试中产生的正弦波的频率,直接影响听到的声音的频率
- ******************************************************************/
- void VS_sin_test(unsigned char x)
- {
- VS_Write_Reg(0x00,0x08,0x20); // 启动正弦测试,
- VS_DREQ=1;
- while(!VS_DREQ); // 等待DREQ变为高电平
- VS_XDCS=0; // 打开数据片选 SDI有效
- SPI_WriteByte(0x53); // 写入以下8个字节,进入正弦测试
- SPI_WriteByte(0xef); // 正弦测试命令:0x53 0xef 0x6e xx 0x00 0x00 0x00 0x00
- SPI_WriteByte(0x6e);
- SPI_WriteByte(x); // 参数x用来调整正弦测试中正弦波的频率
- SPI_WriteByte(0); // 比如x=126 (0b 011 11110) FsIdx=011=3 Fs=22050Hz S=11110=30 F=22050Hz X 30 /128 =5168 Hz
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- delay200mS(); // 这里延时一段时间,为了听到“正弦音”
- SPI_WriteByte(0x45); //写入以下8个字节,退出正弦测试
- SPI_WriteByte(0x78);
- SPI_WriteByte(0x69);
- SPI_WriteByte(0x74);
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- SPI_WriteByte(0);
- VS_XDCS=1; // 关闭数据片选
- }
- /******************************************************************
- 功能:为VS1003打补丁,获得实时频谱,atab与dtab是VS1003频谱功能补丁码,在patch.h中
- ******************************************************************/
- void LoadPatch()
- {
- unsigned int i;
- for(i=0;i<943;i++)
- {
- VS_Write_Reg(atab[i],dtab[i]>>8,dtab[i]&0xff);
- }
- }
复制代码
所有完整源码下载:
第21章 MP3播放器.rar
(9.79 MB, 下载次数: 118)
|