找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2249|回复: 3
收起左侧

遥控音乐盒制作日志(一)

  [复制链接]
ID:695961 发表于 2022-5-8 11:58 | 显示全部楼层 |阅读模式
前几天带儿子逛商场,儿子看上一款音乐盒,小小的一个东西要几十块钱,感觉很不划算……于是带他吃了一顿比萨,很快他就忘了这回事啦(与儿子斗其乐无穷),回来以后,孩子又把这事记起来了,感情还是对音乐盒念念不忘啊,作为一名学习电子设计的小学生,正好借这个机会练练手,给孩子做一款独一无二的遥控音乐盒。

遥控这个东西实现手段很多,红外、蓝牙、wifi……做这玩意太复杂啦,咱们的主要目的是做音乐盒啊,于是花了8块从万能的某宝上买了一款【2262/2272四路无线遥控套件】(还包邮哦)


2262/2272

2262/2272


先用面包板搭一下,可是音乐从哪弄呢?当然从黑坛里搜啊。

记得很早之前在群里看到一位群友写过一篇【51单片机音乐盒1602显示 Proteus仿真程序】,地址为:
http://www.51hei.com/bbs/dpj-183341-1.html

可是……

可是……

可是看到一大段乐谱,我头直接就大了,这得需要多少单片机空间啊,咱的STC89才4K程序空间,本着写单片机要节约每一个字节的原则,我对这段乐谱进行了改造!!!压缩它,弄死它!原乐谱如下:

  1. //《烟花易冷》
  2. unsigned char code song1[]={
  3.      5,2,1, 3,2,1, 2,2,2, 2,2,4, 3,2,1, 1,2,1, 2,2,1, 3,2,4,
  4.          5,2,1, 3,2,1, 2,2,2, 2,2,2, 5,1,1, 3,2,1, 4,2,1, 3,2,4,
  5.          3,2,1, 3,2,1, 7,2,1, 3,2,1, 2,2,2, 1,2,1, 7,1,1, 1,2,1,
  6.          2,2,1, 3,2,1, 6,2,3, 6,1,1, 1,2,1, 3,2,1, 2,2,1, 6,1,1,
  7.          1,2,1, 7,1,1, 5,1,1, 6,1,6, 5,2,1, 3,2,1, 2,2,2, 2,2,1,
  8.          2,2,1, 3,2,1, 1,2,1, 2,2,1, 3,2,4, 5,2,1, 3,2,1, 2,2,2,
  9.          2,2,1, 2,2,1, 5,1,1, 3,2,1, 4,2,1, 3,2,4, 3,2,1, 3,2,1,
  10.          7,2,3, 3,2,1, 2,2,2, 1,2,1, 7,1,1, 1,2,1, 2,2,1, 3,2,1,
  11.          6,2,3, 6,1,1, 1,2,1, 3,2,1, 2,2,1, 6,1,1, 1,2,1, 7,1,2,
  12.          5,1,2, 6,1,6, 0,0,0 };

  13. //《发如雪》
  14. unsigned char code song2[]={
  15.      5,1,1, 2,2,1, 3,2,2, 2,2,1, 3,2,1, 5,2,1, 6,2,1, 5,2,3, 1,2,1, 2,2,1,
  16.          3,2,1, 6,2,1, 5,2,1, 3,2,1, 5,2,3, 5,2,1, 6,2,1, 1,3,2, 6,2,1, 5,2,1,
  17.          3,2,1, 5,2,1, 3,2,2, 1,2,1, 2,2,1, 3,2,1, 1,2,1, 6,1,1, 3,2,1, 2,2,1,
  18.          5,1,1, 2,2,1, 3,2,2, 2,2,1, 3,2,1, 5,2,1, 6,2,1, 5,2,3, 1,2,1, 2,2,1,
  19.          3,2,1, 6,2,1, 5,2,3, 5,2,1, 6,2,1, 1,3,2, 6,2,1,
  20.          5,2,1, 3,2,1, 5,2,1, 3,2,2, 1,2,1, 6,1,1, 3,2,1, 2,2,1, 1,2,1, 6,1,1,
  21.          1,2,1, 2,2,1, 2,2,1, 1,2,4, 0,0,0 };

  22. //《简单爱》
  23. unsigned char code song3[]={
  24.      5,1,1, 1,2,1, 2,2,1, 3,2,1, 2,2,1, 3,2,1, 4,2,1, 5,2,1, 5,2,1, 5,2,1,
  25.          4,2,1, 3,2,1, 2,2,3, 5,1,1, 1,2,1, 2,2,1, 3,2,1, 4,2,1, 5,2,1, 5,2,1,
  26.          5,2,1, 6,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2, 1,2,1, 6,1,1, 2,2,1, 2,2,1,
  27.          3,2,1, 3,2,1, 1,2,1, 5,2,1, 1,2,1, 5,2,1, 1,2,1, 7,1,1, 1,2,1, 1,2,1, 6,1,1,
  28.          2,2,1, 2,2,1, 3,2,1, 3,2,1, 5,2,1, 5,2,1,
  29.          5,2,1, 6,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2,  
  30.          5,1,1, 1,2,1, 2,1,2, 3,2,1, 2,2,1, 3,2,1, 4,2,1, 5,2,1, 5,2,1, 5,2,1,
  31.          4,2,1, 3,2,1, 2,2,3, 5,1,1, 1,2,1, 2,2,1, 3,2,1, 2,2,1, 3,2,1, 4,2,1,
  32.          5,2,1, 5,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2, 1,2,1, 6,1,1, 2,2,1, 2,2,1,
  33.          3,2,1, 3,2,1, 1,2,2, 5,2,1, 1,2,1, 5,2,1, 5,2,1, 7,1,1, 1,2,1, 0,0,0 };

  34. //《世上只有妈妈好》
  35. unsigned char code song4[]={
  36.      6,2,3, 5,2,1, 3,2,2, 5,2,2, 1,3,2, 6,2,1,
  37.          //6,2,3代表6,中音,3个半拍;
  38.          //5,2,1代表5,中音,1个半拍;
  39.          //3,2,2代表3,中音,2个半拍;
  40.          //5,2,2代表5,中音,2个半拍;
  41.          //1,3,2代表1,高音,2个半拍;
  42.          //...
  43.      5,2,1,6,2,4, 3,2,2, 5,2,1, 6,2,1, 5,2,2, 3,2,2, 1,2,1,6,1,1, 5,2,1,
  44.          3,2,1, 2,2,4, 2,2,3, 3,2,1, 5,2,2, 5,2,1, 6,2,1, 3,2,2, 2,2,2,
  45.          1,2,4, 5,2,3, 3,2,1,2,2,1, 1,2,1, 6,1,1, 1,2,1, 5,1,6, 0,0,0};

  46. //《当你孤单你会想起谁》
  47. unsigned char code song5[]={
  48.      3,2,2, 3,2,1, 4,2,1, 3,2,2, 2,2,1, 1,2,1,  2,2,2, 5,2,2, 2,2,2, 2,2,3,
  49.          1,2,2, 1,2,1, 2,2,1, 1,2,2, 7,1,1, 6,1,1, 7,1,2, 3,2,2, 7,1,2, 7,1,3,
  50.          6,1,2, 2,2,1, 3,2,1, 2,2,1, 1,2,1, 6,1,2, 5,1,2, 2,2,1, 3,2,1, 2,2,1,
  51.          1,2,1, 6,1,2, 6,1,2, 2,2,1, 3,2,1, 2,2,1, 1,2,1, 6,1,1, 7,1,1, 1,2,6, 0,0,0 };

  52. //《乡间小路》
  53. unsigned char code song6[]={
  54.      3,1,2, 3,1,1, 3,1,1, 6,0,1, 6,0,1, 1,1,2,
  55.      6,0,1, 5,0,1, 6,0,4, 6,0,2, 6,0,1 ,6,0,1, 6,0,2, 6,0,1, 1,1,1,
  56.      2,1,2, 2,1,1, 3,1,1, 2,1,4, 3,1,1, 3,1,1, 3,1,1, 2,1,1, 4,1,2,
  57.      4,1,2, 3,1,2, 2,1,1, 1,1,1, 2,1,4, 7,0,1, 7,0,1, 7,0,1, 6,0,1,
  58.      5,0,1, 5,0,1, 6,0,1, 7,0,1, 7,0,1, 6,0,1, 5,0,1, 6,0,4, 6,1,2,
  59.      3,1,1, 6,1,1, 7,1,1, 6,1,1, 5,1,1, 5,1,2, 5,1,1, 2,1,1, 5,1,1,
  60.      6,1,1, 5,1,1, 4,1,1, 4,1,2, 4,1,1, 3,1,1, 2,1,2, 1,1,1, 2,1,1,
  61.      3,1,1, 2,1,1, 1,1,1, 2,1,1, 3,1,4, 6,1,2, 3,1,1, 6,1,1, 7,1,1,
  62.          6,1,1, 5,1,1, 5,1,2, 2,1,1, 5,1,1, 6,1,1, 5,1,1, 4,1,1, 0,0,0};     

  63. //《送别》
  64. unsigned char code song7[]={
  65.      5,1,2, 3,1,3, 5,1,1, 1,2,3, 6,1,2, 1,2,2,
  66.      5,1,4, 5,1,2, 1,1,1, 2,1,1, 3,1,2, 2,1,1, 1,1,1, 2,1,4, 5,1,2,
  67.          3,1,1, 5,1,1, 1,2,2, 7,1,1, 6,1,2, 1,2,2, 5,1,4, 5,1,2, 2,1,1,
  68.          3,1,1, 4,1,2, 7,0,1, 1,1,4, 6,1,2, 1,2,2, 1,2,4, 7,1,2, 6,1,1,
  69.          7,1,1, 1,2,4, 6,1,1, 7,1,1, 1,2,1, 6,1,1, 6,1,1, 5,1,1, 3,1,1,
  70.          1,1,1, 2,1,8, 5,1,2, 3,1,1, 5,1,1, 1,2,2, 7,1,1, 6,1,2, 1,2,2,
  71.          5,1,4, 5,1,2, 2,1,1, 3,1,1, 4,1,2, 7,0,2, 1,1,4, 0,0,0};

  72. //《最浪漫的事》
  73. unsigned char code song8[]={
  74.      5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1, 3,1,1, 5,1,5,
  75.          5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1, 6,1,1, 1,1,5,
  76.          1,1,1, 2,1,1, 3,1,1, 2,1,1, 2,1,1, 2,1,1, 1,1,1, 2,1,1, 1,1,1, 6,1,1,
  77.          3,1,2, 2,1,3, 5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1,
  78.          6,1,1, 1,1,5, 1,1,1, 2,1,1, 3,1,1, 4,1,2, 4,1,1, 5,1,1, 6,1,1, 6,1,1,
  79.          5,1,1, 6,1,2, 1,2,1, 6,1,3, 1,2,1, 6,1,1, 5,1,1, 5,1,4, 1,1,1, 6,1,1,
  80.          5,1,5, 5,1,1, 6,1,1, 1,2,1, 3,1,1, 2,1,1, 3,1,1, 1,1,6, 0,0,0};
复制代码
仔细观查发现:



第一个数字音符的范围是:1到,代表哆来咪发...
第二个数字范围是:0123之一,代表低音\中音\高音\超高音(第几个八度)
第三个数字范围是:嗯……又仔细看了一下,最大的值为6,于是写了一段note.js程序,把每首乐谱进行了压缩(顺手10字节对齐一下),把三个字节压缩为1个字节,直接把乐谱的空间节约了三分之二……

压缩后的乐谱代码如下:


  1. //////////////////////////////////////////////
  2. //7-5:对应的音符1234567之一(第几个音),代表哆来咪发...
  3. //4-3:0:低音, 1:中音, 2:高音, 3:超高音(第几个八度)
  4. //2-0:时间长度+1, 以半拍为单位, 乐曲数据表的结尾是0
  5. //////////////////////////////////////////////
  6. //《烟花易冷》
  7. BYTE code song0[]={
  8.      0xb0, 0x70, 0x51, 0x53, 0x70, 0x30, 0x50, 0x73, 0xb0, 0x70,
  9.      0x51, 0x51, 0xa8, 0x70, 0x90, 0x73, 0x70, 0x70, 0xf0, 0x70,
  10.      0x51, 0x30, 0xe8, 0x30, 0x50, 0x70, 0xd2, 0xc8, 0x30, 0x70,
  11.      0x50, 0xc8, 0x30, 0xe8, 0xa8, 0xcd, 0xb0, 0x70, 0x51, 0x50,
  12.      0x50, 0x70, 0x30, 0x50, 0x73, 0xb0, 0x70, 0x51, 0x50, 0x50,
  13.      0xa8, 0x70, 0x90, 0x73, 0x70, 0x70, 0xf2, 0x70, 0x51, 0x30,
  14.      0xe8, 0x30, 0x50, 0x70, 0xd2, 0xc8, 0x30, 0x70, 0x50, 0xc8,
  15.      0x30, 0xe9, 0xa9, 0xcd, 0x00 };

  16. //《发如雪》
  17. BYTE code song1[]={
  18.      0xa8, 0x50, 0x71, 0x50, 0x70, 0xb0, 0xd0, 0xb2, 0x30, 0x50,
  19.      0x70, 0xd0, 0xb0, 0x70, 0xb2, 0xb0, 0xd0, 0x39, 0xd0, 0xb0,
  20.      0x70, 0xb0, 0x71, 0x30, 0x50, 0x70, 0x30, 0xc8, 0x70, 0x50,
  21.      0xa8, 0x50, 0x71, 0x50, 0x70, 0xb0, 0xd0, 0xb2, 0x30, 0x50,
  22.      0x70, 0xd0, 0xb2, 0xb0, 0xd0, 0x39, 0xd0, 0xb0, 0x70, 0xb0,
  23.      0x71, 0x30, 0xc8, 0x70, 0x50, 0x30, 0xc8, 0x30, 0x50, 0x50,
  24.      0x33, 0x00 };

  25. //《简单爱》
  26. BYTE code song2[]={
  27.      0xa8, 0x30, 0x50, 0x70, 0x50, 0x70, 0x90, 0xb0, 0xb0, 0xb0,
  28.      0x90, 0x70, 0x52, 0xa8, 0x30, 0x50, 0x70, 0x90, 0xb0, 0xb0,
  29.      0xb0, 0xd0, 0xb1, 0x50, 0x70, 0x31, 0x30, 0xc8, 0x50, 0x50,
  30.      0x70, 0x70, 0x30, 0xb0, 0x30, 0xb0, 0x30, 0xe8, 0x30, 0x30,
  31.      0xc8, 0x50, 0x50, 0x70, 0x70, 0xb0, 0xb0, 0xb0, 0xd0, 0xb1,
  32.      0x50, 0x70, 0x31, 0xa8, 0x30, 0x49, 0x70, 0x50, 0x70, 0x90,
  33.      0xb0, 0xb0, 0xb0, 0x90, 0x70, 0x52, 0xa8, 0x30, 0x50, 0x70,
  34.      0x50, 0x70, 0x90, 0xb0, 0xb0, 0xb1, 0x50, 0x70, 0x31, 0x30,
  35.      0xc8, 0x50, 0x50, 0x70, 0x70, 0x31, 0xb0, 0x30, 0xb0, 0xb0,
  36.      0xe8, 0x30, 0x00 };

  37. //《世上只有妈妈好》
  38. BYTE code song3[]={
  39.      0xd2, 0xb0, 0x71, 0xb1, 0x39, 0xd0, 0xb0, 0xd3, 0x71, 0xb0,
  40.      0xd0, 0xb1, 0x71, 0x30, 0xc8, 0xb0, 0x70, 0x53, 0x52, 0x70,
  41.      0xb1, 0xb0, 0xd0, 0x71, 0x51, 0x33, 0xb2, 0x70, 0x50, 0x30,
  42.      0xc8, 0x30, 0xad, 0x00};

  43. //《当你孤单你会想起谁》
  44. BYTE code song4[]={
  45.      0x71, 0x70, 0x90, 0x71, 0x50, 0x30, 0x51, 0xb1, 0x51, 0x52,
  46.      0x31, 0x30, 0x50, 0x31, 0xe8, 0xc8, 0xe9, 0x71, 0xe9, 0xea,
  47.      0xc9, 0x50, 0x70, 0x50, 0x30, 0xc9, 0xa9, 0x50, 0x70, 0x50,
  48.      0x30, 0xc9, 0xc9, 0x50, 0x70, 0x50, 0x30, 0xc8, 0xe8, 0x35,
  49.      0x00 };
  50.         
  51. //《乡间小路》
  52. BYTE code song5[]={
  53.      0x69, 0x68, 0x68, 0xc0, 0xc0, 0x29, 0xc0, 0xa0, 0xc3, 0xc1,
  54.      0xc0, 0xc0, 0xc1, 0xc0, 0x28, 0x49, 0x48, 0x68, 0x4b, 0x68,
  55.      0x68, 0x68, 0x48, 0x89, 0x89, 0x69, 0x48, 0x28, 0x4b, 0xe0,
  56.      0xe0, 0xe0, 0xc0, 0xa0, 0xa0, 0xc0, 0xe0, 0xe0, 0xc0, 0xa0,
  57.      0xc3, 0xc9, 0x68, 0xc8, 0xe8, 0xc8, 0xa8, 0xa9, 0xa8, 0x48,
  58.      0xa8, 0xc8, 0xa8, 0x88, 0x89, 0x88, 0x68, 0x49, 0x28, 0x48,
  59.      0x68, 0x48, 0x28, 0x48, 0x6b, 0xc9, 0x68, 0xc8, 0xe8, 0xc8,
  60.      0xa8, 0xa9, 0x48, 0xa8, 0xc8, 0xa8, 0x88, 0x00};

  61. //《送别》
  62. BYTE code song6[]={
  63.      0xa9, 0x6a, 0xa8, 0x32, 0xc9, 0x31, 0xab, 0xa9, 0x28, 0x48,
  64.      0x69, 0x48, 0x28, 0x4b, 0xa9, 0x68, 0xa8, 0x31, 0xe8, 0xc9,
  65.      0x31, 0xab, 0xa9, 0x48, 0x68, 0x89, 0xe0, 0x2b, 0xc9, 0x31,
  66.      0x33, 0xe9, 0xc8, 0xe8, 0x33, 0xc8, 0xe8, 0x30, 0xc8, 0xc8,
  67.      0xa8, 0x68, 0x28, 0x4e, 0xa9, 0x68, 0xa8, 0x31, 0xe8, 0xc9,
  68.      0x31, 0xab, 0xa9, 0x48, 0x68, 0x89, 0xe1, 0x2b, 0x00};

  69. //《最浪漫的事》
  70. BYTE code song7[]={
  71.      0xa8, 0xc8, 0x30, 0xc9, 0xc8, 0xa8, 0xc8, 0xa8, 0x68, 0xac,
  72.      0xa8, 0xc8, 0x30, 0xc9, 0xc8, 0xa8, 0xc8, 0xa8, 0xc8, 0x2c,
  73.      0x28, 0x48, 0x68, 0x48, 0x48, 0x48, 0x28, 0x48, 0x28, 0xc8,
  74.      0x69, 0x4a, 0xa8, 0xc8, 0x30, 0xc9, 0xc8, 0xa8, 0xc8, 0xa8,
  75.      0xc8, 0x2c, 0x28, 0x48, 0x68, 0x89, 0x88, 0xa8, 0xc8, 0xc8,
  76.      0xa8, 0xc9, 0x30, 0xca, 0x30, 0xc8, 0xa8, 0xab, 0x28, 0xc8,
  77.      0xac, 0xa8, 0xc8, 0x30, 0x68, 0x48, 0x68, 0x2d, 0x00};
复制代码

note.js压缩代码标例:


  1. let tt = [5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1, 3,1,1, 5,1,5,
  2.          5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1, 6,1,1, 1,1,5,
  3.          1,1,1, 2,1,1, 3,1,1, 2,1,1, 2,1,1, 2,1,1, 1,1,1, 2,1,1, 1,1,1, 6,1,1,
  4.          3,1,2, 2,1,3, 5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1,
  5.          6,1,1, 1,1,5, 1,1,1, 2,1,1, 3,1,1, 4,1,2, 4,1,1, 5,1,1, 6,1,1, 6,1,1,
  6.          5,1,1, 6,1,2, 1,2,1, 6,1,3, 1,2,1, 6,1,1, 5,1,1, 5,1,4, 1,1,1, 6,1,1,
  7.          5,1,5, 5,1,1, 6,1,1, 1,2,1, 3,1,1, 2,1,1, 3,1,1, 1,1,6, 0,0,0];

  8. let count = 0;
  9. let offset = 0;
  10. let str = ''
  11. while(tt[offset] != 0) {
  12.         let tmp = 0;
  13.         tmp += tt[offset] << 5;
  14.         tmp += tt[offset + 1] << 3;
  15.         if(tt[offset + 2] >= 8)
  16.                 tt[offset + 2] = 7;

  17.         tmp += tt[offset + 2] - 1;
  18.         //str += '0x' + tt[offset] + tt[offset + 1] + ',' + tt[offset + 2] + ', ';
  19.         str += '0x' + tmp.toString(16) + ', ';
  20.         offset += 3;
  21.         //console.log('     ' + str);

  22.         if(++count >= 10) {
  23.                 console.log('     ' + str);
  24.                 count = 0;
  25.                 str = '';
  26.         }
  27. }

  28. console.log('     ' + str + '0x00');
复制代码

使用单片机的T2(16位自动重装定时器)驱动发生,因为人的听力是非常敏感的,程序执行过程中把T2设置为最高优先级!

另外,原文的控制部分看的我也是一脸的蒙B。。。原文代码如下:

  1. ////////////////////////////////////////////////////////////////////////////////////
  2. void music_play(void)//播放相应歌曲的某个音符
  3. {
  4.         if(((music_num==1)&&(play_enable==1))&&(power_enable==1))
  5.         {
  6.                 LCDDispNum(5,2,music_num);
  7.                 fre=song1[num]+7*song1[num+1]-1;//第i个是音符,第i+1个是第几个八度
  8.                 timer0h=FREQH[fre];                    //从数据表中读出频率数值,实际上是定时的时间长度
  9.             timer0l=FREQL[fre];
  10.             time=song1[num+2];              //读出时间长度数值
  11.             num+=3;
  12.                 if(fre<0)                //判断歌曲的结束位,结束后转到下一首
  13.                 {
  14.                         num=0;            //下一首从头播放
  15.                         miao=0;
  16.                         music_num=2;
  17.             }
  18.                 song();                //发出一个音符
  19.         }
  20. ////////////////////////////////////////////////////////////////////////////////////
  21.         if(((music_num==2)&&(play_enable==1))&&(power_enable==1))
  22.         {  
  23.                 LCDDispNum(5,2,music_num);
  24.                 fre=song2[num]+7*song2[num+1]-1;
  25.                 timer0h=FREQH[fre];
  26.             timer0l=FREQL[fre];
  27.             time=song2[num+2];
  28.             num+=3;
  29.                 if(fre<0)
  30.                 {
  31.                         num=0;
  32.                         miao=0;
  33.                         music_num=3;
  34.             }
  35.                 song();               
  36.         }
  37. ////////////////////////////////////////////////////////////////////////////////////
  38.                 if(((music_num==3)&&(play_enable==1))&&(power_enable==1))
  39.         {  
  40.                 LCDDispNum(5,2,music_num);
  41.                 fre=song3[num]+7*song3[num+1]-1;
  42.                 timer0h=FREQH[fre];
  43.             timer0l=FREQL[fre];
  44.             time=song3[num+2];
  45.             num+=3;
  46.                 if(fre<0)
  47.                 {
  48.                         num=0;
  49.                         miao=0;
  50.                         music_num=4;
  51.             }
  52.                 song();               
  53.         }
  54. ////////////////////////////////////////////////////////////////////////////////////
  55.         if(((music_num==4)&&(play_enable==1))&&(power_enable==1))
  56.         {
  57.                 LCDDispNum(5,2,music_num);
  58.                 fre=song4[num]+7*song4[num+1]-1;
  59.                 timer0h=FREQH[fre];
  60.             timer0l=FREQL[fre];
  61.             time=song4[num+2];
  62.             num+=3;
  63.                 if(fre<0)
  64.                 {
  65.                         num=0;
  66.                         miao=0;
  67.                         music_num=5;
  68.             }
  69.                 song();               
  70.         }
  71. ////////////////////////////////////////////////////////////////////////////////////
  72.         if(((music_num==5)&&(play_enable==1))&&(power_enable==1))
  73.         {
  74.                 LCDDispNum(5,2,music_num);
  75.                 fre=song5[num]+7*song5[num+1]-1;
  76.                 timer0h=FREQH[fre];
  77.             timer0l=FREQL[fre];
  78.             time=song5[num+2];
  79.             num+=3;
  80.                 if(fre<0)
  81.                 {
  82.                         num=0;
  83.                         miao=0;
  84.                         music_num=1;
  85.             }
  86.                 song();               
  87.         }

  88. ////////////////////////////////////////////////////////////////////////////////////
  89. }
复制代码

额,好吧,再改!把每首乐谱的内存地址记录下来


  1. // 记录每个曲子的地址
  2. uint16 code songAddr[] = {song0, song1, song2, song3, song4, song5, song6, song7};
复制代码

这样就可以使用序号代表乐曲了。修改后的播放与控制部分如下(播放时间和按钮防抖使用和个软件定时器来控制,防止程序进入空转等待,影响音乐的播放):



  1. /**
  2. * 初始化音乐
  3. */
  4. void MusicInit()
  5. {
  6.         SPEAK = 1;                // 设定为高电位
  7.         
  8.         // 初始化T2
  9.         PT2 = 1;                // 将中断2设置为最高优先级
  10.         //PT2H = 1;
  11.         
  12.         T2MOD = 0;                // 初始化模式寄存器
  13.         T2CON = 0;                // 初始化控制寄存器
  14.         ET2 = 1;                // 开启中断
  15.         
  16.         // 播放第1个音符
  17.         //PlayNote();
  18.         PlayMusic(5);
  19. }

  20. /**
  21. * 播放音乐
  22. * index 音乐序号
  23. */
  24. void PlayMusic(uint8 index)
  25. {
  26.         TR2 = 0;                                        // 停止定时器2
  27.         timers[0].enabled = FALSE;        // 停止音符演奏
  28.         currMusic = index;                        // 要播放的音乐序号
  29.         musicOffset = 0;                        // 音乐偏移量为0
  30.         PlayNote();                                        // 开始播放第1个音符
  31. }

  32. /**
  33. * 上一首
  34. */
  35. void PreviousMusic()
  36. {
  37.         currMusic--;
  38.         if(currMusic <= 1)
  39.                 currMusic = 7;
  40.         
  41.         PlayMusic(currMusic);
  42. }

  43. /**
  44. * 下一首
  45. */
  46. void NextMusic()
  47. {
  48.         currMusic++;
  49.         if(currMusic >= 8)
  50.                 currMusic = 0;
  51.         
  52.         PlayMusic(currMusic);
  53. }

  54. /**
  55. * 播放音符
  56. */
  57. void PlayNote()
  58. {
  59.         BYTE fre;        // 音乐频率
  60.         
  61.         BYTE code *musicAddr = (BYTE*)songAddr[currMusic];
  62.         BYTE tmp = *(musicAddr + musicOffset);
  63.         
  64.         // 判断是否播放完毕
  65.         if(tmp == 0)
  66.         {
  67.                 SPEAK = 1;
  68.                 //CLOSE_GREEN_LED();                        // 关闭LED
  69.                 timers[0].enabled = FALSE;
  70.                 return;
  71.         }
  72.         
  73.         fre = ((tmp & 0xF0) >> 5) + ((tmp & 0x18) >> 3) * 7 - 1;
  74.         TL2 = FrL[fre];                        // 设置定时初值
  75.         TH2 = FrH[fre];                        // 设置定时初值
  76.         RCAP2L = FrL[fre];                // 设置定时重载值
  77.         RCAP2H = FrH[fre];                // 设置定时重载值

  78.         timers[0].count = ((tmp & 7) + 1) * 60;                // 300ms做为一拍
  79.         
  80.         if(!timers[0].enabled)
  81.         {
  82.                 timers[0].enabled = TRUE;
  83.                 timers[0].value = 0;
  84.         }
  85.         
  86.         // 开启定时器
  87.         TR2 = 1;
  88.         
  89.         //SWAP_GREEN_LED();        // 切换绿灯
  90. }

  91. /**
  92. * 音乐软中断处理程序
  93. */
  94. void MusicHandle()
  95. {
  96.         TR2 = 0;                        // 停止定时器2
  97.         musicOffset++;
  98.         PlayNote();                        // 播放音符
  99. }

  100. // T2硬件中断处理程序
  101. void tm2_isr() interrupt 5
  102. {
  103.         TF2 = 0;                        // 清除中断标志(T2定时器不会自动清除中断)
  104.         SPEAK = !SPEAK;
  105. }
复制代码

由于遥控板输出的是高电平,所以使用了一个4069(69?这个好,我喜欢!!!)将高电平转为低电平(先前使用NPN三极管搭了一个非门,考虑到摇控器上有四个按钮,所以换成了4069,某宝国产的4毛钱一片,进口的1块左右,包邮)

至此音乐部分改造完成,效果如下:


2.jpg



东西虽然简单,但是改造乐谱部分还是让我收获很大。整体程序编译下来,从2000多字节一下子降到893个字节,特别有成就感。


  1. Program Size: data=53.0 xdata=0 const=583 code=839
  2. creating hex file from ".\Objects\test"...
  3. ".\Objects\test" - 0 Error(s), 0 Warning(s).
  4. Build Time Elapsed:  00:00:01
复制代码


后面准备增加一个12232,用于显示播放时间,第几首乐曲,时间,温度、湿度、节日提醒功能。


感谢51黑论坛,感谢群友提供的乐谱以及设计灵感。


单片机代码等做完后统一发,嗯,先哄儿子玩会,哈哈……
51hei.png
视频: 视频.7z (2.77 MB, 下载次数: 6)

评分

参与人数 1黑币 +60 收起 理由
admin + 60 很给力!

查看全部评分

回复

使用道具 举报

ID:230742 发表于 2022-5-8 23:15 | 显示全部楼层
高手!支持一下。
回复

使用道具 举报

ID:1034262 发表于 2023-4-30 11:52 | 显示全部楼层
我做过一个电子八音盒,12通道,给孩子玩非常不错。
回复

使用道具 举报

ID:1070015 发表于 2023-6-14 21:33 | 显示全部楼层
代码可以发下嘛
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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