找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7176|回复: 6
收起左侧

STC15F2K60S2单片机C语言音乐编程实现

  [复制链接]
ID:271728 发表于 2018-1-4 23:52 | 显示全部楼层 |阅读模式
keil编程实例音乐

单片机源程序如下:

  1. /**********************
  2. 基于STC15F2K60S2系列单片机C语言编程实现
  3. 使用如下头文件,不用另外再包含"REG51.H"
  4. ***********************/
  5. #include <STC15F2K60S2.h>
  6. #define uint unsigned int
  7. #define uchar unsigned char
  8. sbit beep=P3^4;                          //蜂鸣器
  9. sbit key1=P3^2;                        //按键1
  10. sbit key2=P3^3;                        //按键2
  11. sbit key3=P1^7;     //按键3

  12. sbit Sel0=P2^0;
  13. sbit Sel1=P2^1;
  14. sbit Sel2=P2^2;//位选的三个引脚控制位

  15. uchar pinlv;
  16. uchar pinlv_flag;//改变数码管滚动频率

  17. uchar show_w1;
  18. uchar show_w2;
  19. uchar show_w3;
  20. uchar show_w4;
  21. uchar show_w5;
  22. uchar show_w6;
  23. uchar show_w7;
  24. uchar show_w8;//show_wi,分别对应从左到右的每个数码管上的数字

  25. uchar duanxuan[]={0x73,0x38,0x79,0x77,0x6d,0x79,0x00,0x79,0x37,0x1e,0x3f,0x6e,0x40,0x40,0x0f,0x39,0x38,0x6e,0x00,0x00};//段选,显示PLEASE ENJOY--XLY
  26. uchar weixuan[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; //位选,选择是0-7中的一个数码管

  27. uchar flag0,count;//数码管扫描快慢分频作用

  28. uchar timeh,timel,jindu=0,gequ=0;                  //定义定时器的重装值
  29. bit flag;        //播放标志位
  30. uchar code music1[] ={    //音乐代码,歌曲为《同一首歌》,格式为: 音符, 节拍, 音符, 节拍,   
  31. 0x15,0x20,0x21,0x10,         //音符的十位代表是低八度,中八度还是高八度,1代表低八度,2代表中八度,3代表高八度
  32. 0x22,0x10,0x23,0x15,         //个位代表简谱的音符,例如0x15代表低八度的S0,0x21代表中八度的DO。
  33. 0x24,0x05,0x23,0x10,         //节拍则是代表音长,例如:0x10代表一拍,0x20代表两拍,0x05代表1/2拍
  34. 0x21,0x10,0x22,0x20,
  35. 0x21,0x10,0x16,0x10,
  36. 0x21,0x40,0x15,0x20,
  37. 0x21,0x10,0x22,0x10,
  38. 0x23,0x10,0x23,0x05,
  39. 0x24,0x05,0x25,0x10,
  40. 0x21,0x10,0x24,0x15,
  41. 0x23,0x05,0x25,0x10,
  42. 0x22,0x05,0x23,0x05,
  43. 0x23,0x05,0x22,0x05,
  44. 0x22,0x30,0x23,0x20,
  45. 0x25,0x10,0x31,0x10,
  46. 0x27,0x15,0x26,0x05,
  47. 0x26,0x20,0x25,0x10,
  48. 0x25,0x05,0x26,0x05,
  49. 0x27,0x10,0x26,0x05,
  50. 0x25,0x05,0x23,0x40,
  51. 0x24,0x15,0x24,0x05,
  52. 0x25,0x10,0x26,0x10,
  53. 0x25,0x10,0x24,0x05,
  54. 0x23,0x05,0x22,0x20,
  55. 0x17,0x10,0x17,0x05,
  56. 0x16,0x05,0x15,0x10,
  57. 0x16,0x10,0x21,0x40,
  58. 0x00,0x00
  59. };
  60. uchar code music2[] ={                          //歌曲为小星星

  61. 0x21,0x10,0x21,0x10,
  62. 0x25,0x10,0x25,0x10,
  63. 0x26,0x10,0x26,0x10,
  64. 0x25,0x20,0x24,0x10,
  65. 0x24,0x10,0x23,0x10,
  66. 0x23,0x10,0x22,0x10,
  67. 0x22,0x10,0x21,0x20,
  68. 0x25,0x10,0x25,0x10,
  69. 0x24,0x10,0x24,0x10,
  70. 0x23,0x10,0x23,0x10,
  71. 0x22,0x20,
  72. 0x25,0x10,0x25,0x10,
  73. 0x24,0x10,0x24,0x10,
  74. 0x23,0x10,0x23,0x10,
  75. 0x22,0x20,
  76. 0x21,0x10,0x21,0x10,
  77. 0x25,0x10,0x25,0x10,
  78. 0x26,0x10,0x26,0x10,
  79. 0x25,0x20,0x24,0x10,
  80. 0x24,0x10,0x23,0x10,
  81. 0x23,0x10,0x22,0x10,
  82. 0x22,0x10,0x21,0x20,
  83. 0x00,0x00
  84. };
  85. uchar code music3[] ={                           //歌曲为天空之城
  86. 0x16,0x05,0x17,0x05,
  87. 0x21,0x15,0x17,0x05,
  88. 0x21,0x10,0x23,0x10,
  89. 0x17,0x30,0x23,0x10,
  90. 0x16,0x15,0x15,0x05,
  91. 0x16,0x10,0x21,0x10,
  92. 0x15,0x30,0x13,0x10,
  93. 0x14,0x15,0x13,0x05,
  94. 0x14,0x05,0x21,0x05,
  95. 0x21,0x10,0x13,0x30,
  96. 0x21,0x10,0x17,0x10,
  97. 0x14,0x05,0x14,0x10,
  98. 0x17,0x10,0x17,0x20,
  99. 0xff,
  100. 0x16,0x05,0x17,0x05,
  101. 0x21,0x15,0x17,0x05,
  102. 0x21,0x10,0x23,0x10,
  103. 0x17,0x30,0x13,0x05,
  104. 0x13,0x05,0x16,0x15,
  105. 0x15,0x05,0x16,0x10,
  106. 0x21,0x10,0x15,0x30,
  107. 0x13,0x10,0x14,0x10,
  108. 0x21,0x05,0x17,0x05,
  109. 0x17,0x10,0x21,0x10,
  110. 0x22,0x10,0x23,0x05,
  111. 0x21,0x20,0xff,
  112. 0x21,0x05,0x17,0x05,
  113. 0x16,0x10,0x17,0x10,
  114. 0x15,0x10,0x16,0x20,
  115. 0xff,
  116. 0x21,0x05,0x22,0x05,
  117. 0x23,0x15,0x22,0x10,
  118. 0x23,0x10,0x24,0x10,
  119. 0x25,0x05,0x22,0x30,
  120. 0x15,0x10,0x22,0x03,
  121. 0x21,0x03,0x17,0x03,
  122. 0x21,0x03,0x21,0x10,
  123. 0x21,0x05,0x22,0x10,
  124. 0x23,0x05,0x23,0x40,
  125. 0x16,0x05,0x17,0x05,
  126. 0x21,0x10,0x17,0x05,
  127. 0x21,0x05,0x22,0x10,
  128. 0x21,0x15,0x15,0x05,
  129. 0x15,0x20,0x24,0x10,
  130. 0x23,0x10,0x22,0x10,
  131. 0x21,0x10,0x23,0x30,
  132. 0x16,0x05,0x17,0x05,
  133. 0x21,0x15,0x17,0x05,
  134. 0x21,0x10,0x23,0x10,
  135. 0x17,0x30,0x13,0x10,
  136. 0x16,0x15,0x15,0x05,
  137. 0x16,0x10,0x21,0x10,
  138. 0x15,0x30,0x13,0x10,
  139. 0x14,0x10,0x21,0x05,
  140. 0x17,0x05,0x17,0x10,
  141. 0x21,0x10,0x22,0x10,
  142. 0x23,0x05,0x21,0x05,
  143. 0x21,0x20,0x21,0x05,
  144. 0x17,0x05,0x16,0x10,
  145. 0x17,0x10,0x15,0x10,
  146. 0x16,0x40,0x00,0x00
  147. };
  148. uchar code quzi[] ={          //此数组数据为各个音符在定时器中的重装值,第一列是高位,第二列是低位        //时间
  149. 0xf8,0x8c,          //低八度,低1
  150. 0xf9,0x5b,          
  151. 0xfa,0x15,          //低3
  152. 0xfa,0x67,
  153. 0xfb,0x04,          //低5
  154. 0xfb,0x90,
  155. 0xfc,0x0c,          //低7       
  156. 0xfc,0x44,          //中央C调
  157. 0xfc,0xac,          //中2
  158. 0xfd,0x09,
  159. 0xfd,0x34,          //中4
  160. 0xfd,0x82,
  161. 0xfd,0xc8,          //中6
  162. 0xfe,0x06,
  163. 0xfe,0x22,          //高八度,高1       
  164. 0xfe,0x56,
  165. 0xfe,0x6e,          //高3
  166. 0xfe,0x9a,
  167. 0xfe,0xc1,          //高5
  168. 0xfe,0xe4,
  169. 0xff,0x03            //高7
  170. };
  171. /**********************
  172. 函数名称:void delay(unsigned int xms)
  173. 功能描述:延时
  174. 入口参数:xms:输入需要延时的毫秒值
  175. 出口参数:无
  176. 备注:

  177. ***********************/
  178. void delay(unsigned int xms)
  179. {
  180.         uint i,j;                                                  
  181.          for(i=xms;i>0;i--)
  182.                  for(j=124;j>0;j--);
  183. }
  184. /**********************
  185. 函数名称:uchar quyin(uchar tem)
  186. 功能描述:在quzi数组中,找到music数组定义的简谱音符的重装值,并返回其在quzi数组中的位置
  187. 入口参数:tem:music数组中定义的简谱音符
  188. 出口参数:返回的是tem音符在quzi数组中的位置值
  189. 备注:

  190. ***********************/
  191. uchar quyin(uchar tem)
  192. {
  193.         uchar qudiao,jp,weizhi;                  //定义曲调,音符和位置
  194.         qudiao=tem/16;                                  //高4位是曲调值
  195.         jp=tem%16;                                           //低4位是音符
  196.         if(qudiao==1)                                  //当曲调值为1时,即是低八度,低八度在quzi数组中基址为0
  197.                 qudiao=0;
  198.         else if(qudiao==2)                          //当曲调值为2时,即是中八度,中八度在quzi数组中基址为14
  199.                 qudiao=14;
  200.         else if(qudiao==3)                          //当曲调值为3时,即是高八度,高八度在quzi数组中,基址为28
  201.                 qudiao=28;
  202.         weizhi=qudiao+(jp-1)*2;                  //通过基址加上音符作为偏移量,即可定位此音符在quzi数组中的位置
  203.         return weizhi;                                  //返回这一个位置值
  204. }
  205. /**********************
  206. 函数名称:void playmusic()
  207. 功能描述:播放音乐
  208. 入口参数:无
  209. 出口参数:无
  210. 备注:

  211. ***********************/
  212. void playmusic()
  213. {
  214.         uchar p,m,tem;   //m为节拍      
  215.         while(1)   
  216.         {   
  217.                 if(flag==1)                                          //若播放的标志位为1则播放音乐
  218.                 {
  219.                         if(gequ==0)                                  //歌曲选择位为0,则播放第一首歌
  220.                         {       
  221.                                 p=music1[jindu];             
  222.                                 if(p==0x00)                          //如果碰到结束符,延时1秒,回到开始再来一遍
  223.                                 {
  224.                                         jindu=0;
  225.                                         delay(1000);
  226.                                         break;
  227.                                 }        
  228.                                 else if(p==0xff)           //若碰到休止符,延时100ms,继续取下一音符
  229.                                 {
  230.                                         jindu=jindu+1;
  231.                                         delay(100);
  232.                                         TR0=0;
  233.                                         break;
  234.                                 }      
  235.                                 else                                   //正常情况下取音符和节拍
  236.                                 {
  237.                                         tem=quyin(music1[jindu]);                //取出当前音符在quzi数组中的位置值
  238.                                         timeh=quzi[tem];                                //把音符相应的计时器重装载值赋予timeh和timel
  239.                                         timel=quzi[tem+1];
  240.                                         jindu++;
  241.                                         TH0=timeh;                                                //把timeh和timel赋予计时器
  242.                                         TL0=timel;
  243.                                         m=music1[jindu];                                         //取得节拍
  244.                                         jindu++;
  245.                                 }                    
  246.                     TR0=1;                            //开定时器0   
  247.                                 delay(m*180);                                      //等待节拍完成, 通过P3^4口输出音频   
  248.                                 TR0=0;                            //关定时器0
  249.                                 beep=0;                                                          //使beep端口置0,起保护蜂鸣器作用
  250.                         }                                                                               
  251.                         else if(gequ==1)                   //歌曲选择位为1,则播放小星星
  252.                         {       
  253.                                 p=music2[jindu];            
  254.                                 if(p==0x00)                         //如果碰到结束符,延时1秒,回到开始再来一遍
  255.                                 {
  256.                                         jindu=0;
  257.                                         delay(1000);
  258.                                         break;
  259.                                 }        
  260.                                 else if(p==0xff)   //若碰到休止符,延时100ms,继续取下一音符
  261.                                 {
  262.                                         jindu=jindu+1;
  263.                                         delay(100);
  264.                                         TR0=0;
  265.                                         break;
  266.                                 }      
  267.                                 else                           //正常情况下取音符和节拍
  268.                                 {
  269.                                         tem=quyin(music2[jindu]);                //取出当前音符在quzi数组中的位置值
  270.                                         timeh=quzi[tem];                        //把音符相应的计时器重装载值赋予timeh和timel
  271.                                         timel=quzi[tem+1];
  272.                                         jindu++;
  273.                                         TH0=timeh;                                        //把timeh和timel赋予计时器
  274.                                         TL0=timel;
  275.                                         m=music2[jindu];                                         //取得节拍
  276.                                         jindu++;
  277.                                 }                    
  278.                         TR0=1;                    //开定时器1   
  279.                                 delay(m*300);             //等待节拍完成, 通过P3^4口输出音频   
  280.                                 TR0=0;                    //关定时器1
  281.                                 beep=0;                                          //使beep端口置0,起保护蜂鸣器作用
  282.                         }
  283.                         else if(gequ==2)                  //歌曲选择位为2,则播放天空之城
  284.                         {       
  285.                                 p=music3[jindu];            
  286.                                 if(p==0x00)                         //如果碰到结束符,延时1秒,回到开始再来一遍
  287.                                 {
  288.                                         jindu=0;
  289.                                         delay(1000);
  290.                                         break;
  291.                                 }        
  292.                                 else if(p==0xff)   //若碰到休止符,延时100ms,继续取下一音符
  293.                                 {
  294.                                         jindu=jindu+1;
  295.                                         delay(100);
  296.                                         TR0=0;
  297.                                         break;
  298.                                 }      
  299.                                 else                           //正常情况下取音符和节拍
  300.                                 {
  301.                                         tem=quyin(music3[jindu]);                //取出当前音符在quzi数组中的位置值
  302.                                         timeh=quzi[tem];                        //把音符相应的计时器重装载值赋予timeh和timel
  303.                                         timel=quzi[tem+1];
  304.                                         jindu++;
  305.                                         TH0=timeh;                                        //把timeh和timel赋予计时器
  306.                                         TL0=timel;
  307.                                         m=music3[jindu];                                         //取得节拍
  308.                                         jindu++;
  309.                                 }                    
  310.                     TR0=1;                    //开定时器1   
  311.                                 delay(m*200);             //等待节拍完成, 通过P3^4口输出音频   
  312.                                 TR0=0;                    //关定时器1
  313.                                 beep=0;                                          //使beep端口置0,起保护蜂鸣器作用
  314.                         }
  315.                 }
  316.                 else                                                           //播放标志位不为1时,暂停播放音乐
  317.                 while(flag!=1);   
  318.         }
  319. }
  320. /**********************
  321. 函数名称:void init_sys()
  322. 功能描述:系统初始化,功能是配置IO口
  323. 入口参数:无
  324. 出口参数:无
  325. 备注:

  326. ***********************/
  327. void init_sys()
  328. {
  329.         P0M0=0xff;                           //设置推挽模式
  330.         P0M1=0x00;
  331.         P2M0=0x08;
  332.         P2M1=0x00;
  333.         P3M0=0x10;
  334.         P3M1=0x00;
  335.         P4M0=0x00;
  336.         P4M1=0x00;
  337.         P5M0=0x00;
  338.         P5M1=0x00;
  339. }
  340. /**********************
  341. 函数名称:void init()
  342. 功能描述:定时器和外部中断的初始化
  343. 入口参数:无
  344. 出口参数:无
  345. 备注:

  346. ***********************/
  347. void init()                                                  
  348. {
  349.         TMOD=0x01;                          //设置定时器0,定时方式1,16位手动重装模式(TH0和TL0全用)
  350.         TH0=0xD8;                          //设置定时初值
  351.         TL0=0xEF;
  352.         IE=0x8f;                          // 1000 1111  EA=1(打开总的终中断),ET1=1(定时器1中断使能),EX0=1(外部中断0使能),ET0=1(定时器0中断使能),EX1=0(外部中断1使能);
  353.         IP=0x02;                          // 0000 0010  PT0=1;   定时器0优先级高
  354.         TR0=0;                                  //定时器0停止工作,初始化
  355.         beep=0;                                  //使beep端口置0,起保护蜂鸣器作用
  356.        
  357.         flag0=0;
  358.         count=0;
  359.        
  360.         show_w1=0;
  361.         show_w2=1;
  362.         show_w3=2;
  363.         show_w4=3;
  364.         show_w5=4;
  365.         show_w6=5;
  366.         show_w7=6;
  367.         show_w8=7;//赋初值,为接下来取模做准备
  368. }
  369. void main()
  370. {
  371.         init_sys();                          //系统初始化
  372.         init();
  373.         P0=0x00;      //P0口初始化
  374.         key1=1;                                //三个按键设为输入状态,检测中断
  375.         key2=1;
  376.         key3=1;
  377.         flag=0;                                //播放标志位清零
  378.        
  379.         TMOD=0x90;//定时器1,方式1
  380.         ET1=1;//开启定时器1中断       
  381.         pinlv_flag=0;
  382.         pinlv=100;

  383.         TH1=(65535-1000)/256;//定时器1的高八位设置
  384.         TL1=(65535-1000)%256;//定时器1的低八位设置,这里总体就是设置定时器0的初始值是1ms
  385.         TR1=1;//启动定时器1
  386.         EA=1;//打开总的中断
  387.        
  388.         while(1)
  389.         {
  390.                 playmusic();        //播放音乐函数
  391.         }
  392. }                                                                       
  393. /**********************
  394. 函数名称:void tim1() interrupt 1
  395. 功能描述:定时器0中断处理,重新装值,并把beep值取反,产生方波
  396. 入口参数:无
  397. 出口参数:无
  398. 备注:

  399. ***********************/
  400. void tim1() interrupt 1                                                //计时器控制频率
  401. {
  402.         TH0=timeh;                                                                //赋初值
  403.         TL0=timel;
  404.         beep=~beep;                                                           //中断使得beep翻转产生方波
  405. }
  406. /**********************
  407. 函数名称:void ex1() interrupt 0
  408. 功能描述:按下按键1的外部中断,对标志位取反,功能是暂停和播放音乐
  409. 入口参数:无
  410. 出口参数:无
  411. 备注:

  412. ***********************/
  413. void ex1() interrupt 0                                          
  414. {
  415.         delay(5);               
  416.         if(key1==0)                                                         //判断key1是否按下          
  417.         {
  418.                 delay(5);              //按键消抖
  419.                 if(key1==0)
  420.                 {
  421.                         while(!key1);
  422.                         flag=~flag;                                         //播放中断位取反,播放或者暂停
  423.                 }
  424.         }
  425. }
  426. /**********************
  427. 函数名称:void ex2() interrupt 2
  428. 功能描述:按下按键2的外部中断,作用为切换歌曲
  429. 入口参数:无
  430. 出口参数:无
  431. 备注:

  432. ***********************/
  433. void ex2() interrupt 2
  434. {
  435.         delay(5);
  436.         if(key2==0)                                    //按键key2按下,切换歌曲
  437.         {
  438.                 jindu=0;                           //歌曲的进度清零,从头开始演唱
  439.                 gequ++;                                   //下一曲
  440. ……………………

  441. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
final_4.rar (46.47 KB, 下载次数: 97)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:349092 发表于 2018-6-10 22:50 | 显示全部楼层
        共享资料的黑币奖励!
回复

使用道具 举报

ID:606316 发表于 2019-9-2 11:22 | 显示全部楼层
大神牛B!!!!!!!!!!!!!!
回复

使用道具 举报

ID:369306 发表于 2019-12-23 19:47 | 显示全部楼层
强强强,拿去参考了  又学到了
回复

使用道具 举报

ID:560110 发表于 2020-1-15 21:55 | 显示全部楼层
共享资料的黑币奖励!
回复

使用道具 举报

ID:230847 发表于 2020-1-25 12:42 | 显示全部楼层
参考一下,自己打了5块板子,准备制作一下音乐播放器。谢谢
回复

使用道具 举报

ID:383526 发表于 2020-4-19 12:37 | 显示全部楼层
感谢大佬
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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