今天的目标很明确,那就是我们如何使用51单片机演奏一首音乐。


先听一下演奏效果:

51单片机播放《猪猪侠》音乐(音频)

1.有一个很重要的问题,那就是如何将乐谱转换51单片机的16进制或十进制呢?

然而我们不可能为了编一首乐谱再去学音乐知识,这样太费劲了
但是我们有一个编辑软件,直接将乐谱转换51单片机的16进制或十进制。
https://pan.baidu.com/s/1X_3bESwv831psG2tBL7yJw
提取码:sr7i


2.但是有了乐谱编辑软件,你会用吗?

下面我以《猪猪侠》乐谱 为例,简单的教大家如何使用这个软件

由于本人较懒只编了这么一段

我们打开软件:

其实灰常简单,只需要将乐谱中对应的数字或符号一一对应我们软件中的符号就行了
我们以该乐谱第一行为例编写一段:

这一行有数字:3 1 3_ 4 4_ 2_ 6 2.

符号:| ~ 注:‘~’ 就代表:

那么这一行的十六进制就是:

注意:我们在用该软件编写乐谱时,最好不要将乐谱的前奏也写进去,因为前奏哪一部分演奏效果不是太好。

3.下面就是我们的代码了:

自定义头文件代码:

 曲谱存贮格式 unsigned char code MusicName{音高,音长,音高,音长...., 0,0};   末尾:0,0 表示结束(Important)音高由三位数字组成:个位是表示 1~7 这七个音符 十位是表示音符所在的音区:1-低音,2-中音,3-高音;百位表示这个音符是否要升半音: 0-不升,1-升半音。音长最多由三位数字组成: 个位表示音符的时值,其对应关系是: |数值(n):  |0 |1 |2 |3 | 4 | 5 | 6 |几分音符: |1 |2 |4 |8 |16 |32 |64       音符=2^n十位表示音符的演奏效果(0-2):  0-普通,1-连音,2-顿音百位是符点位: 0-无符点,1-有符点调用演奏子程序的格式Play(乐曲名,调号,升降八度,演奏速度);|乐曲名           : 要播放的乐曲指针,结尾以(0,0)结束;|调号(0-11)       : 是指乐曲升多少个半音演奏;|升降八度(1-3)      : 1:降八度, 2:不升不降, 3:升八度;|演奏速度(1-12000):    值越大速度越快;***************************************************************************/
#ifndef __SOUNDPLAY_H_REVISION_FIRST__
#define __SOUNDPLAY_H_REVISION_FIRST__//**************************************************************************#define SYSTEM_OSC      24000000//定义晶振频率12000000HZ
#define SOUND_SPACE     4/6//定义普通音符演奏的长度分率,//每4分音符间隔
sbit    BeepIO    =     P3^7;      //定义输出管脚unsigned int  code FreTab[12]  = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始频率表
unsigned char code SignTab[7]  = { 0,2,4,5,7,9,11 };                                   //1~7在频率表中的位置
unsigned char code LengthTab[7]= { 1,2,4,8,16,32,64 };
unsigned char Sound_Temp_TH0,Sound_Temp_TL0;    //音符定时器初值暂存
unsigned char Sound_Temp_TH1,Sound_Temp_TL1;    //音长定时器初值暂存
//**************************************************************************
void InitialSound(void)
{BeepIO = 0;Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;    // 计算TL1应装入的初值  (10ms的初装值)Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256;   // 计算TH1应装入的初值TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TMOD  |= 0x11;ET0    = 1;ET1       = 0;TR0    = 0;TR1    = 0;EA     = 1;
}void BeepTimer0(void) interrupt 1 //音符发生中断
{BeepIO = !BeepIO;TH0    = Sound_Temp_TH0;TL0    = Sound_Temp_TL0;
}
//**************************************************************************
void Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed)
{unsigned int NewFreTab[12];        //新的频率表unsigned char i,j;unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;for(i=0;i<12;i++)              // 根据调号及升降八度来生成新的频率表{j = i + Signature;if(j > 11){j = j-12;NewFreTab[i] = FreTab[j]*2;}elseNewFreTab[i] = FreTab[j];if(Octachord == 1)NewFreTab[i]>>=2;else if(Octachord == 3)NewFreTab[i]<<=2;}                                    SoundLength = 0;while(Sound[SoundLength] != 0x00) //计算歌曲长度{SoundLength+=2;}Point = 0;Tone   = Sound[Point];   Length = Sound[Point+1];             // 读出第一个音符和它时时值LDiv0 = 12000/Speed;             // 算出1分音符的长度(几个10ms)LDiv4 = LDiv0/4;                    // 算出4分音符的长度LDiv4 = LDiv4-LDiv4*SOUND_SPACE;     // 普通音最长间隔标准TR0   = 0;TR1   = 1;while(Point < SoundLength){SL=Tone%10;                                //计算出音符SM=Tone/10%10;                                //计算出高低音SH=Tone/100;                               //计算出是否升半CurrentFre = NewFreTab[SignTab[SL-1]+SH];     //查出对应音符的频率if(SL!=0){if (SM==1) CurrentFre >>= 2;       //低音if (SM==3) CurrentFre <<= 2;      //高音Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值Sound_Temp_TH0 = Temp_T/256; Sound_Temp_TL0 = Temp_T%256; TH0 = Sound_Temp_TH0;  TL0 = Sound_Temp_TL0 + 12; //加12是对中断延时的补偿}SLen=LengthTab[Length%10];  //算出是几分音符XG=Length/10%10;             //算出音符类型(0普通1连音2顿音)FD=Length/100;LDiv=LDiv0/SLen;           //算出连音音符演奏的长度(多少个10ms)if (FD==1) LDiv=LDiv+LDiv/2;if(XG!=1)   if(XG==0)                //算出普通音符的演奏长度if (SLen<=4) LDiv1=LDiv-LDiv4;elseLDiv1=LDiv*SOUND_SPACE;elseLDiv1=LDiv/2;      //算出顿音的演奏长度elseLDiv1=LDiv;if(SL==0) LDiv1=0;LDiv2=LDiv-LDiv1;      //算出不发音的长度if (SL!=0){TR0=1;for(i=LDiv1;i>0;i--)  //发规定长度的音{while(TF1==0);TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TF1=0;}}if(LDiv2!=0){TR0=0; BeepIO=0;for(i=LDiv2;i>0;i--)   //音符间的间隔{while(TF1==0);TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TF1=0;}}Point+=2; Tone=Sound[Point];Length=Sound[Point+1];}BeepIO = 0;
}#endif

主函数代码:

#include <REG52.H>
#include "SoundPlay.h"void Delay1ms(unsigned int count)
{unsigned int i,j;for(i=0;i<count;i++)for(j=0;j<120;j++);
}unsigned char code Music[] ={ 0x17,0x02, 0x17,0x02, 0x17,0x02, 0x15,0x02, 0x17,0x03,0x18,0x02, 0x17,0x0D, 0x17,0x03, 0x17,0x03, 0x18,0x03,0x17,0x03, 0x16,0x03, 0x16,0x66, 0x1A,0x02, 0x16,0x03,0x16,0x0D, 0x16,0x16, 0x19,0x02, 0x19,0x02, 0x19,0x02,0x16,0x02, 0x19,0x03, 0x1A,0x0D, 0x19,0x03, 0x19,0x02,0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x18,0x03, 0x18,0x02,0x18,0x03, 0x19,0x03, 0x18,0x02, 0x17,0x0D, 0x17,0x16,0x17,0x02, 0x17,0x02, 0x17,0x02, 0x15,0x02, 0x17,0x03,0x18,0x02, 0x17,0x0D, 0x17,0x03, 0x17,0x03, 0x18,0x03,0x17,0x03, 0x16,0x03, 0x16,0x02, 0x16,0x03, 0x1A,0x02,0x16,0x03, 0x16,0x0D, 0x16,0x16, 0x19,0x02, 0x19,0x02,0x19,0x02, 0x16,0x02, 0x19,0x03, 0x1A,0x0D, 0x19,0x03,0x19,0x02, 0x19,0x03, 0x1A,0x03, 0x1B,0x03, 0x1F,0x03,0x1F,0x66, 0x1B,0x03, 0x1B,0x02, 0x1F,0x0D, 0x1F,0x15,0x19,0x03, 0x1A,0x03, 0x1B,0x03, 0x00,0x00 };
//***********************************************************************************
void main()
{InitialSound();while(1){Play(Music,0,3,360);Delay1ms(500);}
}

4.proteus仿真图:


大家将HEX文件写入AT89C51就可以了


以上就是利用51单片机演奏《猪猪侠》音乐了,你学废了吗?as哈哈 哈哈哈 笑

利用51单片机演奏《猪猪侠》相关推荐

  1. 利用51单片机+0.96寸iic接口oled显示图片或动图

    利用51单片机+0.96寸iic接口oled显示图片或动图 前言:之前讲过如何使用oled显示数字以及字符,但并未讲述如何显示BMP格式的图片, 这篇将在之前的基础上加以封装一些函数用来显示图片 硬件 ...

  2. 利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第一篇“显示贪吃蛇”

    利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第一篇"显示贪吃蛇" 完整的项目链接: https://github.com/linxinloningg/51_chip_ ...

  3. 利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第二篇“自动运行函数”

    利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第二篇"自动运行函数" 完整的项目链接: https://github.com/linxinloningg/51_chip ...

  4. 利用51单片机统计脉冲个数,即时输出显示

    ;利用51单片机设计一个计数显示系统,要求8个数码管显示T1输入脉冲的个数. ;最好用汇编语言,加注释,尽量别太复杂.尽量快些哈! ;悬赏分:30 | 解决时间:2011-7-20 19:15 | ; ...

  5. 用51单片机演奏民歌茉莉花

    用51单片机演奏民歌茉莉花 源代码 #include<reg51.h> sbit Buzz = P3^1; //声明绑定蜂鸣器,接线时只需将此IO口与蜂鸣器(扬声器)信号输入端相连即可 u ...

  6. 利用51单片机制作一个秒表的详细过程

    利用51单片机制作一个秒表的详细过程 前面的话: 和很多朋友一样,在学51单片机的过程中我们肯定会涉及到制作一个秒表,牵涉到把单片机的多个部分组合起来使用,这对于我们初学者来说可能显得有些困难,我同大 ...

  7. 利用51单片机制作从左至右再从右制作的的流水灯

    利用51单片机制作从左至右再从右制作的的流水灯 简述: 1.打开keil 4,新建工程 2.选择Atmel ,选择AT89C51芯片 3.新建文件另存为,将文件名末尾加上".c" ...

  8. 用c语言编写振铃检测程序,利用51单片机2进8出的程控交换机C语言源码

    这个是利用51单片机加上超长的语音芯片合为一体的2进8出的程控交换机C语言源码 /************************** 6-23日 修改总台来显 ******************* ...

  9. c51单片机秒表程序c语言,利用51单片机制作秒表的详细过程

    前面的话: 和很多朋友一样,在学51单片机的过程中我们肯定会涉及到制作一个秒表,牵涉到把单片机的多个部分组合起来使用,这对于我们初学者来说可能显得有些困难,我同大家一样,百思不得其解,最后头都弄大了才 ...

最新文章

  1. 这也不能一直在这儿瞎忙活
  2. 服务器无限火力时间,LOL无限火力2018时间表6月具体开启时间 无限火力模式什么时候出...
  3. Could not find destination factory for transport解决方法
  4. chrome 主进程cpu占用50%怎么办?
  5. zemax评价函数编辑器_ZEMAX与光学设计案例:激光扩束系统详细设计与公差分析(二)...
  6. android刷新时的圆形动画_Android动画篇(一):圆形进度条CircleProgressBar
  7. 扩容是元素还是数组_Java中对数组的操作
  8. Nginx+MySQL+PHP+Memcache+Vsftpd一键安装包
  9. linux运行wordcount,Ubuntu16.04上运行Hadoop2.7.3自带example wordCount摸索记录
  10. 魅族技术晚场回顾,算法、架构、AI之外,还要考虑未来
  11. ArcGIS单波段提取
  12. JmeterTCP返回响应码500
  13. mysql性能优化总结详解:MySQL数据库从原理到高性能实战
  14. 汉字转拼音首字母大写
  15. 使用Matlab理解PID
  16. Cesium中的几种坐标和相互转换
  17. java_计算两个时间相差多少天、小时、分钟、秒
  18. 关于matlab GUI重命名的问题。
  19. 在香港,无法使用迅雷下载怎么办?
  20. C语言初阶-C语言中static的用法

热门文章

  1. 数据库题库haust_2
  2. android 系统版本比例,安卓手机系统版本分布:Android 9.0占比达34%!
  3. 利用freemark进行pdf的转换
  4. 非常简单的语音朗读功能
  5. 无人车高手,与华为云上的少年热血
  6. 2021牛客暑期多校训练营7
  7. [STM32F10x] 利用定时器测量脉冲宽度
  8. Unity3D 游戏画面像素与单位关系简介
  9. 全国电子设计大赛2019年前历届优秀作品,肯定对你电赛之路有所帮助!
  10. python爬取电影并下载