打印

学校举行电子设计大赛,准备做一个“电子播放琴”。

[复制链接]
2337|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 流氓兔v 于 2011-4-22 23:58 编辑

学校举行电子设计大赛,准备做一个“电子播放琴”。




3-18号:完成音乐解码程序


3-20号:根据数据结构里的目录结构建立歌曲列表。

3-29号:成功改用一个MCU播放两个音,多谢stycx!

4-9号:用多重结构体写出仿MP3的两层菜单的子程序,引用数据结构里的广义表(兄弟与孩子的关系)。



4-13号:修改菜单程序,原先只有第二层菜单才能作用,改为第一层菜单也能作用。

4-18号:DS1302万年历

4-24号:半期考,时间过得好快啊,程序好久没写了。。。



模块:

一、主MCU负责对从MCU的控制,12864的驱动和显示,DS1302万年历,按键扫描,数字电位器的控制;
二、从MCU相应主MCU的命令,控制数字电位器。

功能:
一、时间程序:读取DS1302的日期时间,在LCD上显示;

二、播放程序:1、歌曲存储格式:Music_Code={101,1(初始化), 音长,音高,音长,音高……0,0(结束)}。
                            音长: 音长个位:一个节拍分音,|1       |2         | 3
                                                1节拍  1/2节拍 1/3节拍……
                                  音长十位:0为分音断音,1为分音连音
                            音高: 音高个位:音符1,2,3,4,5,6,7,0休止
                                               音高十位:0为中音,1为低音,2为高音,3为最低音,4为最高音
                                  音高百位:0为不升半音,1为升半音

                    2、结构体目录索引,实现对歌曲编程的快速控制;
                                               typedef struct{
                                                                           uint8 code *name;// “歌曲的名称”
                                                                           uint8code *codept;// 歌曲的数组地址
                                                                           uint8 note_time;// 播放的速度
                                                                   }Music_Struct;

                                                 Music_Struct codeMusic_Code[MMAX]={{"caimogu",Music_Code_caimogu,50},
                                                                                                          {"WangLing",Music_Code_WangLing,80}};
                   3、数字电位器控制音量大小,对歌曲尾音的处理:实现颤音和声音渐小的效果;
                   4、以握手方式经串行口与从MCU播放伴音,与伴音音量的控制;
                   5LCD显示歌曲名,音量,当前歌曲次序

三、弹奏程序:1、根据按键不同,发出各音符的声音,可发出不同音阶,和升音;
                   2、主MCUMCU伴音或发出不同的节拍。
                   3
LCD显示曲谱供使用者弹奏。


目前为止能想到的功能就这些了,希望朋友们建议建议,以后我想到的会更新此帖。

(作品还没完成,所以上传的PROTUES仿真文件有点乱)


附上音乐解码程序:8MS调用此程序一次,

PROTUES仿真的结果也一并发上,显示先用1602。由于PROTUES仿真时两个喇叭一起响声音很难听,可用开关闭从CPU的声音。


按键说明:减为确定键,乘为菜单选择键,8,9切换歌曲,最底下连行键为发音。


作品做好后发上全部代码。



/********************************************
* 文件:        Auto_Play.c
* 名称:自动播放音乐函数
* 平台:        AT89S52  12M晶振
* 编写:abao 2011-3-4
* 修改:
* 描述: 1.0版本
歌曲存储格式:Music_Code={101,1(初始化), 音长,音高, 音长,音高……0,0(结束)
                音长: 音长个位:一个节拍分音,|1       | 2      | 3      | 4     |……
                                                                         1节拍   1/2节拍  1/3节拍  1/4节拍 ……
                          音长十位:0为分音断音,1为分音连音                                 
                音高: 音高个位:音符1,2,3,4,5,6,7  0休止
                          音高十位:0为中音,1为低音,2为高音,3为最低音,4为最高音
                          音高百位:0为不升半音,1为升半音                 
********************************************/
#include "My_Function.h"
#include "Auto_Play.h"
#include "LCD_1602.h"

uint8 Evaluate_TH1, Evaluate_TL1;                        //T1赋值变量
uint8 Evaluate_Temp_TH1, Evaluate_Temp_TL1;        //TH1赋值暂存
uint8 Height_Note;                //音符
uint8 Height_Degree;        //音阶
uint8 Heigh_Half;                 //升音
uint16 Meter_Time;                   //分音半周期的时间
uint8 Music_Turn;                //歌曲的次序
uint8 Meter_Part;                //分音
uint8 Meter_Part_Time;        //分音时间暂存
uint8 Meter_Part_Run;        //连音

uint16 code Note_Time_Table[15]={0,956,865,759,716,638,568,506,        /*音符的半周期,中音,0为无效,从音符1开始*/
                                                                  903,804,733,676,602,536,478         /*中音升半音*/};
uint8 code Music_Code_caimogu[]={1,0, 1,0, 1,0,                                 //幽灵公主
                2,11, 2,12, 2,13, 2,14, 2,15, 2,16, 2,17, 2,1, 2,2, 2,3, 2,4, 2,5, 2,6, 2,7, 2,21, 2,22, 2,23, 2,24, 2,25, 2,26, 2,27,
                1,6, 2,23, 2,23, 1,23, 1,23, 2,23, 2,22, 1,21, 1,22, 1,0,
                11,22, 2,22, 2,23, 1,22, 1,21, 2,22, 2,21, 2,6, 2,5, 1,6, 1,0,
                1,3, 2,3, 2,5, 1,5, 1,5, 1,6, 2,6, 2,22, 1,21, 1,0,
                2,6, 2,6, 2,6, 2,21, 1,22, 2,21, 2,22, 11,23, 11,23, 11,23, 11,23, 11,23, 11,23, 11,23, 1,23,

                1,6, 2,23, 2,23, 1,23, 1,23, 2,23, 2,22, 1,21, 1,22, 1,0,
                11,22, 2,22, 2,23, 1,22, 1,21, 2,22, 2,21, 2,6, 2,5, 1,6, 1,0,
                1,3, 2,3, 2,5, 1,5, 1,5, 1,6, 2,6, 2,22, 1,21, 1,0,
                2,22, 2,22, 2,22, 2,21, 1,6, 1,5, 1,3, 1,0,
                11,7, 2,7, 2,6, 11,6, 11,6, 11,6, 11,6, 11,6, 11,6, 11,6, 1,6,

                2,0, 2,26, 2,26, 2,26, 2,26, 2,26, 2,26, 2,25, 2,23, 2,23, 2,23, 2,22, 11,23, 1,23, 2,0,
                2,22, 2,22, 2,22, 2,22, 2,22, 2,22, 2,23, 1,22, 2,22, 2,21, 11,22, 1,22, 2,0,
                2,26, 2,26, 2,26, 2,0, 2,23, 2,23, 2,23, 2,0,
                2,22, 2,22, 2,22, 2,0, 2,21, 2,21, 2,21, 11,3, 1,3,
                2,7, 2,7, 2,7, 2,6, 11,6, 11,6, 11,6, 11,6, 11,6, 11,6, 11,6, 1,6,   

                0,0};
uint8 code Music_Code_YouLing[]={1,0, 1,0, 1,0,                                          //幽灵公主
                 2,16, 2,3, 2,3, 2,2, 11,3, 2,3, 2,3, 2,5, 12,2, 1,2, 1,0,
                2,16, 2,3, 2,3, 2,2, 11,3, 2,3, 2,3, 11,5, 11,5, 1,0,
                2,3, 2,5, 2,6, 2,6, 2,6, 2,6, 11,6, 2,6, 2,6, 1,5, 1,2, 1,3, 1,0,
                2,2, 2,2, 2,2, 2,3, 1,2, 1,16, 11,3, 11,3, 11,3, 1,0,
                 
                2,16, 2,3, 2,3, 2,2, 11,3, 2,3,  2,5, 11,2, 11,2, 11,2, 1,0,
                2,16, 2,3, 2,3, 2,2, 2,3, 1,3, 2,5, 1,5, 1,0,
                2,3, 2,5, 2,6, 2,6, 2,6, 2,6, 11,6, 2,6, 2,6, 1,5, 1,2, 1,3, 1,0,
                2,2, 2,2, 2,2, 2,3, 2,2, 1,16, 2,1, 1,1,  1,0, 1,0,

                2,6, 2,6, 2,6, 2,7, 11,6, 2,6, 1,21, 1,7, 1,3, 1,0,
                1,2, 1,5, 1,3, 2,2, 2,3, 2,7, 2,7, 2,7, 2,21, 11,7, 2,7, 2,5, 1,21, 1,7, 1,3, 2,0,
                2,3, 12,6, 4,6, 14,5, 2,5, 2,4, 11,5, 1,5, 1,0,
                2,3, 2,5, 1,6, 1,21, 2,7, 1,3, 2,5, 11,6, 1,6, 1,0, 1,0,
                0,0};
uint8 code Music_Code_GuXiang[]={1,0, 1,0, 1,0, 2,0,                        //故乡的原风景
                2,2, 2,3, 2,5, 11,6, 11,6, 2,6, 16,7, 16,6, 16,7, 12,5, 4,5, 4,3, 11,7, 1,7, 2,0,         //中音一遍
                2,2, 2,3, 2,5, 11,6, 11,6, 2,6, 16,7, 16,6, 16,7, 12,5, 4,5, 4,22, 11,22, 12,22, 2,7, 2,0,
                2,2, 14,3, 4,5, 11,6, 11,6, 2,6, 16,7, 16,6, 16,7, 12,5, 4,5, 4,3, 11,7, 1,7, 2,0,
                2,2, 2,3, 2,5, 11,6, 11,6, 2,6, 16,7, 16,6, 16,7, 1,5, 11,3, 11,3, 2,3, 2,0,

                1,22, 11,23, 11,23, 1,23, 12,22, 14,23, 4,22, 11,22, 1,22, 2,7, 2,7, 2,0,
                1,22, 14,23, 14,22, 11,23, 11,23, 2,23, 12,22, 14,23, 4,22, 11,22, 2,22, 2,7, 2,7, 2,0,
                2,5, 2,7, 14,6, 14,5, 11,6, 11,6, 2,6, 12,5, 14,5, 4,3, 11,7, 11,7, 2,7, 2,0,
                2,5, 2,7, 14,6, 14,5, 11,6, 1,6, 14,7, 14,6, 14,7, 14,6, 1,5, 11,3, 11,3, 11,3, 1,3, 1,0, 1,0, 1,0, 1,0,

                2,22, 2,23, 2,25, 11,26, 11,26, 2,26, 16,27, 16,26, 16,27, 12,25, 4,25, 4,23, 11,27, 1,27, 2,0,        //高音一遍
                2,22, 2,23, 2,25, 11,26, 11,26, 2,26, 16,27, 16,26, 16,27, 12,25, 4,25, 4,42, 11,42, 12,42, 2,27, 2,0,
                2,22, 14,23, 4,25, 11,26, 11,26, 2,26, 16,27, 16,26, 16,27, 12,25, 4,25, 4,23, 11,27, 1,27, 2,0,
                2,22, 2,23, 2,25, 11,26, 11,26, 2,26, 16,27, 16,26, 16,27, 1,25, 11,23, 11,23, 2,23, 2,0,

                1,42, 11,43, 11,43, 1,43, 12,42, 14,43, 4,42, 11,42, 1,42, 2,27, 2,27, 2,0,
                1,42, 14,43, 14,42, 11,43, 11,43, 2,43, 12,42, 14,43, 4,42, 11,42, 2,42, 2,27, 2,27, 2,0,
                2,25, 2,27, 14,26, 14,25, 11,26, 11,26, 2,26, 12,25, 14,25, 4,23, 11,27, 11,27, 2,27, 2,0,
                2,25, 2,27, 14,26, 14,25, 11,26, 1,26, 14,27, 14,26, 14,27, 14,26, 1,25, 11,23, 11,23, 11,23, 1,23, 1,0, 1,0, 1,0, 1,0,
                0,0};                                                        
uint8 code Music_Code_WangLing[]={1,0, 1,0, 1,0,         //亡灵序曲
           2,0, 4,6, 4,7, 1,21, 2,0, 4,6, 4,7, 1,21, 2,0, 4,7, 4,6, 1,7, 4,0, 4,3, 4,21, 4,7, 4,6, 4,0,
           4,6, 4,7, 4,6, 1,24, 2,0, 4,23, 4,22, 1,23, 2,0, 4,22, 4,21, 1,22, 12,0, 4,0, 4,23, 1,24, 2,0,
           4,23, 4,22, 1,27, 2,0, 4,26, 4,25, 1,26, 2,0, 4,25, 4,24, 1,25, 2,24, 2,23, 2,23, 2,24, 1,22, 2,0,
//           1,0, 2,0,
//     4,26, 4,27, 1,41, 2,0, 4,26, 4,27, 1,41, 2,0, 4,27, 4,26, 1,27, 4,0, 4,23, 4,41, 4,27, 4,26, 4,0,
//           4,26, 4,27, 4,26, 1,44, 2,20, 4,43, 4,42, 1,43, 2,0, 4,42, 4,41, 1,42, 12,0, 4,0, 4,43, 1,44, 2,0,
//           4,43, 4,42, 1,47, 2,0, 4,46, 4,45, 1,46, 2,0, 4,45, 4,44, 1,45, 2,44, 2,43, 2,43, 2,44, 1,42, 2,0,
           2,7, 2,24, 2,27, 1,25, 2,0, 2,21, 2,25, 2,41, 2,25, 2,21, 1,6, 2,0,
           4,16, 4,17, 1,1, 2,0, 4,16, 4,17, 1,1, 2,0,
           4,17, 4,16, 1,17, 4,0, 4,13, 4,1, 4,17, 4,16, 1,16, 4,0, 4,16, 4,17, 4,16, 1,4, 2,0, 4,3, 4,2, 1,3, 2,1, 4,2, 4,1, 1,2, 2,0, 4,0,
           4,3, 1,4, 2,0, 4,3, 4,2, 4,7, 2,0, 4,6, 4,5, 1,6, 2,0, 4,5, 4,4, 1,5, 2,4, 2,3, 2,3, 2,4, 1,2, 2,0, 2,0,
           2,17, 2,4, 2,7, 1,5, 2,0,  
           0,0};
Music_Struct code Music_Code[MMAX]={{"caimogu",Music_Code_caimogu,50},
                                                                        {"YouLing",Music_Code_YouLing,100},
                                                                           {"GuXiang",Music_Code_GuXiang,100},
                                                                           {"WangLing",Music_Code_WangLing,80}};
uint8 *Music_PT;        //歌曲代码的指针

/*********************************
* 功能:音乐解码
* 编写:abao 2010-3-15
* 修改:
* 输入:
* 输出:Evaluate_TH1,Evaluate_TL1
* 使用:Display_State,CS0~CS4,IO_CS,IO_LED8                                          
*********************************/            
void change_music(void)        //切换歌曲
{
        uint8 temp=0;                                                //切换歌曲的信号
        if(KEY_PRE)                                                         //上一曲
        {
                ++temp;
                if(Music_Turn==0)                                //为第一首则返回最后一首
                        Music_Turn=MMAX;                        
                 --Music_Turn;
        }

        if(KEY_NEXT)                                                 //下一曲
        {
                ++temp;
                 ++Music_Turn;
                if(Music_Turn==MMAX)                        //为最后一首则返回第一首
                        Music_Turn=0;                        
        }

        if(*Music_PT==0)                                        //当前曲终
        {
                ++Music_PT;
                if(*Music_PT==0)
                {
                        ++temp;
                         ++Music_Turn;                                //下一曲
                        if(Music_Turn==MMAX)                //为最后一首则返回第一首
                                Music_Turn=0;
                }
                 --Music_PT;        
        }
        if(temp==0)                                                        //切换歌曲的信号值为0返回
                return;
        Music_PT=Music_Code[Music_Turn].codept;//指针为第一首歌的                        
        LCD_clean();                                                //清屏幕
}

void music(void)//音乐解码主函数
{
        uint8 note_time_temp;
        LCD_prints(0, 0, "Volume:20");
        LCD_printc(10, 0, Height_Note+0x30);         
        LCD_printc(13, 0, Music_Turn+0x31); //显示当前歌曲数和总数
        LCD_printc(14, 0, '/');
        LCD_printc(15, 0, MMAX+0x30);
        LCD_prints(0, 1, Music_Code[Music_Turn].name);
        --Meter_Part;                //当前音时间减8ms

        Meter_Part_Run=(*Music_PT )%100/10;        //取出当前音的连音
        ++Music_PT;                //指针定在音高处
        Heigh_Half=(*Music_PT)/100;                         //取出当前音的半音
        Height_Degree=(*Music_PT)%100/10;        //取出当前音的音阶
        Height_Note=(*Music_PT)%10;                        //取出当前音的音符
        ++Music_PT;                //指针定在下一音的音长处
        note_time_temp=Music_Code[Music_Turn].note_time / ((*Music_PT)%10); //取出下个音的时间
        Meter_Part_Time=note_time_temp;
        --Music_PT;                //指针放回当前音长处

        if(Heigh_Half==1)                                        //有升音
                 Height_Note=Height_Note+7;

        Meter_Time=Note_Time_Table[Height_Note];//查表得当前音符的半周期
        if(Height_Degree==1)                                //音符根据音阶改变
        {
                Meter_Time=Meter_Time*2;
        }else if(Height_Degree==2)
        {
                Meter_Time=Meter_Time/2;
        }else if(Height_Degree==3)
        {
                Meter_Time=Meter_Time*4;
        }else if(Height_Degree==4)
        {
                Meter_Time=Meter_Time/4;
        }

        Evaluate_Temp_TH1=(65536-Meter_Time) / 256;        //T1赋值暂存
        Evaluate_Temp_TL1=(65536-Meter_Time) % 256;
        TR2=0;                                                                    //防止赋值过程中断
        Evaluate_TL1=Evaluate_Temp_TL1;
        Evaluate_TH1=Evaluate_Temp_TH1;                 //T1赋值
        TR2=1;

        if(Height_Note==0 ||(Meter_Part_Run==0 & Meter_Part< (note_time_temp/8) ) )        //休止//无连音//最后20MS不发音                           
        {
                ET2=0;
                BEEPIO=0;                        
        }else
        {
                ET2=1;                                                        //发音
        }


        if(Meter_Part != 0)                                          //当前音的时间不为0
        {
                --Music_PT;        //指针放回当前音长处
        }else                                                                //时间为0则取下一音的指针
        {
                ++Music_PT;        //指针定在下一音的音长处
                Meter_Part=Meter_Part_Time;                  
        }        
        
        change_music();                                                //切换歌曲

        if(KEY_HOME)
        {
                ET2=0;
                BEEPIO=0;                                                //关闭发音
                 Main_State=0;                                        //进入功能选择模块
                LCD_clean();                                        //清屏幕
        }
}












电子播放琴.jpg (21.31 KB )

电子播放琴.jpg

proteus仿真.jpg (101.67 KB )

proteus仿真.jpg

CODE首次超过6000.jpg (34.62 KB )

CODE首次超过6000.jpg

电子播放琴PROTUES仿真文件.rar

46.59 KB

相关帖子

沙发
stycx| | 2011-3-26 16:44 | 只看该作者
1、歌曲存储在哪里?
2、发声设备能否采用专门midi芯片?
3、两个cpu是否有必要?
4、如果要求同时发出更多的声音,怎么扩展?

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
流氓兔v + 1
板凳
流氓兔v|  楼主 | 2011-3-26 20:31 | 只看该作者
本帖最后由 流氓兔v 于 2011-3-26 20:35 编辑
1、歌曲存储在哪里?
2、发声设备能否采用专门midi芯片?
3、两个cpu是否有必要?
4、如果要求同时发出更多的声音,怎么扩展?
stycx 发表于 2011-3-26 16:44


1、歌曲存在单片机片内,AT89S52有8K的存储,而且歌曲的代码段很小。

有个想法:用EEPROM来代替存储(像U盘那样),电脑用VC之类的写一个串行口的程序,通过单片机读写EEPROM实现歌曲代码的添加修改,并记录歌曲的头地址。

2,、发音没有midi芯片,直接读取频率的。很想做一个MIDI,会VS1003B芯片,接下来是存储卡……很难吧

3、由于AT89S52一个定时器用于控制节拍的时间,一个用于频率的形成。要形成主唱和伴唱应该要两个CPU吧。

4、不能同时发出更多声音,不知怎样扩展。

使用特权

评论回复
地板
stycx| | 2011-3-27 18:23 | 只看该作者
3# 流氓兔v

想办法解决上面的一个或几个问题吧

使用特权

评论回复
5
SHUJIEWS| | 2011-3-27 20:40 | 只看该作者
后生可畏

使用特权

评论回复
6
Metalor| | 2011-3-28 16:32 | 只看该作者
用一个MCU足已

使用特权

评论回复
7
abin0415| | 2011-3-28 21:37 | 只看该作者
想法不错。学习中

使用特权

评论回复
8
zxcscm| | 2011-3-29 09:23 | 只看该作者
还要做出实物吗,这两个MCU不太合适吧

使用特权

评论回复
9
流氓兔v|  楼主 | 2011-3-29 14:15 | 只看该作者
3# 流氓兔v  

想办法解决上面的一个或几个问题吧
stycx 发表于 2011-3-27 18:23


恩,现在改用一个CPU了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:流氓兔不流氓^

0

主题

9

帖子

1

粉丝