前几天带儿子逛商场,儿子看上一款音乐盒,小小的一个东西要几十块钱,感觉很不划算……于是带他吃了一顿比萨,很快他就忘了这回事啦(与儿子斗其乐无穷),回来以后,孩子又把这事记起来了,感情还是对音乐盒念念不忘啊,作为一名学习电子设计的小学生,正好借这个机会练练手,给孩子做一款独一无二的遥控音乐盒。

遥控这个东西实现手段很多,红外、蓝牙、wifi……做这玩意太复杂啦,咱们的主要目的是做音乐盒啊,于是花了8块从万能的某宝上买了一款【2262/2272四路无线遥控套件】(还包邮哦)
image.png
先用面包板搭一下,可是音乐从哪弄呢?当然从黑坛里搜啊。

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

可是……

可是……

可是看到一大段乐谱,我头直接就大了,这得需要多少单片机空间啊,咱的STC89才4K程序空间,本着写单片机要节约每一个字节的原则,我对这段乐谱进行了改造!!!压缩它,弄死它!原乐谱如下:
//《烟花易冷》
  • unsigned char code song1[]={
  •      5,2,1, 3,2,1, 2,2,2, 2,2,4, 3,2,1, 1,2,1, 2,2,1, 3,2,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,
  •          3,2,1, 3,2,1, 7,2,1, 3,2,1, 2,2,2, 1,2,1, 7,1,1, 1,2,1,
  •          2,2,1, 3,2,1, 6,2,3, 6,1,1, 1,2,1, 3,2,1, 2,2,1, 6,1,1,
  •          1,2,1, 7,1,1, 5,1,1, 6,1,6, 5,2,1, 3,2,1, 2,2,2, 2,2,1,
  •          2,2,1, 3,2,1, 1,2,1, 2,2,1, 3,2,4, 5,2,1, 3,2,1, 2,2,2,
  •          2,2,1, 2,2,1, 5,1,1, 3,2,1, 4,2,1, 3,2,4, 3,2,1, 3,2,1,
  •          7,2,3, 3,2,1, 2,2,2, 1,2,1, 7,1,1, 1,2,1, 2,2,1, 3,2,1,
  •          6,2,3, 6,1,1, 1,2,1, 3,2,1, 2,2,1, 6,1,1, 1,2,1, 7,1,2,
  •          5,1,2, 6,1,6, 0,0,0 };
  • //《发如雪》
  • unsigned char code song2[]={
  •      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,
  •          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,
  •          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,
  •          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,
  •          3,2,1, 6,2,1, 5,2,3, 5,2,1, 6,2,1, 1,3,2, 6,2,1,
  •          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,
  •          1,2,1, 2,2,1, 2,2,1, 1,2,4, 0,0,0 };
  • //《简单爱》
  • unsigned char code song3[]={
  •      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,
  •          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,
  •          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,
  •          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,
  •          2,2,1, 2,2,1, 3,2,1, 3,2,1, 5,2,1, 5,2,1,
  •          5,2,1, 6,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2,  
  •          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,
  •          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,
  •          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,
  •          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 };
  • //《世上只有妈妈好》
  • unsigned char code song4[]={
  •      6,2,3, 5,2,1, 3,2,2, 5,2,2, 1,3,2, 6,2,1,
  •          //6,2,3代表6,中音,3个半拍;
  •          //5,2,1代表5,中音,1个半拍;
  •          //3,2,2代表3,中音,2个半拍;
  •          //5,2,2代表5,中音,2个半拍;
  •          //1,3,2代表1,高音,2个半拍;
  •          //...
  •      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,
  •          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,
  •          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};
  • //《当你孤单你会想起谁》
  • unsigned char code song5[]={
  •      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,
  •          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,
  •          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,
  •          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 };
  • //《乡间小路》
  • unsigned char code song6[]={
  •      3,1,2, 3,1,1, 3,1,1, 6,0,1, 6,0,1, 1,1,2,
  •      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,
  •      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,
  •      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,
  •      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,
  •      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,
  •      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,
  •      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,
  •          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};     
  • //《送别》
  • unsigned char code song7[]={
  •      5,1,2, 3,1,3, 5,1,1, 1,2,3, 6,1,2, 1,2,2,
  •      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,
  •          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,
  •          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,
  •          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,
  •          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,
  •          5,1,4, 5,1,2, 2,1,1, 3,1,1, 4,1,2, 7,0,2, 1,1,4, 0,0,0};
  • //《最浪漫的事》
  • unsigned char code song8[]={
  •      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,
  •          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,
  •          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,
  •          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,
  •          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,
  •          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,
  •          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个字节,直接把乐谱的空间节约了三分之二……

    压缩后的乐谱代码如下:
    //////////////////////////////////////////////
  • //7-5:对应的音符1234567之一(第几个音),代表哆来咪发...
  • //4-3:0:低音, 1:中音, 2:高音, 3:超高音(第几个八度)
  • //2-0:时间长度+1, 以半拍为单位, 乐曲数据表的结尾是0
  • //////////////////////////////////////////////
  • //《烟花易冷》
  • BYTE code song0[]={
  •      0xb0, 0x70, 0x51, 0x53, 0x70, 0x30, 0x50, 0x73, 0xb0, 0x70,
  •      0x51, 0x51, 0xa8, 0x70, 0x90, 0x73, 0x70, 0x70, 0xf0, 0x70,
  •      0x51, 0x30, 0xe8, 0x30, 0x50, 0x70, 0xd2, 0xc8, 0x30, 0x70,
  •      0x50, 0xc8, 0x30, 0xe8, 0xa8, 0xcd, 0xb0, 0x70, 0x51, 0x50,
  •      0x50, 0x70, 0x30, 0x50, 0x73, 0xb0, 0x70, 0x51, 0x50, 0x50,
  •      0xa8, 0x70, 0x90, 0x73, 0x70, 0x70, 0xf2, 0x70, 0x51, 0x30,
  •      0xe8, 0x30, 0x50, 0x70, 0xd2, 0xc8, 0x30, 0x70, 0x50, 0xc8,
  •      0x30, 0xe9, 0xa9, 0xcd, 0x00 };
  • //《发如雪》
  • BYTE code song1[]={
  •      0xa8, 0x50, 0x71, 0x50, 0x70, 0xb0, 0xd0, 0xb2, 0x30, 0x50,
  •      0x70, 0xd0, 0xb0, 0x70, 0xb2, 0xb0, 0xd0, 0x39, 0xd0, 0xb0,
  •      0x70, 0xb0, 0x71, 0x30, 0x50, 0x70, 0x30, 0xc8, 0x70, 0x50,
  •      0xa8, 0x50, 0x71, 0x50, 0x70, 0xb0, 0xd0, 0xb2, 0x30, 0x50,
  •      0x70, 0xd0, 0xb2, 0xb0, 0xd0, 0x39, 0xd0, 0xb0, 0x70, 0xb0,
  •      0x71, 0x30, 0xc8, 0x70, 0x50, 0x30, 0xc8, 0x30, 0x50, 0x50,
  •      0x33, 0x00 };
  • //《简单爱》
  • BYTE code song2[]={
  •      0xa8, 0x30, 0x50, 0x70, 0x50, 0x70, 0x90, 0xb0, 0xb0, 0xb0,
  •      0x90, 0x70, 0x52, 0xa8, 0x30, 0x50, 0x70, 0x90, 0xb0, 0xb0,
  •      0xb0, 0xd0, 0xb1, 0x50, 0x70, 0x31, 0x30, 0xc8, 0x50, 0x50,
  •      0x70, 0x70, 0x30, 0xb0, 0x30, 0xb0, 0x30, 0xe8, 0x30, 0x30,
  •      0xc8, 0x50, 0x50, 0x70, 0x70, 0xb0, 0xb0, 0xb0, 0xd0, 0xb1,
  •      0x50, 0x70, 0x31, 0xa8, 0x30, 0x49, 0x70, 0x50, 0x70, 0x90,
  •      0xb0, 0xb0, 0xb0, 0x90, 0x70, 0x52, 0xa8, 0x30, 0x50, 0x70,
  •      0x50, 0x70, 0x90, 0xb0, 0xb0, 0xb1, 0x50, 0x70, 0x31, 0x30,
  •      0xc8, 0x50, 0x50, 0x70, 0x70, 0x31, 0xb0, 0x30, 0xb0, 0xb0,
  •      0xe8, 0x30, 0x00 };
  • //《世上只有妈妈好》
  • BYTE code song3[]={
  •      0xd2, 0xb0, 0x71, 0xb1, 0x39, 0xd0, 0xb0, 0xd3, 0x71, 0xb0,
  •      0xd0, 0xb1, 0x71, 0x30, 0xc8, 0xb0, 0x70, 0x53, 0x52, 0x70,
  •      0xb1, 0xb0, 0xd0, 0x71, 0x51, 0x33, 0xb2, 0x70, 0x50, 0x30,
  •      0xc8, 0x30, 0xad, 0x00};
  • //《当你孤单你会想起谁》
  • BYTE code song4[]={
  •      0x71, 0x70, 0x90, 0x71, 0x50, 0x30, 0x51, 0xb1, 0x51, 0x52,
  •      0x31, 0x30, 0x50, 0x31, 0xe8, 0xc8, 0xe9, 0x71, 0xe9, 0xea,
  •      0xc9, 0x50, 0x70, 0x50, 0x30, 0xc9, 0xa9, 0x50, 0x70, 0x50,
  •      0x30, 0xc9, 0xc9, 0x50, 0x70, 0x50, 0x30, 0xc8, 0xe8, 0x35,
  •      0x00 };
  •         
  • //《乡间小路》
  • BYTE code song5[]={
  •      0x69, 0x68, 0x68, 0xc0, 0xc0, 0x29, 0xc0, 0xa0, 0xc3, 0xc1,
  •      0xc0, 0xc0, 0xc1, 0xc0, 0x28, 0x49, 0x48, 0x68, 0x4b, 0x68,
  •      0x68, 0x68, 0x48, 0x89, 0x89, 0x69, 0x48, 0x28, 0x4b, 0xe0,
  •      0xe0, 0xe0, 0xc0, 0xa0, 0xa0, 0xc0, 0xe0, 0xe0, 0xc0, 0xa0,
  •      0xc3, 0xc9, 0x68, 0xc8, 0xe8, 0xc8, 0xa8, 0xa9, 0xa8, 0x48,
  •      0xa8, 0xc8, 0xa8, 0x88, 0x89, 0x88, 0x68, 0x49, 0x28, 0x48,
  •      0x68, 0x48, 0x28, 0x48, 0x6b, 0xc9, 0x68, 0xc8, 0xe8, 0xc8,
  •      0xa8, 0xa9, 0x48, 0xa8, 0xc8, 0xa8, 0x88, 0x00};
  • //《送别》
  • BYTE code song6[]={
  •      0xa9, 0x6a, 0xa8, 0x32, 0xc9, 0x31, 0xab, 0xa9, 0x28, 0x48,
  •      0x69, 0x48, 0x28, 0x4b, 0xa9, 0x68, 0xa8, 0x31, 0xe8, 0xc9,
  •      0x31, 0xab, 0xa9, 0x48, 0x68, 0x89, 0xe0, 0x2b, 0xc9, 0x31,
  •      0x33, 0xe9, 0xc8, 0xe8, 0x33, 0xc8, 0xe8, 0x30, 0xc8, 0xc8,
  •      0xa8, 0x68, 0x28, 0x4e, 0xa9, 0x68, 0xa8, 0x31, 0xe8, 0xc9,
  •      0x31, 0xab, 0xa9, 0x48, 0x68, 0x89, 0xe1, 0x2b, 0x00};
  • //《最浪漫的事》
  • BYTE code song7[]={
  •      0xa8, 0xc8, 0x30, 0xc9, 0xc8, 0xa8, 0xc8, 0xa8, 0x68, 0xac,
  •      0xa8, 0xc8, 0x30, 0xc9, 0xc8, 0xa8, 0xc8, 0xa8, 0xc8, 0x2c,
  •      0x28, 0x48, 0x68, 0x48, 0x48, 0x48, 0x28, 0x48, 0x28, 0xc8,
  •      0x69, 0x4a, 0xa8, 0xc8, 0x30, 0xc9, 0xc8, 0xa8, 0xc8, 0xa8,
  •      0xc8, 0x2c, 0x28, 0x48, 0x68, 0x89, 0x88, 0xa8, 0xc8, 0xc8,
  •      0xa8, 0xc9, 0x30, 0xca, 0x30, 0xc8, 0xa8, 0xab, 0x28, 0xc8,
  •      0xac, 0xa8, 0xc8, 0x30, 0x68, 0x48, 0x68, 0x2d, 0x00};
  • 复制代码
    note.js压缩代码标例:
    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,
  •          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,
  •          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,
  •          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,
  •          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,
  •          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,
  •          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];
  • let count = 0;
  • let offset = 0;
  • let str = ''
  • while(tt[offset] != 0) {
  •         let tmp = 0;
  •         tmp += tt[offset] << 5;
  •         tmp += tt[offset + 1] << 3;
  •         if(tt[offset + 2] >= 8)
  •                 tt[offset + 2] = 7;
  •         tmp += tt[offset + 2] - 1;
  •         //str += '0x' + tt[offset] + tt[offset + 1] + ',' + tt[offset + 2] + ', ';
  •         str += '0x' + tmp.toString(16) + ', ';
  •         offset += 3;
  •         //console.log('     ' + str);
  •         if(++count >= 10) {
  •                 console.log('     ' + str);
  •                 count = 0;
  •                 str = '';
  •         }
  • }
  • console.log('     ' + str + '0x00');
  • 复制代码
    使用单片机的T2(16位自动重装定时器)驱动发生,因为人的听力是非常敏感的,程序执行过程中把T2设置为最高优先级!

    另外,原文的控制部分看的我也是一脸的蒙B。。。原文代码如下:
    ////////////////////////////////////////////////////////////////////////////////////
  • void music_play(void)//播放相应歌曲的某个音符
  • {
  •         if(((music_num==1)&&(play_enable==1))&&(power_enable==1))
  •         {
  •                 LCDDispNum(5,2,music_num);
  •                 fre=song1[num]+7*song1[num+1]-1;//第i个是音符,第i+1个是第几个八度
  •                 timer0h=FREQH[fre];                    //从数据表中读出频率数值,实际上是定时的时间长度
  •             timer0l=FREQL[fre];
  •             time=song1[num+2];              //读出时间长度数值
  •             num+=3;
  •                 if(fre<0)                //判断歌曲的结束位,结束后转到下一首
  •                 {
  •                         num=0;            //下一首从头播放
  •                         miao=0;
  •                         music_num=2;
  •             }
  •                 song();                //发出一个音符
  •         }
  • ////////////////////////////////////////////////////////////////////////////////////
  •         if(((music_num==2)&&(play_enable==1))&&(power_enable==1))
  •         {  
  •                 LCDDispNum(5,2,music_num);
  •                 fre=song2[num]+7*song2[num+1]-1;
  •                 timer0h=FREQH[fre];
  •             timer0l=FREQL[fre];
  •             time=song2[num+2];
  •             num+=3;
  •                 if(fre<0)
  •                 {
  •                         num=0;
  •                         miao=0;
  •                         music_num=3;
  •             }
  •                 song();               
  •         }
  • ////////////////////////////////////////////////////////////////////////////////////
  •                 if(((music_num==3)&&(play_enable==1))&&(power_enable==1))
  •         {  
  •                 LCDDispNum(5,2,music_num);
  •                 fre=song3[num]+7*song3[num+1]-1;
  •                 timer0h=FREQH[fre];
  •             timer0l=FREQL[fre];
  •             time=song3[num+2];
  •             num+=3;
  •                 if(fre<0)
  •                 {
  •                         num=0;
  •                         miao=0;
  •                         music_num=4;
  •             }
  •                 song();               
  •         }
  • ////////////////////////////////////////////////////////////////////////////////////
  •         if(((music_num==4)&&(play_enable==1))&&(power_enable==1))
  •         {
  •                 LCDDispNum(5,2,music_num);
  •                 fre=song4[num]+7*song4[num+1]-1;
  •                 timer0h=FREQH[fre];
  •             timer0l=FREQL[fre];
  •             time=song4[num+2];
  •             num+=3;
  •                 if(fre<0)
  •                 {
  •                         num=0;
  •                         miao=0;
  •                         music_num=5;
  •             }
  •                 song();               
  •         }
  • ////////////////////////////////////////////////////////////////////////////////////
  •         if(((music_num==5)&&(play_enable==1))&&(power_enable==1))
  •         {
  •                 LCDDispNum(5,2,music_num);
  •                 fre=song5[num]+7*song5[num+1]-1;
  •                 timer0h=FREQH[fre];
  •             timer0l=FREQL[fre];
  •             time=song5[num+2];
  •             num+=3;
  •                 if(fre<0)
  •                 {
  •                         num=0;
  •                         miao=0;
  •                         music_num=1;
  •             }
  •                 song();               
  •         }
  • ////////////////////////////////////////////////////////////////////////////////////
  • }
  • 复制代码
    额,好吧,再改!把每首乐谱的内存地址记录下来
    // 记录每个曲子的地址
  • uint16 code songAddr[] = {song0, song1, song2, song3, song4, song5, song6, song7};
  • 复制代码
    这样就可以使用序号代表乐曲了。修改后的播放与控制部分如下(播放时间和按钮防抖使用和个软件定时器来控制,防止程序进入空转等待,影响音乐的播放):
    /**
  • * 初始化音乐
  • */
  • void MusicInit()
  • {
  •         SPEAK = 1;                // 设定为高电位
  •         
  •         // 初始化T2
  •         PT2 = 1;                // 将中断2设置为最高优先级
  •         //PT2H = 1;
  •         
  •         T2MOD = 0;                // 初始化模式寄存器
  •         T2CON = 0;                // 初始化控制寄存器
  •         ET2 = 1;                // 开启中断
  •         
  •         // 播放第1个音符
  •         //PlayNote();
  •         PlayMusic(5);
  • }
  • /**
  • * 播放音乐
  • * index 音乐序号
  • */
  • void PlayMusic(uint8 index)
  • {
  •         TR2 = 0;                                        // 停止定时器2
  •         timers[0].enabled = FALSE;        // 停止音符演奏
  •         currMusic = index;                        // 要播放的音乐序号
  •         musicOffset = 0;                        // 音乐偏移量为0
  •         PlayNote();                                        // 开始播放第1个音符
  • }
  • /**
  • * 上一首
  • */
  • void PreviousMusic()
  • {
  •         currMusic--;
  •         if(currMusic <= 1)
  •                 currMusic = 7;
  •         
  •         PlayMusic(currMusic);
  • }
  • /**
  • * 下一首
  • */
  • void NextMusic()
  • {
  •         currMusic++;
  •         if(currMusic >= 8)
  •                 currMusic = 0;
  •         
  •         PlayMusic(currMusic);
  • }
  • /**
  • * 播放音符
  • */
  • void PlayNote()
  • {
  •         BYTE fre;        // 音乐频率
  •         
  •         BYTE code *musicAddr = (BYTE*)songAddr[currMusic];
  •         BYTE tmp = *(musicAddr + musicOffset);
  •         
  •         // 判断是否播放完毕
  •         if(tmp == 0)
  •         {
  •                 SPEAK = 1;
  •                 //CLOSE_GREEN_LED();                        // 关闭LED
  •                 timers[0].enabled = FALSE;
  •                 return;
  •         }
  •         
  •         fre = ((tmp & 0xF0) >> 5) + ((tmp & 0x18) >> 3) * 7 - 1;
  •         TL2 = FrL[fre];                        // 设置定时初值
  •         TH2 = FrH[fre];                        // 设置定时初值
  •         RCAP2L = FrL[fre];                // 设置定时重载值
  •         RCAP2H = FrH[fre];                // 设置定时重载值
  •         timers[0].count = ((tmp & 7) + 1) * 60;                // 300ms做为一拍
  •         
  •         if(!timers[0].enabled)
  •         {
  •                 timers[0].enabled = TRUE;
  •                 timers[0].value = 0;
  •         }
  •         
  •         // 开启定时器
  •         TR2 = 1;
  •         
  •         //SWAP_GREEN_LED();        // 切换绿灯
  • }
  • /**
  • * 音乐软中断处理程序
  • */
  • void MusicHandle()
  • {
  •         TR2 = 0;                        // 停止定时器2
  •         musicOffset++;
  •         PlayNote();                        // 播放音符
  • }
  • // T2硬件中断处理程序
  • void tm2_isr() interrupt 5
  • {
  •         TF2 = 0;                        // 清除中断标志(T2定时器不会自动清除中断)
  •         SPEAK = !SPEAK;
  • }
  • 复制代码
    由于遥控板输出的是高电平,所以使用了一个4069(69?这个好,我喜欢!!!)将高电平转为低电平(先前使用NPN三极管搭了一个非门,考虑到摇控器上有四个按钮,所以换成了4069,某宝国产的4毛钱一片,进口的1块左右,包邮)

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

    image.png


    东西虽然简单,但是改造乐谱部分还是让我收获很大。整体程序编译下来,从2000多字节一下子降到893个字节,特别有成就感。
    Program Size: data=53.0 xdata=0 const=583 code=839
  • creating hex file from ".\Objects\test"...
  • ".\Objects\test" - 0 Error(s), 0 Warning(s).
  • Build Time Elapsed:  00:00:01
  • 复制代码

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

    单片机代码等做完后统一发,嗯,先哄儿子玩会,哈哈……