找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机播放《可可托海牧羊人》问题

[复制链接]
跳转到指定楼层
楼主
ID:886808 发表于 2021-3-2 13:18 来自手机 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近有一首歌挺火,又登上春晚。过年时没事我按《51单片机例程100》把它改成音乐编码用单片机播放。原例程的谱子中没有休止符,可这首歌多次出现不同拍节的休止符。我按音符宏定义的方法定义了休止符,频率为0,可播放休止符时声音变味,后来又用了关蜂鸣器等方法均不理想。在这里请教大侠,应怎么处理。原倒程和我编的歌曲码附后:
  1. //实例49用定时器T0的中断实现"渴望"主题曲的播放 #include<reg51.h>   //包含51单片机寄存器定义的头文件 /
  2. sbit sound=P3^7;    //将sound位定义为P3.7
  3. unsigned int C;     //储存定时器的定时常数
  4. //以下是C调低音的音频宏定义
  5. #define l_dao 262   //将“l_dao”宏定义为低音“1”的频率262Hz
  6. #define l_re 286    //将“l_re”宏定义为低音“2”的频率286Hz
  7. #define l_mi 311    //将“l_mi”宏定义为低音“3”的频率311Hz
  8. #define l_fa 349    //将“l_fa”宏定义为低音“4”的频率349Hz
  9. #define l_sao 392   //将“l_sao”宏定义为低音“5”的频率392Hz
  10. #define l_la 440    //将“l_a”宏定义为低音“6”的频率440Hz
  11. #define l_xi 494    //将“l_xi”宏定义为低音“7”的频率494Hz
  12. //以下是C调中音的音频宏定义
  13. #define dao 523     //将“dao”宏定义为中音“1”的频率523Hz
  14. #define re 587      //将“re”宏定义为中音“2”的频率587Hz
  15. #define mi 659      //将“mi”宏定义为中音“3”的频率659Hz
  16. #define fa 698      //将“fa”宏定义为中音“4”的频率698Hz
  17. #define sao 784     //将“sao”宏定义为中音“5”的频率784Hz
  18. #define la 880      //将“la”宏定义为中音“6”的频率880Hz
  19. #define xi 987      //将“xi”宏定义为中音“7”的频率523H      
  20. //以下是C调高音的音频宏定义
  21. #define h_dao 1046     //将“h_dao”宏定义为高音“1”的频率1046Hz
  22. #define h_re 1174      //将“h_re”宏定义为高音“2”的频率1174Hz
  23. #define h_mi 1318      //将“h_mi”宏定义为高音“3”的频率1318Hz
  24. #define h_fa 1396     //将“h_fa”宏定义为高音“4”的频率1396Hz
  25. #define h_sao 1567    //将“h_sao”宏定义为高音“5”的频率1567Hz
  26. #define h_la 1760     //将“h_la”宏定义为高音“6”的频率1760Hz  #define h_xi 1975     //将“h_xi”宏定义为高音“7”的频率1
  27. //函数功能1个延时单位延时200ms
  28. void delay()               
  29.    {
  30.      unsigned char i,j;
  31.    for(i=0;i<250;i++)
  32.      for(j=0;j<250;j++)
  33.         ;
  34.    }
  35. //函数功能主函数
  36. void main(void)
  37.   {
  38.   unsigned char i,j;            
  39. //以下是《渴望》片头曲的一段简谱
  40.    unsigned  int code f[]={re,mi,re,dao,l_la,dao,l_la,   //每行对应一小节音符                          l_sao,l_mi,l_sao,l_la,dao,
  41.              l_la,dao,sao,la,mi,sao,
  42.              re,      
  43.              mi,re,mi,sao,mi,
  44.              l_sao,l_mi,l_sao,l_la,dao,                           l_la,l_la,dao,l_la,l_sao,l_re,l_mi,
  45.          l_sao,
  46.          re,re,sao,la,sao,
  47.          fa,mi,sao,mi,
  48.          la,sao,mi,re,mi,l_la,dao,
  49.          re,
  50.          mi,re,mi,sao,mi,
  51.          l_sao,l_mi,l_sao,l_la,dao,
  52.          l_la,dao,re,l_la,dao,re,mi,
  53.          re,
  54.          l_la,dao,re,l_la,dao,re,mi,
  55.          re,
  56. //以下为我编的可可托海牧羊人
  57. 前奏
  58. mi,mi,re,mi,fa,fa,mi,fa,fa,sao,la, xi,sao,fa,mi,
  59. //1.
  60. mi,re,mi,l_la,
  61. l_la,l_la,l_xi,l_la,l_la,l_xi,
  62. l_sao,l_mi,
  63. dao,dao,l_la,dao,
  64. l_la,re,mi,sao,la,mi,
  65. mi,mi,sao,sao,sao,mi,la,la,h_dao,la,sao,re,l_la,dao,re,mi,re,re,
  66. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,mi,l_xi,l_la,

  67. mi,re,mi,l_la,
  68. l_la,l_la,l_xi,l_la,l_la,l_xi,
  69. l_sao,l_mi,
  70. dao,dao,l_la,dao,
  71. l_la,dao,re,mi,sao,la,mi,
  72. mi,sao,sao,sao,mi,mi,la,xi,la,sao,mi,re,l_la,l_la,dao,re,mi,re,re,
  73. re,mi,l_sao,l_sao,l_sao,l_mi,l_mi,
  74. re,re,mi,dao,
  75. l_sao,l_sao,l_mi,l_sao,l_la,l_la,
  76. mi,sao,la,
  77. //以下反复开始
  78. la,la,sao,la,sao,la,xi,la,sao,sao,
  79. sao,la,re,
  80. re,re,mi,mi,sao,la,mi,mi,mi,
  81. mi,sao,sao,sao,sao,mi,mi,la,xi,la,sao,mi,
  82. re,l_la,l_la,dao,re,mi,re,re,
  83. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  84. l_sao,l_sao,l_mi,l_sao,l_la,
  85. sao,la,re,re,re,mi,mi,sao,la,mi,mi,mi,
  86. mi,sao,sao,sao,mi,mi,la,xi,la,sao,mi,re,l_la,l_la,dao,re,mi,re,re,
  87. //mi,re,l_la,l_la,dao,re,mi,re,re,mi,la,
  88. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  89. l_sao,l_sao,l_mi,l_sao,l_la,l_la,mi,sao,la,
  90. //反复结束
  91. la,la,sao,la,sao,la,xi,la,sao,sao,

  92. sao,la,re,
  93. re,re,mi,mi,sao,la,mi,mi,mi,
  94. mi,sao,sao,sao,sao,mi,mi,la,xi,la,sao,mi,
  95. re,l_la,l_la,dao,re,mi,re,re,
  96. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  97. l_sao,l_sao,l_mi,l_sao,l_la,
  98. sao,la,re,re,re,mi,mi,sao,la,mi,mi,mi,
  99. mi,sao,sao,sao,mi,mi,la,xi,la,sao,mi,re,l_la,l_la,dao,re,mi,re,re,
  100. //mi,re,l_la,l_la,dao,re,mi,re,re,mi,la,
  101. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  102. l_sao,l_sao,l_mi,l_sao,l_la,l_la,mi,sao,la,
  103. /*
  104. la,la,sao,la,sao,la,xi,la,sao,sao,
  105. sao,la,re,
  106. re,re,mi,mi,sao,la,mi,mi,mi,
  107. mi,sao,sao,sao,sao,mi,mi,la,xi,la,sao,mi,
  108. re,l_la,l_la,dao,re,mi,re,re,
  109. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  110. l_sao,l_sao,l_mi,l_sao,l_la,
  111. sao,la,re,re,re,mi,mi,sao,la,mi,mi,mi,
  112. mi,sao,sao,sao,mi,mi,la,xi,la,sao,mi,re,l_la,l_la,dao,re,mi,re,re,
  113. mi,re,l_la,l_la,dao,re,mi,re,re,mi,la,
  114. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  115. l_sao,l_sao,l_mi,l_sao,l_la,l_la,mi,sao,la,
  116. //3
  117. la,la,sao,la,sao,la,xi,la,sao,sao,
  118. sao,la,re,
  119. re,re,mi,mi,sao,la,mi,mi,mi,
  120. mi,sao,sao,sao,sao,mi,mi,la,xi,la,sao,mi,
  121. re,l_la,l_la,dao,re,mi,re,re,
  122. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  123. l_sao,l_sao,l_mi,l_sao,l_la,
  124. sao,la,re,re,re,mi,mi,sao,la,mi,mi,mi,
  125. mi,sao,sao,sao,mi,mi,la,xi,la,sao,mi,re,l_la,l_la,dao,re,mi,re,re,
  126. mi,re,l_la,l_la,dao,re,mi,re,re,mi,la,
  127. re,mi,l_sao,l_sao,l_mi,l_sao,l_la,re,re,mi,dao,dao,
  128. l_sao,l_sao,l_mi,l_sao,l_la,l_la,mi,sao,la,*/
  129. //结束
  130. l_sao,l_sao,l_mi,l_sao,l_la,l_la,
  131.          0xff}; //以0xff作为音符的结束标志  
  132. //以下是简谱中每个音符的节拍
  133. //"4"对应4个延时单位"2"对应2个延时单位"1"对应1个延时单位  
  134. unsigned char code JP[ ]={4,1,1,4,1,1,2,   
  135.                      2,2,2,2,8,
  136.        4,2,3,1,2,2,
  137.        10,         4,2,2,4,4,
  138.        2,2,2,2,4,
  139.                      2,2,2,2,2,2,2,
  140.        10,
  141.        4,4,4,2,2,
  142.        4,2,4,4,
  143.        4,2,2,2,2,2,2,
  144.        10,
  145.        4,2,2,4,4,
  146.        2,2,2,2,6,
  147.        4,2,2,4,1,1,4,
  148.        10,
  149.        4,2,2,4,1,1,4,
  150.          10,
  151. 6,1,2,1,6,1,2,1,3,3,1,1,1,1,6,
  152. //节拍开始
  153. 1,1,1,12,
  154. 1,1,2,1,1,2,
  155. 2,12,
  156. 1,1,1,3,
  157. 1,3,2,2,3,6,
  158. 1,1,2,2,2,2,2,1,1,2,2,2,2,1,1,1,1,3,
  159. 1,1,3,1,2,2,1,1,2,6,
  160. 1,1,1,6,
  161. 1,1,1,2,1,1,
  162. 2,12,
  163. 1,1,1,6,
  164. 1,1,2,2,1,3,6,
  165. 2,2,2,1,1,2,2,1,1,2,2,1,1,2,1,1,1,1,3,
  166. 1,1,2,2,2,1,1,
  167. 2,1,1,4,
  168. 2,1,1,2,2,4,
  169. 2,1,1,
  170. //以下反复开始
  171. 3,1,1,2,2,2,2,2,2,3,

  172. 2,2,4,
  173. 1,2,1,1,1,3,2,2,3,
  174. 2,2,1,1,1,1,2,2,1,1,2,2,
  175. 2,1,1,1,1,1,1,3,
  176. 1,1,2,1,1,2,2,2,1,1,2,2,
  177. 2,1,1,2,2,
  178. 2,2,3,1,2,1,1,1,3,2,2,4,
  179. 1,2,1,1,1,2,2,1,1,2,2,2,1,1,1,1,1,1,3,
  180. //mi,re,l_la,l_la,dao,re,mi,re,re,mi,la,
  181. 1,1,2,1,1,2,2,2,1,1,2,2,
  182. 2,1,1,2,2,4,2,1,1,
  183. //反复结束
  184. 3,1,1,2,2,2,2,2,2,4,

  185. 2,2,3,
  186. 1,2,1,1,1,3,2,2,4,
  187. 2,2,1,1,1,1,2,2,1,1,2,2,
  188. 2,1,1,1,1,1,1,3,
  189. 1,1,2,1,1,2,2,2,1,1,2,2,
  190. 2,1,1,2,2,
  191. 2,2,6,1,2,1,1,1,6,2,2,4,
  192. 1,2,1,1,1,
  193. //结束
  194. 2,1,1,2,2,4,
  195. 1,1,1,3,1,1,1,
  196. 10       };
  197.     EA=1;         //开总中断
  198.     ET0=1;        //定时器T0中断允许
  199.       TMOD=0x00;    // 使用定时器T0的模式113位计数器
  200.     while(1)       //无限循环
  201.    {
  202.     i=0;   //从第1个音符f[0]开始播放
  203.        while(f[i]!=0xff)            //只要没有读到结束标志就继续播放
  204.       {
  205.               C=460830/f[i];     
  206.               TH0=(8192-C)/32;   //可证明这是13位计数器TH0高8位的赋初值方法
  207.               TL0=(8192-C)%32;   //可证明这是13位计数器TL0低5位的赋初值方法
  208.               TR0=1;             //启动定时器T0
  209.       for(j=0;j<JP[i];j++)  //控制节拍数
  210.                   delay();          //延时1个节拍单位
  211.       TR0=0;                //关闭定时器T0

  212.          i++;                 //播放下一个音符
  213.       }            
  214.   }   
  215. }
  216. //函数功能定时器T0的中断服务子程序使P3.7引脚输出音频的方波
  217. void Time0(void ) interrupt 1 using 1   
  218.   {
  219.     sound=!sound;      //将P3.7引脚输出电平取反形成方波   
  220.     TH0=(8192-C)/32;   //可证明这是13位计数器TH0高8位的赋初值方法
  221.     TL0=(8192-C)%32;   //可证明这是13位计数器TL0低5位的赋初值方法 }
  222. }
复制代码

可能有转发时有错我试验时除休止符外一切正常。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:213173 发表于 2021-3-2 16:59 | 只看该作者
所谓休止就是频率为0,蜂鸣器无输出,但要保证蜂鸣器是复位状态。可以设一个休止标志,在中断中计数判断休止时长。
//函数功能定时器T0的中断服务子程序使P3.7引脚输出音频的方波
void Time0(void ) interrupt 1 using 1   
{
        static unsigned i;
        if(xiuzhi)//xiuzhi标志=1
        {
                sound=1;//蜂鸣器初始态
                TH0=0x??;//??=重装值
                TL0=0x??;//
                i++;
                if(i>=x)//x=休止时长
                {
                        i=0;
                        xiuzhi=0;//休止结束
                }
        }
        else
        {
                sound=~sound;      //将P3.7引脚输出电平取反形成方波   
                TH0=(8192-C)/32;   //可证明这是13位计数器TH0高8位的赋初值方法
                TL0=(8192-C)%32;   //可证明这是13位计数器TL0低5位的赋初值方法
        }
}
回复

使用道具 举报

板凳
ID:886808 发表于 2021-3-2 17:48 来自手机 | 只看该作者
太谢谢你了,有空把休止符加上,重新检测一遍!把谱子补全,拍节找准。再次感感谢!
回复

使用道具 举报

地板
ID:3666 发表于 2021-3-2 20:30 | 只看该作者
你上面数组表是怎么算出来的
回复

使用道具 举报

5#
ID:886808 发表于 2021-3-3 10:24 来自手机 | 只看该作者
liushiming82 发表于 2021-3-2 20:30
你上面数组表是怎么算出来的

不用计算。宏定义的低音dao到高音xi后边的数值就是C调的实际振动频率。改变了曲谱的排列顺序,就改变了播放顺序。实际上用简谱1234567再加上高低音标志就更直观了。原例用的是拼音或英文标注。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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