打印

求个课程设计,51单片机的电子琴

[复制链接]
111|1
手机看帖
扫描二维码
随时随地手机跟帖
沙发
gaochy1126| | 2024-11-30 22:01 | 只看该作者

求个课程设计,51单片机的电子琴

#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;                             //喇叭引脚取反,产生频率的音乐
}

使用特权

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

本版积分规则

20

主题

3046

帖子

2

粉丝