实现简易播放旋律音乐
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
简易音乐播放器的工作原理
简易音乐播放器是通过MCU产生特定频率的信号,以达到控制蜂鸣器发出不同的声音的目的。因此,简易交通灯包括MCU最小系统电路,蜂鸣器驱动电路,按键控制电路。基本原理如图2.1所示。
图2.1 简易音乐播放器原理框架
由图2.1可以看出,按键控制电路向MCU最小系统发送控制信号,MCU最小系统发出不同频率的信号控制蜂鸣器驱动电路发出声音,达到播放音乐的目的。
2.3 蜂鸣器的的选择
图2.4 无源蜂鸣器
蜂鸣器分为有源蜂鸣器和无源蜂鸣器两种,有源和无源指的是“震荡源”而不是“电源”,有源蜂鸣器的内部含有震荡源,两个引脚接入电源就会直接发出声音,使用起来简单方便,但由于内部震荡源确定,只能发出单一的声音,所以我们这里选用无源振荡器;无缘振荡器内部不含震荡源,使用的时候必须在引脚上加入震荡的方波,驱动起来比较复杂,但是无源蜂鸣器可以根据方波频率的变化发出不同的声音,非常适合我们做简易音乐播放器的发声装置。
2.4 三极管驱动蜂鸣器
图2.5 NPN三极管
无源蜂鸣器的驱动方式有很多种,常见的有使用PNP三极管驱动、NPN三极管驱动、ULN2003D芯片驱动。总而言之,单片机自身的驱动电流无法驱动蜂鸣器发声,需要一个放大器件进行驱动。
这里选用NPN三极管进行驱动,因为NPN三极管常见,成本低、稳定性好,相对于ULN2003D来说性价比更好,更符合工程实际。
2.5 LCD1602显示电路
LCD1602的8根数据线和3根控制线E,RS和R/W与单片机相连后即可正常工作。一般应用中只须往LCD1602中写入命令和数据,因此,可将LCD1602的R/W读/写选择控制端直接接地,这样可节省1根数据线。VO引脚是液晶对比度调试端,通常连接一个10kΩ的电位器即可实现对比度的调整;也可采用将一个适当大小的电阻从该引脚接地的方法进行调整,不过电阻的大小应通过调试决定。
第三章 电路分析与参数计算
图3.1 STC89C52单片机复位电路
8051系列单片机的ALE及/PSEN两引脚输出高电平,RST引脚高电平到时,单片机复位。若直接由启动瞬间产生,则为启动复位,若通过按动按钮产生高电平复位称手动复位。如图3.1所示,上电时,接通电源,电容器C相当于瞬间短路,+5V加到了RST/VPD端,该高电平使8051全机复位。
3.2 蜂鸣器驱动电路
图3.2 蜂鸣器驱动电路
蜂鸣器的驱动电路,如图3.2所示。由于单片机1/0口的驱动电流仅有100~200
uA,远远小于驱动蜂鸣器的电流,故用三极管来扩流,这里用的是2 N3417(NPN)。由原理图可知,单片机的P2.6端口出现高电平时,三极管导通,从而电流由VCC经三极管再经蜂鸣器到达GND,这样蜂鸣器就会发声;相反,若D5为低电平,则三极管截止,蜂鸣器中没有电流,那么肯定就不发声。
3.3 按键控制电路
图3.3 按键控制电路
简易音乐播放器的按键控制电路由三个按键组成,分别接在单片机的P1.0-P1.2口,单片机IO口在默认情况下为高电平,当按键按下后引脚接地,单片机IO口变为低电平。单片机由此判断哪个按键按下。
MUSIC1:音乐一播放按键,按键按下后,简易音乐播放器播放第一首音乐。
MUSIC2:音乐二播放按键,按键按下后,简易音乐播放器播放第二首音乐。
PAUSE/CONTINUE:音乐暂停/播放按键,在音乐播放时,可以通过此按键控制音乐的播放与暂停。
第四章 程序设计与仿真调试
4.1 程序设计
4.1.1 简易音乐播放器总体流程
1.系统上电后,等待音乐选择。
2.音乐播放时可以暂停和切换歌曲。
仿真中遇到的问题
1.简易音乐播放器仿真时,无源蜂鸣器元件BUZZTON无法发出声音。
排查过程:首先检查了蜂鸣器驱动电路,元件是否选择正确,电路是否连接正确。然后检查其他硬件电路是否正常,最后检查程序是否正确。
原因与改进办法:在Proteus8.6版本中元件无源蜂鸣器BUZZTON不支持仿真,无论如何都是无法发出声音的,故使用无源蜂鸣器SOUNDER代替。
简易音乐播放器共有三个部分组成。第一个部分为STC89C52最小系统。最小系统控制引脚输出频率变化的方波,驱动无源蜂鸣器播放音乐。
第二部分是无源蜂鸣器驱动电路,因为单片机IO口本身驱动电流及其微小,无法直接驱动无源蜂鸣器,所以使用了一个NPN三极管放大电流,此部分也可以使用PNP型三极管或者ULN2003D驱动芯片。
第三部分是按键控制电路,三个按键分别控制播放两首音乐和控制音乐的播放和暂停。
单片机源程序如下:
- #include "reg52.h"
- #include "string.h"
- #define uint8 unsigned char
- #define uint16 unsigned short int
- #define SETMODE 0x38 //16*2显示,5*7点阵,8位数据接口
- #define DISOPEN 0x0C //显示开,不显示光标,光标不闪烁
- #define DISMODE 0x06 //读写字符后地址加1,屏显不移动
- #define SETADDR 0x80 //设置数据地址指针初始值
- #define CLEAR 0x01 //清屏,数据指针清零
- #define RET 0x02 //回车,数据指针清零
- #define PORT P0 //I/O口
- sbit RS = P2^6;
- sbit RW = P2^5;
- sbit E = P2^7;
- sbit key_stop = P3^0;//暂停按键
- sbit key_play = P3^1;//播放
- sbit key_next = P3^2;//下一首按键
- sbit key_last = P3^3;//上一首按键
- sbit Beep = P1^5;
- uint8 code MUSIC1_NAME[]="MUSIC1";
- uint8 code MUSIC1_lyric[]="Bells on bob.tail ring";
- uint8 code MUSIC2_NAME[]="MUSIC2";
- uint8 code MUSIC2_lyric[]="Happy birthday to you!";
- uint8 code MUSIC3_NAME[]="MUSIC3";
- uint8 code MUSIC3_lyric[]="Two tigers,Two tigers";
- uint8 code string_stop[]="now stop................";
- uint8 music_cacah=0;//记录当前音乐曲目
- uint8 flag_music = 1;//音乐曲目标志
- uint8 flag_stop=1;//音乐播放/暂停标志
- unsigned char p,m; //m为频率常数变量
- unsigned char i=0;
- unsigned char n=0; //n为节拍常数变量
- unsigned char code MUSIC1[] ={0xff,//Jing Bells
- 0x26,0x20,0x18,0x20,0x19,0x20,0x1c,0x20,0x26,0x40,0x60,0x10,0x26,0x20,
- 0x26,0x20,0x18,0x20,0x19,0x20,0x1c,0x20,0x24,0x40,0x60,0x10,0x24,0x20,
- 0x18,0x20,0x19,0x20,0x13,0x20,0x13,0x20,0x13,0x20,0x13,0x20,0x12,0x20,
- 0x13,0x20,0x15,0x20,0x19,0x20,0x1c,0x20,0x00,
- };
- unsigned char code MUSIC2[] ={0xff,//happy birthday
- 0x26,0x20,0x26,0x20,0x24,0x40,0x26,0x40,0x1c,0x40,0x20,0x80,0x26,0x20,
- 0x26,0x20,0x24,0x40,0x26,0x40,0x19,0x40,0x1c,0x80,0x26,0x20,0x26,0x20,
- 0x13,0x40,0x18,0x40,0x1c,0x40,0x20,0x40,0x12,0x40,0x15,0x20,0x15,0x20,
- 0x18,0x40,0x1c,0x40,0x19,0x40,0x18,0x80,0x26,0x20,0x26,0x20,0x18,0x40,
- 0x1c,0x40,0x19,0x40,0x18,0x80,0x26,0x20,0x26,0x20,0x24,0x80,0x00,
- };
- unsigned char code MUSIC3[] ={0xff,//Two tigers
- 0x39,0x40,0x33,0x40,0x30,0x40,0x39,0x40,0x39,0x40,0x33,0x40,0x30,0x40,
- 0x39,0x40,0x30,0x40,0x2b,0x40,0x26,0x80,0x30,0x40,0x2b,0x40,0x26,0x80,
- 0x26,0x10,0x24,0x30,0x26,0x10,0x2b,0x30,0x30,0x40,0x39,0x40,0x26,0x10,
- 0x24,0x30,0x26,0x10,0x24,0x30,0x26,0x10,0x2b,0x30,0x30,0x40,0x39,0x40,
- 0x39,0x40,0x26,0x40,0x39,0x80,0x39,0x40,0x26,0x40,0x39,0x80,0x00,
- };
- void Int1Init()
- {
- TMOD&=0x0f;
- TMOD|=0x01;
- TH0=0xd8;TL0=0xef;
- EA=1;
- ET0=1;
- }
- void delayms (unsigned char m) //控制频率延时
- {
- unsigned i=3*m;
- while(--i);
- }
- void delaymsms(unsigned char a) //豪秒延时子程序
- {
- while(--a);
- }
- void Write1602_Com(uint8 com)
- {
- E=0;
- RS=0; //命令
- delayms(50); //延时
- RW=0; //写
- delayms(50);
- PORT=com; //端口赋值
- delayms(50);
- E=1; //高脉冲
- delayms(50);
- E=0;
- }
- void Write1602_Dat(uint8 dat)
- {
- E=0;
- RS=1; //数据
- delayms(50); //延时
- RW=0; //写
- delayms(50);
- PORT=dat; //端口赋值
- delayms(50);
- E=1; //高脉冲
- delayms(50);
- E=0;
- }
- void Init1602(void)
- {
- Write1602_Com(SETMODE); //模式设置
- delayms(500);
- Write1602_Com(DISOPEN); //显示设置
- delayms(500);
- Write1602_Com(DISMODE); //显示模式
- delayms(500);
- Write1602_Com(CLEAR); //清屏
- delayms(500);
- }
- void Write1602_Str(uint8 addr,uint8 length,uint8 *pbuf)
- {
- uint8 i;
- Write1602_Com(addr);
- for(i=0;i<length;i++)
- {
- Write1602_Dat(pbuf[i]);
- }
- }
- void scanf()
- {
- if(key_stop == 0)
- {
- delaymsms(10);//消抖
- flag_stop = 0;
- while(key_stop==0);//等待按键弹起
- }
- if(key_next == 0)
- {
- delaymsms(10);//消抖
- flag_stop = 0;
- flag_music++;
- while(key_next==0);//等待按键弹起
- }
- if(key_last == 0)
- {
- delaymsms(10);//消抖
- flag_stop = 0;
- flag_music--;
- while(key_last==0);//等待按键弹起
- }
-
- if(flag_music==0)//1-8循环切歌
- flag_music=3;
- if(flag_music==4)
- flag_music=1;
- }
- void music_play(uint8 ur[])
- {
- music_cacah = flag_music;
- i = 0;
- play:
- while(1)
- {
- a:
- if(flag_stop==0)//音乐暂停
- {
- if(flag_music != music_cacah)//如果播放途中切换了曲目,跳出当前播放
- {
- flag_stop=1;
- break;
- }
- else
- {
- Write1602_Str(0x80+0x40,strlen(string_stop),string_stop); //"stoping..."
- while(1)//等待音乐播放
- {
- scanf();
- if(key_play==0||flag_music != music_cacah)//按下播放键
- {
- flag_stop=1;
- break;
- }
- }
- if(flag_music != music_cacah)//如果暂停途中切换了曲目,跳出当前播放
- {
- flag_stop=1;
- break;
- }
- }
- }
- p=ur[i];
- if(p==0x00) { i=0, delaymsms(1000); goto play;} //如果碰到结束符,延时1秒,回到开始再来一遍
- else if(p==0xff) { i=i+1;delaymsms(100),TR0=0; goto a;} //若碰到休止符,延时100ms,继续取下一音符
- else {m=ur[i++], n=ur[i++];} //取频率常数 和 节拍常数
- TR0=1; //开定时器1
- while(n!=0) Beep=~Beep,delayms(m); //等待节拍完成
- TR0=0; //关定时器1
- }
- }
- void main()
- {
- Int1Init();//定时器中断1初始化
- Init1602(); //初始化1602
- Write1602_Str(0x80+0x40,strlen(string_stop),string_stop); //"stop"
- while(1)
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
仿真代码与word资料51hei附件下载:
音乐播放器-3首lcd1602显示歌词.zip
(507.25 KB, 下载次数: 81)
|