找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7667|回复: 8
收起左侧

第21章 单片机mp3播放器实验

  [复制链接]
ID:111078 发表于 2016-3-29 02:12 | 显示全部楼层 |阅读模式
51单片机轻松入门—基于STC15W4K系列(C语言版)
李友全
编著 详见:http://www.51hei.com/bbs/dpj-37954-1.html

21MP3播放器实验
1 电路图
2 程序移植
0.png
本章实现的功能是单片机读取SD卡中的MP3音乐文件进行自动播放。
1 电路图
1.png
1号单片机与VS1003的接口电路
3.png
2 程序移植
程序中比较重要的代码是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文件:
  1. #include "vs1003.h"
  2. #include "patch.h"
  3. #include "myfun.h"
  4. /****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
  5. ★★★★★★★★★★★★★★★★★★★★★★★★
  6. 《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
  7.   作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
  8.   仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
  9.   QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
  10.         验证信息:STC15单片机
  11.   邮箱:xgliyouquan@126.com
  12.   ★★★★★★★★★★★★★★★★★★★★★★★★*/
  13. unsigned char bdata dat; //dat是可位寻址的变量

  14. sbit dat7=dat^7;
  15. sbit dat6=dat^6;
  16. sbit dat5=dat^5;
  17. sbit dat4=dat^4;
  18. sbit dat3=dat^3;
  19. sbit dat2=dat^2;
  20. sbit dat1=dat^1;
  21. sbit dat0=dat^0; //取出dat的各个位

  22. /******************************************************************
  23. 功能:IO模拟SPI,发送一个字节
  24. ******************************************************************/
  25. void SPI_WriteByte(unsigned char x)
  26. {
  27.         dat=x;              // 将x的值赋给可位寻址的变量dat,以便取出各个位
  28.         
  29.         SPI_SI=dat7;  // 取出第7个位,写到数据线上
  30.         SPI_SCLK=0;
  31.         SPI_SCLK=1;          // 时钟线产生上升沿,数据被写入
  32.         
  33.         SPI_SI=dat6;
  34.         SPI_SCLK=0;
  35.         SPI_SCLK=1;
  36.         
  37.         SPI_SI=dat5;
  38.         SPI_SCLK=0;
  39.         SPI_SCLK=1;
  40.         
  41.         SPI_SI=dat4;
  42.         SPI_SCLK=0;
  43.         SPI_SCLK=1;
  44.         
  45.         SPI_SI=dat3;
  46.         SPI_SCLK=0;
  47.         SPI_SCLK=1;
  48.         
  49.         SPI_SI=dat2;
  50.         SPI_SCLK=0;
  51.         SPI_SCLK=1;
  52.         
  53.         SPI_SI=dat1;
  54.         SPI_SCLK=0;
  55.         SPI_SCLK=1;
  56.         
  57.         SPI_SI=dat0;
  58.         SPI_SCLK=0;
  59.         SPI_SCLK=1;
  60. }

  61. /******************************************************************
  62. 功能:IO模拟SPI,读取一个字节
  63. ******************************************************************/
  64. //unsigned char SPI_ReadByte()
  65. //{  
  66. //        SPI_SO=1;
  67. //        
  68. //        SPI_SCLK=1;
  69. //        delay(1);
  70. //        SPI_SCLK=0;
  71. //        delay(1);
  72. //        dat7=SPI_SO;
  73. //        
  74. //        SPI_SCLK=1;
  75. //        delay(1);
  76. //        SPI_SCLK=0;
  77. //        delay(1);
  78. //        dat6=SPI_SO;
  79. //        
  80. //        SPI_SCLK=1;
  81. //        delay(1);
  82. //        SPI_SCLK=0;
  83. //        delay(1);
  84. //        dat5=SPI_SO;
  85. //        
  86. //        SPI_SCLK=1;
  87. //        delay(1);
  88. //        SPI_SCLK=0;
  89. //        delay(1);
  90. //        dat4=SPI_SO;
  91. //        
  92. //        SPI_SCLK=1;
  93. //        delay(1);
  94. //        SPI_SCLK=0;
  95. //        delay(1);
  96. //        dat3=SPI_SO;
  97. //        
  98. //        SPI_SCLK=1;
  99. //        delay(1);
  100. //        SPI_SCLK=0;
  101. //        delay(1);
  102. //        dat2=SPI_SO;
  103. //        
  104. //        SPI_SCLK=1;
  105. //        delay(1);
  106. //        SPI_SCLK=0;
  107. //        delay(1);
  108. //        dat1=SPI_SO;
  109. //        
  110. //        SPI_SCLK=1;
  111. //        delay(1);
  112. //        SPI_SCLK=0;
  113. //        delay(1);
  114. //        dat0=SPI_SO;
  115. //        
  116. //        return dat;
  117. //}


  118. /******************************************************************
  119. 功能:向VS1003的功能寄存器中写入数据(两个字节)
  120. 参数:addr是功能寄存器的地址
  121.       hdat是要写入的高字节
  122.       ldat是要写入的低字节
  123. ******************************************************************/
  124. void VS_Write_Reg(unsigned char addr,unsigned char hdat,unsigned char ldat)
  125. {  
  126.         VS_DREQ=1;            // 51单片机IO作输入时先置为1
  127.         while(!VS_DREQ);      // VS1003的DREQ为高电平时才接收数据
  128.         VS_XCS=0;             // 打开命令片选,这样才能对功能寄存器进行读写
  129.         SPI_WriteByte(0x02);  // 写入操作码0x02   00000010 (功能寄存器写操作)
  130.         SPI_WriteByte(addr);  // 写入寄存器地址
  131.         SPI_WriteByte(hdat);  // 写入高字节
  132.         SPI_WriteByte(ldat);  // 写入低字节   
  133.         VS_XCS=1;             // 关闭命令片选
  134. }

  135. /******************************************************************
  136. 功能:从VS1003的功能寄存器中读取数据(2个字节)
  137. 参数:addr是功能寄存器的地址
  138. 返回:返回从VS1003的功能寄存器中读到的值
  139. ******************************************************************/
  140. //unsigned int VS_Read_Reg(unsigned char addr)
  141. //{
  142. //        unsigned int temp=0;
  143. //        VS_DREQ=1;            // 51单片机IO作输入时先置为1   
  144. //        while(!VS_DREQ);      // VS1003的DREQ为高电平时才接收数据
  145. //        VS_XCS=0;                  // 打开命令片选,这样才能对功能寄存器进行读写
  146. //        SPI_WriteByte(0x03);  // 读出操作码0x03   00000011(功能寄存器读操作)
  147. //        SPI_WriteByte(addr);  // 写入寄存器地址
  148. //        temp=SPI_ReadByte();  // 读高字节
  149. //        temp<<=8;
  150. //        temp|=SPI_ReadByte(); // 读取低字节,与高字节拼成一个整数
  151. //        
  152. //        VS_XCS=1;                  // 关闭命令片选
  153. //        return temp;          // 返回读到的值
  154. //}        

  155. /******************************************************************
  156. 功能:VS1003硬件复位+软件复位+初始化(设置时钟频率及音量)
  157. ******************************************************************/
  158. unsigned char VS_Reset()
  159. {
  160.         ///////////  硬件复位 //////////
  161.         unsigned char retry=0;
  162.         VS_XDCS=1;             // 取消数据传输
  163.         VS_XCS=1;             // 取消指令传输
  164.         VS_XRESET=1;
  165.         delay(10);                 
  166.         VS_XRESET=0;         // 硬件低电平复位
  167.         delay100mS();         // 延时100ms
  168.         VS_XRESET=1;  
  169.         while(VS_DREQ==0&&retry<200)   //等待DREQ为高
  170.         {
  171.                 retry++;
  172.                 delay50us();
  173.         };            
  174.         delay20ms();        

  175.         ///////////  软件复位 //////////
  176.         VS_Write_Reg(0x00,0x08,0x04); // 软件复位,向模式寄存器写入0x0804即可

  177.         ///////////  初始化 //////////
  178.         VS_Write_Reg(0x03,0x98,0x00); // 时钟设置,3倍频
  179.         VS_Write_Reg(0x0b,0x00,0x00); // 音量设置,左右声道均最大音量
  180.         
  181.         VS_XDCS=0;                 // 打开数据片选,注意此时XCS(片选)为高电平
  182.         SPI_WriteByte(0);    // 写入数据,这里写入4个字节00或FF,是无关数据,用来启动数据传输
  183.         SPI_WriteByte(0);
  184.         SPI_WriteByte(0);
  185.         SPI_WriteByte(0);
  186.         VS_XDCS=1;                 // 关闭数据片选

  187.         if(retry>=200)return 1;          // 硬件复位失败
  188.         else return 0;                          // 硬件复位成功
  189. }

  190. /******************************************************************
  191. 功能:向VS1003写入一个字节的音频数据(即用于播放的数据)
  192. 参数:dat是要写入的字节
  193. ******************************************************************/
  194. void VS_Send_Dat(unsigned char dat)
  195. {
  196.         VS_XDCS=0;           // 打开数据片选
  197.         VS_DREQ=1;
  198.         while(!VS_DREQ);     // VS1003的DREQ为高才能写入数据
  199.         SPI_WriteByte(dat);  // 通过SPI向VS1003写入一个字节的音频数据
  200.         VS_XDCS=1;           // 关闭数据片选
  201. }

  202. /******************************************************************
  203. 功能:向VS1003写入2048个0,用于清空VS1003的数据缓冲区,在播放完一个完整的音频(如MP3)
  204.       后,调用函数,清空VS1003数据缓冲区,为下面的音频数据(如下一首MP3)作准备。
  205. ******************************************************************/
  206. void VS_Flush_Buffer()
  207. {
  208.         unsigned int i;
  209.         VS_XDCS=0;                 // 打开数据片选
  210.         for(i=0;i<2048;i++)
  211.         {
  212.                 VS_Send_Dat(0);
  213.         }
  214.         VS_XDCS=1;           // 关闭数据片选
  215. }

  216. /******************************************************************
  217. 功能:正弦测试,这是测试VS1003芯片是否正常的有效手段!!
  218. 参数:x决定了正弦测试中产生的正弦波的频率,直接影响听到的声音的频率
  219. ******************************************************************/
  220. void VS_sin_test(unsigned char x)
  221. {
  222.         VS_Write_Reg(0x00,0x08,0x20);  // 启动正弦测试,
  223.         VS_DREQ=1;
  224.         while(!VS_DREQ);               // 等待DREQ变为高电平
  225.         VS_XDCS=0;                           // 打开数据片选 SDI有效
  226.         SPI_WriteByte(0x53);           // 写入以下8个字节,进入正弦测试
  227.         SPI_WriteByte(0xef);                    // 正弦测试命令:0x53 0xef 0x6e xx 0x00 0x00 0x00 0x00
  228.         SPI_WriteByte(0x6e);
  229.         SPI_WriteByte(x);   // 参数x用来调整正弦测试中正弦波的频率
  230.         SPI_WriteByte(0);   // 比如x=126 (0b 011 11110) FsIdx=011=3   Fs=22050Hz   S=11110=30    F=22050Hz X 30 /128 =5168 Hz
  231.         SPI_WriteByte(0);
  232.         SPI_WriteByte(0);
  233.         SPI_WriteByte(0);

  234.         delay200mS();                  // 这里延时一段时间,为了听到“正弦音”         

  235.         SPI_WriteByte(0x45);  //写入以下8个字节,退出正弦测试
  236.         SPI_WriteByte(0x78);
  237.         SPI_WriteByte(0x69);
  238.         SPI_WriteByte(0x74);
  239.         SPI_WriteByte(0);
  240.         SPI_WriteByte(0);
  241.         SPI_WriteByte(0);
  242.         SPI_WriteByte(0);
  243.         VS_XDCS=1;                 // 关闭数据片选  
  244. }

  245. /******************************************************************
  246. 功能:为VS1003打补丁,获得实时频谱,atab与dtab是VS1003频谱功能补丁码,在patch.h中
  247. ******************************************************************/
  248. void LoadPatch()
  249. {
  250.         unsigned int i;
  251.         for(i=0;i<943;i++)
  252.         {
  253.                 VS_Write_Reg(atab[i],dtab[i]>>8,dtab[i]&0xff);
  254.         }
  255. }
复制代码

0.png


所有完整源码下载: 第21章 MP3播放器.rar (9.79 MB, 下载次数: 116)
回复

使用道具 举报

ID:113189 发表于 2016-8-11 20:25 | 显示全部楼层
学习,希望能学会
回复

使用道具 举报

ID:140218 发表于 2016-9-29 23:42 | 显示全部楼层
好东西,正在研究之中
回复

使用道具 举报

ID:142974 发表于 2016-10-17 17:56 | 显示全部楼层
有仿真文件吗 怎么找不到?
回复

使用道具 举报

ID:171696 发表于 2017-3-19 17:38 | 显示全部楼层
好东西,正是我到处找的东西
回复

使用道具 举报

ID:314710 发表于 2018-4-24 20:17 | 显示全部楼层
感谢!
回复

使用道具 举报

ID:393796 发表于 2018-10-23 23:45 | 显示全部楼层
感谢楼主分享
回复

使用道具 举报

ID:288930 发表于 2019-1-18 14:01 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

ID:229361 发表于 2019-3-17 11:55 | 显示全部楼层
好东西,感谢楼主分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表