找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3582|回复: 6
打印 上一主题 下一主题
收起左侧

求一个单片机的音乐播放器

[复制链接]
楼主
ID:475984 发表于 2019-2-12 18:03 | 显示全部楼层
我用stc12c5a60s2单片机做的 和你要求的功能差不多基本上改改晶振值就行 了


  1. /****************************
  2. 表白神器  音乐盒
  3. ****************************
  4. 晶振值33.1776MHz
  5. 功能简介:K16控制暂停与继续
  6.           K4 上一曲
  7.                                         K12下一曲
  8.     数码管显示当前歌曲序号
  9. ****************************
  10. 歌曲分别是:
  11. 纸短情长
  12. 两只老虎
  13. 祝你生日快乐歌
  14. 小星星
  15. ****************************/
  16. #include <stc12c5a60s2.h>
  17. #define Xtal 33177600  //赋晶振值
  18. #define All 4          //歌曲总数


  19. sbit BUZZ = P1^3;  //蜂鸣器控制引脚
  20. sbit KEY = P2^4;   //按键定义
  21. sbit KEY4 = P2^7;
  22. sbit KEY12 = P2^5;
  23. sbit ADDR0 = P2^0; //数码管显示控制
  24. sbit ADDR1 = P2^1;
  25. sbit ADDR2 = P2^2;
  26. sbit ENLED = P1^1; //总线收发器

  27. bit KeySta = 1;  //当前按键状态
  28. bit KeySta4 = 1;  
  29. bit KeySta12 = 1;
  30. bit backup = 1;  //默认弹起时时一
  31. bit backup4 = 1;
  32. bit backup12 = 1;
  33. bit cntkey = 0;  //判断暂停还是播放
  34. bit breakflage = 0;//用按键改变歌曲标志

  35. unsigned char keybuf = 0xFF;
  36. unsigned char keybuf4 = 0xFF;
  37. unsigned char keybuf12 = 0xFF;
  38. unsigned char Num = 1; //第几首歌
  39. unsigned char sizeofNote;//节拍的多少
  40.                
  41. extern void Delay_ms(unsigned int ms);//延时函数

  42. void PlayControl(unsigned char Num);//歌曲选择函数
  43. void Play();//演奏函数

  44. unsigned char code LedChar[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};//数码管显示字符转换表
  45. unsigned int code NoteFrequ[] = {  //中音1-7低音1-7和高音1-7对应频率列表
  46.     523,  587,  659,  698,  784,  880,  988,  //中音1-7
  47.     1047, 1175, 1319, 1397, 1568, 1760, 1976,  //高音1-7
  48.           262, 294, 330, 349, 392, 440, 494,300//低音1-7  最后一个纯属凑数
  49. };
  50. unsigned int code NoteReload[] = { //中音1-7和高音1-7对应的定时器重载值
  51.     65536 - (Xtal/12) / (523*2),  //中音1
  52.     65536 - (Xtal/12) / (587*2),  //2
  53.     65536 - (Xtal/12) / (659*2),  //3
  54.     65536 - (Xtal/12) / (698*2),  //4
  55.     65536 - (Xtal/12) / (784*2),  //5
  56.     65536 - (Xtal/12) / (880*2),  //6
  57.     65536 - (Xtal/12) / (988*2),  //7
  58.     65536 - (Xtal/12) / (1047*2), //高音1
  59.     65536 - (Xtal/12) / (1175*2), //2
  60.     65536 - (Xtal/12) / (1319*2), //3
  61.     65536 - (Xtal/12) / (1397*2), //4
  62.     65536 - (Xtal/12) / (1568*2), //5
  63.     65536 - (Xtal/12) / (1760*2), //6
  64.     65536 - (Xtal/12) / (1976*2), //7
  65.           65536 - (Xtal/12) / (262*2), //低音1
  66.     65536 - (Xtal/12) / (294*2), //2
  67.     65536 - (Xtal/12) / (330*2), //3
  68.     65536 - (Xtal/12) / (349*2), //4
  69.     65536 - (Xtal/12) / (392*2), //5
  70.     65536 - (Xtal/12) / (440*2), //6
  71.     65536 - (Xtal/12) / (494*2), //7
  72.                 65536 - (Xtal/12) / (300*2), //纯属凑数
  73. };

  74. unsigned char *SongNote, *SongBeat;//指针
  75. unsigned char code XiaoXingXingNote[] = {   //小星星
  76.         1, 1, 5, 5,    6, 6, 5,    4, 4, 3, 3,    2, 2, 1,  
  77.         5, 5, 4, 4,    3, 3, 2,    5, 5, 4, 4,    3, 3, 2 ,
  78.         1, 1, 5, 5,    6, 6, 5,    4, 4, 3, 3,    2, 2, 1, 0xff    };

  79. unsigned char code XiaoXingXingBeat[] = {
  80.         4, 4, 4, 4,    4, 4, 8,    4, 4, 4, 4,    4, 4, 8,
  81.         4, 4, 4, 4,    4, 4, 8,    4, 4, 4, 4,    4, 4, 8,
  82.         4, 4, 4, 4,    4, 4, 8,    4, 4, 4, 4,    4, 4, 8,};
  83. unsigned char code TwoTigerNote[] = {    //两只老虎音符表
  84.         1,   2,   3, 1,    1,   2,   3, 1,   3, 4, 5,   3, 4, 5,
  85.         5,6, 5,4, 3, 1,    5,6, 5,4, 3, 1,   1, 5, 1,   1, 5, 1,0xff};

  86. unsigned char code TwoTigerBeat[] = {    //两只老虎节拍表,4表示一拍,1就是1/4拍,8就是2拍
  87.         4,   4,   4, 4,    4,   4,   4, 4,   4, 4, 8,   4, 4, 8,
  88.         3,1, 3,1, 4, 4,    3,1, 3,1, 4, 4,   4, 4, 8,   4, 4, 8,
  89.     };
  90. unsigned char code HappybirthdayNote[] = {  //生日快乐歌
  91.         5, 5, 6, 5, 8, 7, 22, 5, 5, 6, 5, 9, 8, 5, 5, 12, 10, 8, 7, 6, 11, 11,  10, 8, 9, 8,0xff };
  92. unsigned char code HappybirthdayBeat[] = {
  93.         2, 2, 4, 4, 4, 4, 4, 2, 2,  4, 4, 4, 8, 2, 2, 4, 4, 4, 4, 8, 2, 2, 4, 4, 4, 8};       
  94. unsigned char code         ZhiduanqingchangNote[] = { //纸短情长
  95.               //8, 9, 10, 9, 8, 6, 22, 11, 10, 9, 22, 7, 8, 9, 7, 7, 5, 22, 7, 9, 8, 8, 3, 4, 2, 3, 1, 1, 5, 2,  //前奏
  96.         19, 3, 3, 3, 2, 3, 1, 2, 2, 2, 1, 2, 5, 1, 1, 1, 20, 1, 20, 19,     2, 2, 2, 3, 20, 19, 4, 4, 4, 3, 4, 1, 2, 2, 2, 1, 2, 5,
  97.                1, 1, 1, 20, 1, 20, 3, 2, 2, 1, 1, 22, 22, 22, 1, 1, 2,             3, 3, 3, 22, 3, 2, 1, 21, 6, 5, 22, 5, 6, 7, 8, 3, 3, 22, 8, 7, 8,
  98.               7, 3, 5, 5, 6, 8, 5, 6, 22, 6, 5, 4,5, 3, 2, 1, 20, 1,               3, 2, 2, 1, 2, 5, 1, 2, 5, 22, 22, 22, 1, 1, 2,
  99.         3, 3, 2, 3, 22, 3, 2, 1, 5, 5, 3, 5, 22, 5, 6, 7,                   8, 8, 8, 8, 8, 7, 6, 7, 6, 3, 5, 5, 5, 6, 8, 5, 6, 22, 6, 5, 4,
  100.         5, 3, 2, 1, 6, 1, 3, 2, 2, 1, 2, 1, 20, 1, 22,                      22, 20, 1, 3, 2, 2, 22, 2, 1, 2, 1, 1, 22, 20, 1, 1, 0xff};       
  101. unsigned char code ZhiduanqingchangBeat[] = {
  102.               //2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 8, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 8, 8, 12, 4, 5, 4, 8, 8, 4,   //前奏
  103.         8, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 4, 2,       2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 5, 2, 2, 2, 2, 2, 5,
  104.         2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 8, 4, 4, 2, 2, 2, 2,                4, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2,
  105.         4, 2, 5, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 4, 2, 5, 1, 1,             2, 2, 2, 2, 2, 4, 2, 16, 16,4, 4, 2, 2, 2, 2,
  106.         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,                   2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 4, 2, 2, 2, 4, 2, 2, 2, 2, 2,
  107.         2, 4, 2, 5, 1, 1, 2, 2, 2, 2, 2, 4, 1, 12, 4,                     2, 1, 1, 2, 2, 8, 2, 1, 1, 2, 2, 8, 2, 2, 12, 16};
  108. bit enable = 1;   //蜂鸣器发声使能标志
  109. bit tmrflag = 0;  //定时器中断完成标志
  110. unsigned char T0RH = 0xFF;  //T0重载值的高字节
  111. unsigned char T0RL = 0x00;  //T0重载值的低字节


  112. void main()
  113. {
  114.    
  115.     EA = 1;       //使能全局中断
  116.     TMOD = 0x11;  //配置T0,T1工作在模式1
  117.     TH0 = T0RH;   
  118.     TL0 = T0RL;
  119.     ET0 = 1;      //使能T0中断
  120.           ET1 = 1;      //使能T1中断
  121.           TR1 = 1;      //启动T1
  122.           ENLED = 0x00; //使能总线收发器
  123.           ADDR2=1; ADDR1=0; ADDR0=1;//选择最右边的数码管
  124.           P23 = 0;      //启用KEY
  125.    
  126.     while (1)
  127.     {
  128.                         P0 = LedChar[Num]; //数码管显示当前歌曲序号
  129.       PlayControl(Num);                       
  130.                         if(breakflage == 1)
  131.                                 breakflage = 0;
  132.                         else
  133.                                 Delay_ms(500);
  134.     }
  135. }

  136. void PlayControl(unsigned char Num)
  137. {
  138.         switch(Num)
  139.         {
  140.                 case 4:SongNote = XiaoXingXingNote;    SongBeat =  XiaoXingXingBeat;  sizeofNote = sizeof(XiaoXingXingNote);   Play();break;
  141.     case 2:SongNote = TwoTigerNote;        SongBeat =TwoTigerBeat;        sizeofNote = sizeof(TwoTigerNote);       Play();break;
  142.                 case 3:SongNote = HappybirthdayNote;   SongBeat =HappybirthdayBeat;   sizeofNote = sizeof(HappybirthdayNote);  Play();break;
  143.                 case 1:SongNote = ZhiduanqingchangNote;SongBeat =ZhiduanqingchangBeat;sizeofNote = sizeof(ZhiduanqingchangNote);Play();break;               
  144.                 default:break;
  145.         }
  146. }
  147. /* 演奏函数 */
  148. void Play()//演奏函数
  149. {
  150.     unsigned char beat;   //当前节拍索引
  151.     unsigned char note;   //当前节拍对应的音符
  152.     unsigned int time = 0;      //当前节拍计时
  153.     unsigned int beatTime = 0;  //当前节拍总时间
  154.     unsigned int soundTime = 0; //当前节拍需发声时间

  155.     for (beat=0; beat<sizeofNote; )  //用节拍索引作为循环变量
  156.     {
  157.                                 if(breakflage == 1)
  158.                                         break;
  159.         while (!tmrflag);  //每次定时器中断完成后,检测并处理节拍
  160.         tmrflag = 0;
  161.         if (time == 0)  //当前节拍播完则启动一个新节拍
  162.         {
  163.                                         if(breakflage == 1)
  164.                                                 break;
  165.             note = SongNote[beat] - 1;
  166.                                           if(note == 0xfe)
  167.                                                 {
  168.                                                         if(Num == All)
  169.                                                                 Num = 1;
  170.                                                         else
  171.                                                         Num++;
  172.                                                         break;
  173.                                                 }
  174.             T0RH = NoteReload[note] >> 8;
  175.             T0RL = NoteReload[note];
  176.             beatTime = (SongBeat[beat] * NoteFrequ[note]) >> 2;//计算节拍总时间,右移2位相当于除4,移位代替除法可以加快执行速度
  177.             soundTime = beatTime - (beatTime >> 2);//计算发声时间,
  178.             enable = 1;  //指示蜂鸣器开始发声
  179.                                                 if (note == 21)//简谱的0 等待
  180.                                                         enable =0;
  181.             time++;
  182.         }
  183.         else  //当前节拍未播完则处理当前节拍
  184.         {
  185.             if (time >= beatTime)  //当前持续时间到达节拍总时间时归零,
  186.             {                      //并递增节拍索引,以准备启动新节拍
  187.                 time = 0;
  188.                 beat++;
  189.             }
  190.             else  //当前持续时间未达到总时间时,
  191.             {
  192.                 time++;   //累加时间计数
  193.                 if (time == soundTime)  //到达发声时间后,指示关闭蜂鸣器,
  194.                 {                       //插入0.25*总时间的静音间隔,
  195.                     enable = 0;         //用以区分连续的两个节拍
  196.                 }
  197.             }
  198.         }
  199.     }
  200. }
  201. /*控制蜂鸣器发声 */
  202. void InterruptTimer0() interrupt 1
  203. {
  204.     TH0 = T0RH;   //重新加载重载值
  205.     TL0 = T0RL;
  206.     tmrflag = 1;
  207.     if (enable)   //使能时反转蜂鸣器控制电平
  208.         BUZZ = ~BUZZ;
  209.     else          //未使能时关闭蜂鸣器
  210.         BUZZ = 1;
  211. }
  212. /*按键扫描*/
  213. void InterruptTimer1() interrupt 3 //按键部分参看之前的帖子 带有计次功能的秒表
  214. {
  215.         TH1 = 0xC9;
  216.         TL1 = 0xEA;
  217.        
  218.           keybuf = (keybuf<<1) | KEY;
  219.     if (keybuf == 0x00)
  220.         KeySta = 0;
  221.     else if (keybuf == 0xFF)
  222.         KeySta = 1;
  223.     else{}
  224.                        
  225.           keybuf4 = (keybuf4<<1) | KEY4;
  226.     if (keybuf4 == 0x00)
  227.         KeySta4 = 0;
  228.     else if (keybuf4 == 0xFF)
  229.         KeySta4 = 1;
  230.     else{}
  231.                        
  232.          keybuf12= (keybuf12<<1) | KEY12;
  233.     if (keybuf12 == 0x00)
  234.         KeySta12 = 0;
  235.     else if (keybuf12 == 0xFF)
  236.         KeySta12 = 1;
  237.     else{}
  238.                        
  239.                               if (KeySta != backup)  
  240.         {
  241.             if (backup == 0)        
  242.                                                 {
  243.                                                         cntkey=~cntkey;
  244.                                                         TR0 = cntkey;
  245.                                                 }
  246.             backup = KeySta;               
  247.         }
  248.                 if (KeySta4 != backup4)
  249.                 {
  250.                         if(backup4 ==0)
  251.                         {
  252.                                 breakflage = 1;
  253.                                 if(Num <All)
  254.                                   Num++;
  255.                           else if(Num == All)
  256.                                         Num =1;
  257.                                 P0 = LedChar[Num];
  258.                         }
  259.                         backup4 = KeySta4;
  260.                 }               
  261.                
  262.                 if (KeySta12 != backup12)
  263.                 {
  264.                         if(backup12 ==0)
  265.                         {
  266.                                 breakflage = 1;
  267.                                 if(Num >1)
  268.                                   Num--;
  269.                           else if(Num == 1)
  270.                                         Num =All;
  271.                                 P0 = LedChar[Num];
  272.                         }
  273.                         backup12 = KeySta12;
  274.                 }                       
  275.                
  276. }
复制代码
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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