当前位置:网站首页>STC-B学习板蜂鸣器播放音乐

STC-B学习板蜂鸣器播放音乐

2022-07-06 09:24:00 芜湖韩金轮

功能:单片机烧录好程序后,按key1按键播放《IF YOU》,再次按key1可暂停播放,按key2可切换歌曲到《国际歌》,再按key3可切换歌曲到《孤勇者》

芯片:STC15F2K61S2

完整工程文件和hex文件在这
提取码:1111

前言:相信大家焊好板子后最喜欢玩的就是蜂鸣器播放音乐,路过每个教室基本都是各种杂音,毕竟这玩意真挺好玩的,于是我就根据老师的代码和谱子写了播放其他歌曲的文件(国际歌是我直接拿往届学长的音乐代码,来凑个数的),说实话这玩意看起来挺简单的,实际上挺难的,还得学一遍乐理知识,然后对着各种拍子和音调不断调试才能得到一个比较理想的状态,但是if you和孤勇者这两首曲子总感觉有些地方不是很完美,但对于摆烂人来说能听就行了。反正也是娱乐娱乐

废话不多说,代码如下:(谱子在最后)

/**********************
文件名称:beep.c
说明:进行音乐播放的例程,按下key1键后开始播放音乐
修改记录:
***********************/

/**********************
基于STC15F2K60S2系列单片机C语言编程实现
使用如下头文件,不用另外再包含"REG51.H"
***********************/
#include <STC15F2K60S2.h>
#define uint unsigned int
#define uchar unsigned char
sbit beep=P3^4;			  //蜂鸣器
sbit key1=P3^2;			//按键1
sbit key2=P3^3;			//按键2
uchar timeh,timel,jindu=0,gequ=0;		  //定义定时器的重装值
bit flag;	//播放标志位
uchar code music1[] =     //音乐代码,歌曲为《IF YOU》,格式为: 音符, 节拍, 音符, 节拍,
{
    0x26,0x10,
    0x25,0x10,
    0x23,0x10,
    0x21,0x10,
    0x22,0x10,
    0x23,0x10,
    0x16,0x20,

    0x22,0x08,
    0x21,0x08,
    0x22,0x08,
    0x21,0x08,
    0x22,0x08,
    0x21,0x08,
    0x22,0x10,
    0x21,0x08,
    0x22,0x08,
    0x22,0x08,
    0x21,0x08,
    0x23,0x20,

    0x26,0x10,
    0x25,0x10,
    0x23,0x10,
    0x21,0x10,
    0x22,0x10,
    0x23,0x10,
    0x16,0x20,

    0x16,0x08,
    0x17,0x10,
    0x21,0x08,
    0x21,0x08,
    0x16,0x08,
    0x21,0x08,
    0x16,0x08,
    0x21,0x08,
    0x22,0x08,
    0x23,0x08,
    0x22,0x08,
    0x22,0x10,
    0x21,0x08,
    0x21,0x08,
    0x21,0x10,
    0x15,0x08,
    0x21,0x20,

    0x31,0x10,
    0x31,0x08,
    0x31,0x08,
    0x27,0x08,
    0x26,0x08,
    0x21,0x10,
    0x32,0x10,
    0x33,0x10,
    0x36,0x10,
    0x35,0x10,
    0x33,0x10,
    0x32,0x10,
    0x31,0x10,
    0x32,0x30,

    0x32,0x08,
    0x31,0x08,
    0x32,0x08,
    0x23,0x08,
    0x32,0x10,
    0x25,0x24,

    0x25,0x08,
    0x32,0x08,
    0x31,0x08,
    0x32,0x08,
    0x33,0x24,

    0x31,0x08,
    0x31,0x10,
    0x32,0x10,
    0x33,0x10,
    0x36,0x10,
    0x35,0x10,
    0x33,0x10,
    0x32,0x10,
    0x31,0x08,
    0x31,0x08,
    0x32,0x10,
    0x31,0x30,

    0x26,0x08,
    0x26,0x08,
    0x31,0x08,
    0x26,0x08,
    0x31,0x08,
    0x31,0x24,

    0x31,0x08,
    0x31,0x08,
    0x32,0x08,
    0x31,0x08,
    0x31,0x08,
    0x31,0x24,

    0x00,0x10,


};
uchar code music2[] =  			  //歌曲为国际歌
{
    0x25, 0x10, 0x31, 0x18, 0x27, 0x08, 0x32, 0x08, 0x31, 0x08, 0x25, 0x08, 0x23, 0x08, 0x26, 0x18, 0x26, 0x08, 0x24, 0x10, 0x20, 0x08,
    0x26, 0x08, 0x32, 0x18, 0x31, 0x08, 0x27, 0x08, 0x26, 0x08, 0x25, 0x08, 0x24, 0x08, 0x23, 0x30,
    0x25, 0x10, 0x31, 0x18, 0x27, 0x08, 0x32, 0x08, 0x31, 0x08, 0x25, 0x08, 0x23, 0x08, 0x26, 0x20, 0x24, 0x08,
    0x26, 0x08, 0x32, 0x08, 0x31, 0x08, 0x27, 0x10, 0x32, 0x10, 0x34, 0x10, 0x27, 0x10, 0x31, 0x20, 0x31, 0x08, 0x30, 0x08,
    0x33, 0x08, 0x32, 0x08, 0x27, 0x20, 0x26, 0x08, 0x27, 0x08, 0x31, 0x08, 0x26, 0x08, 0x27, 0x20, 0x25, 0x08,
    0x25, 0x08, 0x24, 0x08, 0x25, 0x08, 0x26, 0x18, 0x26, 0x08, 0x32, 0x18, 0x31, 0x08, 0x27, 0x20, 0x27, 0x08, 0x20, 0x08,
    0x32, 0x10, 0x32, 0x18, 0x27, 0x08, 0x25, 0x08, 0x25, 0x08, 0x24, 0x08, 0x25, 0x08, 0x33, 0x20, 0x31, 0x08,
    0x26, 0x08, 0x27, 0x08, 0x31, 0x08, 0x27, 0x10, 0x32, 0x10, 0x31, 0x10, 0x26, 0x10, 0x25, 0x20, 0x25, 0x08, 0x20, 0x08,
    0x33, 0x08, 0x32, 0x08, 0x31, 0x20, 0x25, 0x18, 0x23, 0x08, 0x26, 0x20, 0x24, 0x08, 0x20, 0x08,
    0x32, 0x0c, 0x31, 0x04, 0x27, 0x20, 0x26, 0x10, 0x25, 0x10, 0x25, 0x20, 0x25, 0x08, 0x20, 0x08,
    0x25, 0x10, 0x33, 0x20, 0x32, 0x10, 0x25, 0x10, 0x31, 0x20, 0x27, 0x18,
    0x27, 0x08, 0x26, 0x18, 0x25, 0x08, 0x26, 0x10, 0x32, 0x10, 0x32, 0x20, 0x32, 0x08, 0x30, 0x08,
    0x33, 0x0c, 0x32, 0x04, 0x31, 0x20, 0x25, 0x18, 0x23, 0x08, 0x26, 0x20, 0x24, 0x08, 0x20, 0x08,
    0x32, 0x0c, 0x31, 0x04, 0x27, 0x20, 0x26, 0x10, 0x25, 0x10, 0x33, 0x30,
    0x33, 0x10, 0x35, 0x20, 0x34, 0x10, 0x33, 0x10, 0x32, 0x18, 0x33, 0x08, 0x34, 0x10, 0x30, 0x08,
    0x34, 0x08, 0x33, 0x18, 0x33, 0x08, 0x32, 0x18, 0x32, 0x08, 0x31, 0x30,
    0x00, 0x00
};
uchar code music3[] =  			  //歌曲为孤勇者
{
    0x16,0x08,0x17,0x08,
    0x21,0x08,0x22,0x08,
    0x17,0x08,0x21,0x08,
    0x21,0x10,0x21,0x08,
    0x17,0x08,0x21,0x08,
    0x22,0x08,0x17,0x08,
    0x21,0x08,0x21,0x10,
    0x21,0x08,0x22,0x08,
    0x23,0x08,0x22,0x08,
    0x23,0x08,0x22,0x08,
    0x23,0x10,0x23,0x08,
    0x22,0x08,0x23,0x10,
    0x25,0x10,0x23,0x10,
    0x16,0x08,0x17,0x08,
    0x21,0x08,0x22,0x08,
    0x17,0x08,0x21,0x08,

    0x21,0x10,0x21,0x08,
    0x17,0x08,0x21,0x08,
    0x22,0x08,0x17,0x08,
    0x21,0x08,0x21,0x10,
    0x21,0x08,0x22,0x08,
    0x23,0x08,0x22,0x08,
    0x23,0x08,0x22,0x08,

    0x23,0x10,0x23,0x08,
    0x22,0x08,0x23,0x10,
    0x25,0x10,0x23,0x10,
    0x25,0x10,0x23,0x14,
    0x25,0x08,0x23,0x14,
    0x25,0x08,0x23,0x08,
    0x25,0x08,0x26,0x08,
    0x23,0x08,0x25,0x10,
    0x25,0x08,0x23,0x14,
    0x25,0x08,0x23,0x14,
    0x25,0x08,0x23,0x08,
    0x25,0x08,0x26,0x08,
    0x23,0x08,0x25,0x10,
    0x25,0x08,0x25,0x08,
    0x23,0x08,0x22,0x08,
    0x22,0x10,0x22,0x10,
    0x21,0x08,0x23,0x08,
    0x23,0x08,0x22,0x08,
    0x22,0x10,0x22,0x10,
    0x21,0x08,0x21,0x08,
    0x16,0x20,0x25,0x08,
    0x25,0x08,0x23,0x08,
    0x22,0x08,0x22,0x10,

    0x22,0x10,0x21,0x08,
    0x23,0x08,0x23,0x08,
    0x22,0x08,0x22,0x10,
    0x22,0x10,0x21,0x08,
    0x21,0x08,0x16,0x20,
    0x00
};
uchar code quzi[] =  	 //此数组数据为各个音符在定时器中的重装值,第一列是高位,第二列是低位	//时间
{
    0xf8,0x8c,	  //低八度,低1
    0xf9,0x5b,
    0xfa,0x15,	  //低3
    0xfa,0x67,
    0xfb,0x04,	  //低5
    0xfb,0x90,
    0xfc,0x0c,	  //低7
    0xfc,0x44,	  //中央C调
    0xfc,0xac,	  //中2
    0xfd,0x09,
    0xfd,0x34,	  //中4
    0xfd,0x82,
    0xfd,0xc8,	  //中6
    0xfe,0x06,
    0xfe,0x22,	  //高八度,高1
    0xfe,0x56,
    0xfe,0x6e,	  //高3
    0xfe,0x9a,
    0xfe,0xc1,	  //高5
    0xfe,0xe4,
    0xff,0x03	  //高7
};
/**********************
函数名称:void delay(unsigned int xms)
功能描述:延时
入口参数:xms:输入需要延时的毫秒值
出口参数:无
备注:

***********************/
void delay(unsigned int xms)
{
    uint i,j;
    for(i=xms; i>0; i--)
        for(j=124; j>0; j--);
}
/**********************
函数名称:uchar quyin(uchar tem)
功能描述:在quzi数组中,找到music数组定义的简谱音符的重装值,并返回其在quzi数组中的位置
入口参数:tem:music数组中定义的简谱音符
出口参数:返回的是tem音符在quzi数组中的位置值
备注:

***********************/
uchar quyin(uchar tem)
{
    uchar qudiao,jp,weizhi;		  //定义曲调,音符和位置
    qudiao=tem/16;				  //高4位是曲调值
    jp=tem%16;					  //低4位是音符
    if(qudiao==1)				  //当曲调值为1时,即是低八度,低八度在quzi数组中基址为0
        qudiao=0;
    else if(qudiao==2)			  //当曲调值为2时,即是中八度,中八度在quzi数组中基址为14
        qudiao=14;
    else if(qudiao==3)			  //当曲调值为3时,即是高八度,高八度在quzi数组中,基址为28
        qudiao=28;
    weizhi=qudiao+(jp-1)*2;		  //通过基址加上音符作为偏移量,即可定位此音符在quzi数组中的位置
    return weizhi;				  //返回这一个位置值
}
/**********************
函数名称:void playmusic()
功能描述:播放音乐
入口参数:无
出口参数:无
备注:

***********************/
void playmusic()
{
    uchar p,m,tem;   //m为节拍
    while(1)
    {
        if(flag==1)					  //若播放的标志位为1则播放音乐
        {
            if(gequ==0)				  //歌曲选择位为0,则播放同一首歌
            {
                p=music1[jindu];
                if(p==0x00)			  //如果碰到结束符,延时1秒,回到开始再来一遍
                {
                    jindu=0;
                    delay(1000);
                    break;
                }
                else if(p==0xff) 	  //若碰到休止符,延时100ms,继续取下一音符
                {
                    jindu=jindu+1;
                    delay(100);
                    TR0=0;
                    break;
                }
                else				   //正常情况下取音符和节拍
                {
                    tem=quyin(music1[jindu]);		//取出当前音符在quzi数组中的位置值
                    timeh=quzi[tem];				//把音符相应的计时器重装载值赋予timeh和timel
                    timel=quzi[tem+1];
                    jindu++;
                    TH0=timeh;						//把timeh和timel赋予计时器
                    TL0=timel;
                    m=music1[jindu];					 //取得节拍
                    jindu++;
                }
                TR0=1;                            //开定时器1
                delay(m*180);    				  //等待节拍完成, 通过P3^4口输出音频
                TR0=0;                            //关定时器1
                beep=0;							  //使beep端口置0,起保护蜂鸣器作用
            }
            else if(gequ==1)		   //歌曲选择位为1,则播放小毛驴
            {
                p=music2[jindu];
                if(p==0x00)			 //如果碰到结束符,延时1秒,回到开始再来一遍
                {
                    jindu=0;
                    delay(1000);
                    break;
                }
                else if(p==0xff)   //若碰到休止符,延时100ms,继续取下一音符
                {
                    jindu=jindu+1;
                    delay(100);
                    TR0=0;
                    break;
                }
                else			   //正常情况下取音符和节拍
                {
                    tem=quyin(music2[jindu]);		//取出当前音符在quzi数组中的位置值
                    timeh=quzi[tem];			//把音符相应的计时器重装载值赋予timeh和timel
                    timel=quzi[tem+1];
                    jindu++;
                    TH0=timeh;					//把timeh和timel赋予计时器
                    TL0=timel;
                    m=music2[jindu];					 //取得节拍
                    jindu++;
                }
                TR0=1;                    //开定时器1
                delay(m*300);             //等待节拍完成, 通过P3^4口输出音频
                TR0=0;                    //关定时器1
                beep=0;					  //使beep端口置0,起保护蜂鸣器作用
            }
            else if(gequ==2)		  //歌曲选择位为2,则播放天空之城
            {
                p=music3[jindu];
                if(p==0x00)			 //如果碰到结束符,延时1秒,回到开始再来一遍
                {
                    jindu=0;
                    delay(1000);
                    break;
                }
                else if(p==0xff)   //若碰到休止符,延时100ms,继续取下一音符
                {
                    jindu=jindu+1;
                    delay(100);
                    TR0=0;
                    break;
                }
                else			   //正常情况下取音符和节拍
                {
                    tem=quyin(music3[jindu]);		//取出当前音符在quzi数组中的位置值
                    timeh=quzi[tem];			//把音符相应的计时器重装载值赋予timeh和timel
                    timel=quzi[tem+1];
                    jindu++;
                    TH0=timeh;					//把timeh和timel赋予计时器
                    TL0=timel;
                    m=music3[jindu];					 //取得节拍
                    jindu++;
                }
                TR0=1;                    //开定时器1
                delay(m*200);             //等待节拍完成, 通过P3^4口输出音频
                TR0=0;                    //关定时器1
                beep=0;					  //使beep端口置0,起保护蜂鸣器作用
            }
        }
        else							   //播放标志位不为1时,暂停播放音乐
            while(flag!=1);
    }
}
/**********************
函数名称:void init_sys()
功能描述:系统初始化,功能是配置IO口
入口参数:无
出口参数:无
备注:

***********************/
void init_sys()
{
    P0M0=0xff;			   //设置推挽模式
    P0M1=0x00;
    P2M0=0x08;
    P2M1=0x00;
    P3M0=0x10;
    P3M1=0x00;
    P4M0=0x00;
    P4M1=0x00;
    P5M0=0x00;
    P5M1=0x00;
}
/**********************
函数名称:void init()
功能描述:定时器和外部中断的初始化
入口参数:无
出口参数:无
备注:

***********************/
void init()
{
    TMOD=0x01;			  //设置定时器0,定时方式1,16位手动重装模式
    TH0=0xD8;			  //设置定时初值
    TL0=0xEF;
    IE=0x87;			  // 1000 0111  EA=1,EX0=1,ET0=1,EX1=0;
    IP=0x02;			  // 0000 0010  PT0=1;   定时器0优先级高
    TR0=0;				  //定时器0开始运行
    beep=0;				  //使beep端口置0,起保护蜂鸣器作用
}
void main()
{
    init_sys();			  //系统初始化
    init();
    P0=0x00;
    key1=1;				//两个按键设为输入状态,检测中断
    key2=1;
    flag=0;				//播放标志位清零
    while(1)
    {
        playmusic();	//播放音乐函数
    }
}
/**********************
函数名称:void tim1() interrupt 1
功能描述:定时器0中断处理,重新装值,并把beep值取反,产生方波
入口参数:无
出口参数:无
备注:

***********************/
void tim1() interrupt 1						//计时器控制频率
{
    TH0=timeh;								//赋初值
    TL0=timel;
    beep=~beep;							   //中断使得beep翻转产生方波
}
/**********************
函数名称:void ex1() interrupt 0
功能描述:按下按键1的外部中断,对标志位取反,功能是暂停和播放音乐
入口参数:无
出口参数:无
备注:

***********************/
void ex1() interrupt 0
{
    delay(5);
    if(key1==0)							 //判断key1是否按下
    {
        delay(5);
        if(key1==0)
        {
            while(!key1);
            flag=~flag;							 //播放中断位取反,播放或者暂停
        }
    }
}
/**********************
函数名称:void ex2() interrupt 2
功能描述:按下按键2的外部中断,作用为切换歌曲
入口参数:无
出口参数:无
备注:

***********************/
void ex2() interrupt 2
{
    delay(5);
    if(key2==0)				    //按键key2按下,切换歌曲
    {
        jindu=0;			   //歌曲的进度清零,从头开始演唱
        gequ++;				   //下一曲
        if(gequ==3)			   //到达最后一首调到第一首
            gequ=0;
    }
}

在这里插入图片描述
在这里插入图片描述

原网站

版权声明
本文为[芜湖韩金轮]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_51684393/article/details/125468272