问答

汇集网友智慧,解决技术难题

21ic问答首页 - 求个课程设计,51单片机的电子琴

51单片机 单片机 电子 电子琴 设计

求个课程设计,51单片机的电子琴 赏3000家园币

mnynt1212024-11-30
求个课程设计,51单片机的电子琴
回答 +关注 0
455人浏览 2人回答问题 分享 举报
2 个回答
  • #include <reg51.h>
    #include <absacc.h>
    #include <stdio.h>
    #include <math.h>                 //头文件       
    #define uchar unsigned char
    #define uint unsigned int          //宏定义
    uchar STH0;                                  //定时器变量
    uchar STL0;                                  //定时器变量
    bit FY=0;                                         //模式变量,为0时弹奏模式,为1时播放模式
    uchar Song_Index=0,Tone_Index=0;//单首歌曲音符数  
    uchar k, key;                                         //k:按键数值变量。key:按键的键值(也就是有按键按下时的P0口状态)
    sbit SPK=P3^7 ;                                 //定义喇叭的接口
    sbit LED1=P3^5;
    sbit LED2=P3^4;                                 //定义两个LED的接口
    uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,//数码管显示的数组(1 2 3 4 5 6 7 8 9)
                                                    0x88,0x83,0xc6,0xa1,0x86,0x8e,0x89,0xa3,0x8c,0xc8};        //(A B C D E F H O P N)
    unsigned char code num1[]=                        "   Music:       ";
    uchar code Song[][100]=         //内置音乐数组,song【歌曲序号】【音符顺序】
    {
            //        1        2        3        4        5        6        7
            //        8        9        10        11        12        13        14
            //        15        16        17        18        19        20        21

            {12,10,9,9,10,8,9,10,
            12,10,9,9,5,10,11,10,
            10,10,14,10,9,8,7,8,
            9,10,13,6,8,10,9,6,
            8,7,5,6,12,10,9,9,
            9,10,8,9,10,12,10,9,
            9,9,5,10,11,10,10,10,
            14,10,9,8,7,8,9,10,
            13,6,8,10,9,6,8,7,
            5,6,-1},                                 //烟花易冷

            {13,12,10,12,15,13,
            12,13,10,12,13,12,10,8,6,12,
            10,9,9,10,12,12,13,10,9,
            8,12,10,9,8,6,8,5,-1},//世上只有妈妈好

            {10,10,11,10,9,8,9,12,9,9,
            8,8,9,8,7,6,7,10,7,7,
            6,9,10,9,8,6,5,9,10,9,
            8,6,6,9,10,9,8,6,7,8,-1}, //当你孤单你会想起谁
             
            {5,3,5,8,6,8,
            5,5,1,2,3,2,1,2,5,
            3,5,8,7,6,8,5,5,2,
            3,4,0,1,6,8,8,7,6,
            7,8,6,7,8,6,6,5,3,
            1,2,5,3,5,8,7,6,8,
            5,5,2,3,4,0,1,-1},                 //送别

            {5,6,8,6,6,5,6,5,3,5,
            5,6,8,6,6,5,6,5,6,1,
            1,2,3,2,2,2,1,2,1,6,
            3,2,5,6,8,6,6,5,6,5,
            6,1,1,2,3,4,4,5,6,6,
            5,6,8,6,8,6,5,5,1,6,
            5,5,6,8,3,2,3,1,-1},           //最浪漫的事

            {5,9,10,9,10,12,13,12,8,9,
            10,13,12,10,12,12,13,15,13,12,
            10,12,10,8,9,10,8,6,10,9,
            12,9,10,9,10,12,13,12,8,9,
            10,13,12,12,13,15,13,
            12,10,12,10,8,6,10,9,8,6,
            8,9,9,8,-1},                                //发如雪
             
            {5,8,9,10,9,10,11,12,12,12,
            11,10,9,5,8,9,10,11,12,12,
            12,13,12,9,10,8,8,6,9,9,
            10,10,8,12,8,12,8,7,8,8,6,
            9,9,10,10,12,12,
            12,13,12,9,10,8,
            5,8,9,10,9,10,11,12,12,12,
            11,10,9,5,8,9,10,9,10,11,
            12,12,12,9,10,8,8,6,9,9,
            10,10,8,12,8,12,12,7,8,-1},        //简单爱

            {8,9,10,8,8,9,10,8,10,11,12,10,11,12,
            12,13,12,11,10,8,12,13,12,11,10,8,8,5,8,8,5,8,-1},        //两只老虎
           
            {5,5,6,5,8,7,
            5,5,6,5,9,8,
            5,5,12,10,8,7,6,
            11,11,10,8,9,8,-1},                        //生日快乐

            {6,8,9,10,12,10,8,9,6,8,9,10,
            12,12,13,9,10,10,12,13,
            12,13,15,14,13,12,13,10,8,9,10,12,8,6,
            8,9,10,13,12,10,13,13,
            12,11,10,9,10,12,6,8,9,8,9,
            10,12,13,15,14,13,12,10,13,-1},        //让我们荡起双桨

            {8,8,12,12,13,13,12,
            11,11,10,10,9,9,8,
            12,12,11,11,10,10,9,
            12,12,11,11,10,10,9,
            8,8,12,12,13,13,12,
            11,11,10,10,9,9,8,-1},                        //小星星

            {12,10,12,10,12,10,8,9,11,10,9,12,
            12,10,12,10,12,10,8,9,11,10,9,8,
            9,9,11,11,10,8,12,9,11,10,9,12,
            12,10,12,10,12,10,8,9,11,10,9,8,-1}, //粉刷匠

            {8,9,10,11,12,12,12,11,10,
            11,11,11,10,9,8,10,12,
            8,9,10,11,12,12,12,11,10,
            11,11,11,10,9,8,10,8,
            13,13,13,12,11,12,12,12,11,10,
            11,11,11,10,9,8,10,12,
            13,13,13,12,11,12,12,12,11,10,
            11,11,11,10,9,8,10,8,-1},                        //洋娃娃和小熊跳舞

            {12,10,12,13,15,16,17,16,15,13,12,15,
            17,16,15,12,17,16,15,12,
            10,12,13,15,16,17,15,13,15,16,
            13,13,14,13,13,17,15,14,15,13,
            12,10,12,13,15,16,17,16,15,13,12,15,
            17,17,17,17,15,16,16,16,16,12,
            12,10,12,13,15,16,17,16,15,13,12,
            15,15,-1},                                                           //小红花

            {8,9,10,11,12,10,8,15,13,11,12,12,10,
            8,9,10,11,12,10,9,8,9,10,9,12,
            8,9,10,11,12,10,8,15,13,11,12,10,
            8,9,10,11,12,10,9,8,9,10,8,8,
            15,13,11,12,12,8,15,13,11,12,10,
            8,9,10,11,12,10,9,8,9,10,8,8,
            15,13,11,12,12,8,15,13,11,12,10,
            8,9,10,11,12,10,9,8,9,10,8,8,-1},        //小红帽
           
            {10,12,16,15,12,11,10,10,10,11,12,
            13,12,10,12,16,15,12,11,
            10,12,12,13,14,15,15,16,12,12,14,13,12,
            10,12,15,13,15,16,15,14,12,10,12,
            16,15,12,11,10,12,12,13,14,15,15,-1},        //雪绒花
    };
    uchar code Len[][100]= //内置音乐对应的节拍(音符持续时间)
    {
            {1,1,2,4,1,1,1,4,
            1,1,2,2,1,1,1,4,
            1,1,1,1,2,1,1,1,
            1,1,3,1,1,1,1,1,
            1,1,1,6,1,1,2,1,
            1,1,1,1,4,1,1,2,
            1,1,1,1,1,4,1,1,
            3,1,2,1,1,1,1,1,
            3,1,1,1,1,1,1,2,
            2,6,-1},

            {3,1,2,2,2,1,
            1,4,2,1,1,2,2,1,1,1,
            1,4,3,1,2,1,1,2,2,
            4,3,1,1,1,1,1,6,-1},

            {2,1,1,2,1,1,2,2,2,3,
            2,1,1,2,1,1,2,2,2,3,
            2,1,1,1,1,2,2,1,1,1,
            1,2,2,1,1,1,1,1,1,6,-1},
             
            {2,3,1,3,2,2,
            4,2,1,1,2,1,1,4,2,
            1,1,2,1,2,2,4,2,1,
            1,2,1,4,2,2,4,2,1,
            1,4,1,1,1,1,1,1,1,
            1,8,2,1,1,2,1,2,2,
            4,2,1,1,2,2,4,-1},

            {1,1,1,2,1,1,1,1,1,5,
            1,1,1,2,1,1,1,1,1,5,
            1,1,1,1,1,1,1,1,1,1,
            2,3,1,1,1,2,1,1,1,1,
            1,5,1,1,1,2,1,1,1,1,
            1,2,1,3,1,1,1,4,1,1,
            5,1,1,1,1,1,1,6,-1},

            {1,1,2,1,1,1,1,3,1,1,
            1,1,1,1,3,1,1,2,1,1,
            1,1,2,1,1,1,1,1,1,1,
            1,1,2,1,1,1,1,3,1,1,
            1,1,3,1,1,2,1,
            1,1,1,2,1,1,1,1,1,1,
            1,1,1,4,-1},

            {1,1,1,1,1,1,1,1,1,1,
            1,1,3,1,1,1,1,1,1,1,
            1,1,2,1,1,2,1,1,1,1,
            1,1,1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,
            1,1,2,1,1,2,
            1,1,2,1,1,1,1,1,1,1,
            1,1,3,1,1,1,1,1,1,1,
            1,1,2,1,1,2,1,1,1,1,
            1,1,2,1,1,1,1,1,1,-1},
           
            {2,2,2,2,2,2,2,2,2,2,4,2,2,4,
            1,1,1,1,2,2,1,1,1,1,2,2,2,2,4,2,2,4,-1},

            {1,1,2,2,2,4,
            1,1,2,2,2,4,
            1,1,2,2,2,2,2,
            1,1,2,2,2,4,-1},

            {1,1,1,3,1,1,1,2,4,1,1,1,
            3,1,2,2,4,1,1,4,
            3,1,1,1,1,1,1,2,1,1,3,1,2,2,
            1,1,1,1,5,4,3,1,
            1,1,2,4,3,1,1,1,3,1,1,
            2,2,2,2,1,1,1,1,4,-1},

            {2,2,2,2,2,2,3,
            2,2,2,2,2,2,3,
            2,2,2,2,2,2,3,
            2,2,2,2,2,2,3,
            2,2,2,2,2,2,3,
            2,2,2,2,2,2,4,-1},

            {1,1,1,1,1,1,2,1,1,1,1,2,
            1,1,1,1,1,1,2,1,1,1,1,2,
            1,1,1,1,1,1,2,1,1,1,1,2,
            1,1,1,1,1,1,2,1,1,1,1,3,-1},

            {1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,1,2,
            1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,1,2,
            1,1,1,1,1,1,1,1,1,2,
            1,1,1,1,1,1,1,2,
            1,1,1,1,1,1,1,1,1,1,
            1,1,1,1,1,1,1,3,-1},

            {1,1,1,1,1,1,2,1,1,1,1,4,
            2,1,1,4,2,1,1,4,
            2,1,1,2,2,1,1,1,1,4,
            2,1,1,3,1,1,1,1,1,4,
            1,1,1,1,1,1,2,1,1,1,1,4,
            1,1,1,1,4,1,1,1,1,4,
            1,1,1,1,1,1,2,1,1,1,1,
            4,4,-1},

            {1,1,1,1,2,1,1,2,1,1,1,1,2,
            1,1,1,1,1,1,1,1,2,2,2,2,
            1,1,1,1,2,1,1,2,1,1,2,2,
            1,1,1,1,1,1,1,1,2,2,2,2,
            2,1,1,1,1,2,2,1,1,2,2,
            1,1,1,1,1,1,1,1,2,2,2,2,
            2,1,1,1,1,2,2,1,1,2,2,
            1,1,1,1,1,1,1,1,2,2,2,2,-1},

            {2,2,4,2,2,4,2,2,1,1,2,
            4,4,2,2,4,2,2,4,
            2,2,1,1,2,4,4,4,1,2,1,1,2,
            2,2,4,2,2,2,2,4,4,2,2,
            4,2,2,4,2,2,1,1,1,4,4,-1}
    };
    uint code tab[]={         //内置16个音符弹奏和播放时都是调用此数组内的数据用于定时器初值
            63500,                                                                                 //超低音 si
            63628,63835,64021,64103,64260,64400,64524,          //低音do-si
            64580,64684,64777,64820,64898,64968,65030,          //           do-si
            65058,65110,65157,65178,65217,65252,65283,         //高音do-si
            65313 };                                                                         //超高音do

    void delay1 (uint ms)      //粗略1ms延时函数,不精确  
    {
            uchar t;
            while (ms--)
            for(t=0;t<120;t++);
    }
    void delay(void)
    {
            uchar i;
            for (i=300;i>0;i--);
    }
    uchar getkey(void)                                  //矩阵按键扫描函数
    {
            uchar scancode,tmpcode;
            if((P1&0xf0)==0xf0)                         //无按键按下时此表达式成立
            return (0);                                         //此函数返回值为0
            scancode = 0xfe;                          //如果上面的if表达式不成立,此语句才可以执行
            while((scancode&0x10)!=0)    //有按键按下时,此表达式成立
            {                                                
                    P1=scancode;                           //将P0口赋值
                    if((P1&0xf0)!=0xf0)           //判断P0口的状态
                    {
                            tmpcode = (P1&0xf0)|0x0f;                 //P0口的状态与上0xf0,然后或上0x0f
                            return((~scancode)+(~tmpcode));         //将两个变量的值取反相加后返回此函数
                    }
                    else scancode=(scancode<<1)|0x01;           //如果上面的if语句不成立,将scancode左移一位
            }
            return(0xff);
    }

    void anjian()                                 //按键键值识别
    {   
            P1=0xf0;                                 //P1口赋值
            if((P1&0xf0)!=0xf0)            //判断是否有按键按下
            {
                    delay();                      //去抖
                    if((P1&0xf0)!=0xf0)  //再次判断有无按键按下  
                    {
                            key=getkey();         //扫描按键
                            Tone_Index=0;    //播放音符顺序清零
                            switch(key)            //根据扫描的按键编码将k赋值
                            {
                                    case 0x88:         //按键编码为0x88
                                    k = 0;                 //k赋值0
                                    break;                  //已经确定键值后提前跳出switch
                                    case 0x48:   //如果不满足上一个case则继续向下判断,直到有符合
                                    k = 1;                  //k赋值1
                                    break;       //下同,略         
                                    case 0x28:   
                                    k = 2 ;
                                    break;  
                                    case 0x18:   
                                    k = 3 ;
                                    break;  
                                    case 0x84:   
                                    k = 4 ;
                                    break;
                                    case 0x44:   
                                    k = 5 ;
                                    break;
                                    case 0x24:   
                                    k = 6 ;
                                    break;
                                    case 0x14:   
                                    k = 7 ;
                                    break;
                                    case 0x82:   
                                    k = 8 ;
                                    break;
                                    case 0x42:   
                                    k = 9 ;
                                    break;
                                    case 0x22:   
                                    k = 10 ;
                                    break;
                                    case 0x12:   
                                    k = 11 ;
                                    break;
                                    case 0x81:   
                                    k = 12 ;
                                    break;
                                    case 0x41:   
                                    k = 13 ;
                                    break;
                                    case 0x21:   
                                    k = 14 ;
                                    break;
                                    case 0x11:   
                                    k = 15 ;
                                    break;
                                    default :                 //如果以上都不符合,直接跳出,无键值输出
                                    break;
                            }
                    }
            }
    }

    void main(void)                                                   //主函数
    {
            SPK=0;
            LED1=1;                                                          
            LED2=0;                                                    //开机默认弹奏模式
            P0=0xc0;                                                   //数码管显示0
            IE=0x87;                                                   //定义外部中断控制器
            TMOD=0x01;                                                   //定义定时器0的工作方式
            IT0=1;                                                           //外部中断0为下降沿触发
            IT1=1;                                                           //外部中断1为下降沿触发
            while(1)                                                   //进入死循环
            {
                    P1=0xf0;                                            //P1口赋值
                    if((P1&0xf0)!=0xf0)                           //判断P0口是否有变化
                    {       
                            anjian();                                   //读取键值
                            P0=DSY_CODE[k];                           //显示键值,也就是显示音符
                            if(FY==0)                                   //如果是弹奏模式
                            {
                                    STH0 = tab[k]/256;
                                    STL0 = tab[k]%256;           //根据k的值赋初值给T0
                                    TR0 = 1;               //打开定时器用于定时产生频率发生     
                                    while ((P1&0xf0)!=0xf0); //按键不松开的话,T0就一直产生频率
                                    TR0=0;                 //按键松开后关闭T0计时,频率停止
                            }
                            else  //如果是播放模式(上面的if语句不成立就执行else)
                            {
                                    while (FY==1)                                                          //进入播放模式
                                    {
                                            if(Song[k][Tone_Index]==-1)                  //一首播放完退出
                                            {
                                                    Tone_Index=0;
                                                    SPK=0;
                                                    break;
                                            }  
                                            STH0=(tab[Song[k][Tone_Index]])/256;
                                            STL0=(tab[Song[k][Tone_Index]])%256; //将内置音乐数组的数据赋给定时器做为初值计时
                                    //        P0=DSY_CODE[Song[k][Tone_Index]];          //显示播放的音符
                                            TR0 = 1;                                                          //打开定时器定时开关
                                            delay1(300*Len[k][Tone_Index]);          //节拍数组延时
                                            Tone_Index++;                                                  //变量加准备播放下一个音符
                                            TR0=0;                                                                 //停止定时器
                                            anjian();                                                         //扫描按键
                                            P0=DSY_CODE[k];                                                 //显示音乐序号
                                            while((P1&0xf0)!=0xf0);
                                    }
                            }
                    }
            }
    }

    void EXO_IXT() interrupt 0                  //外部中断0
    {
            FY=0;                                                  //弹奏模式
            LED1=1;
            LED2=0;                                                  //点亮弹奏模式指示灯
            Tone_Index=0;                                  //歌曲音符序号清零,以便于下次播放内置音乐时从头播放
    }
    void EX1_INT() interrupt 2                  //外部中断1
    {
            FY=1;                                                  //播放模式
            LED1=0;                                                  //点亮播放模式指示灯
            LED2=1;
    }
    void time0_int(void) interrupt 1 using 0   //定时器0
    {      
            TH0 = STH0;                                   //定时器赋初值
            TL0 = STL0;
            SPK=!SPK;                             //喇叭引脚取反,产生频率的音乐
    }
  • 用数组

您需要登录后才可以回复 登录 | 注册