找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 3961|回復(fù): 0
收起左側(cè)

單片機(jī)簡(jiǎn)易音樂(lè)播放器Proteus仿真程序

[復(fù)制鏈接]
ID:991884 發(fā)表于 2021-12-13 20:05 | 顯示全部樓層 |閱讀模式
實(shí)現(xiàn)簡(jiǎn)易播放旋律音樂(lè)
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.gif

簡(jiǎn)易音樂(lè)播放器的工作原理

簡(jiǎn)易音樂(lè)播放器是通過(guò)MCU產(chǎn)生特定頻率的信號(hào),以達(dá)到控制蜂鳴器發(fā)出不同的聲音的目的。因此,簡(jiǎn)易交通燈包括MCU最小系統(tǒng)電路,蜂鳴器驅(qū)動(dòng)電路,按鍵控制電路;驹砣鐖D2.1所示。


圖2.1 簡(jiǎn)易音樂(lè)播放器原理框架
由圖2.1可以看出,按鍵控制電路向MCU最小系統(tǒng)發(fā)送控制信號(hào),MCU最小系統(tǒng)發(fā)出不同頻率的信號(hào)控制蜂鳴器驅(qū)動(dòng)電路發(fā)出聲音,達(dá)到播放音樂(lè)的目的。

2.3 蜂鳴器的的選擇
51hei.png
圖2.4 無(wú)源蜂鳴器
蜂鳴器分為有源蜂鳴器和無(wú)源蜂鳴器兩種,有源和無(wú)源指的是“震蕩源”而不是“電源”,有源蜂鳴器的內(nèi)部含有震蕩源,兩個(gè)引腳接入電源就會(huì)直接發(fā)出聲音,使用起來(lái)簡(jiǎn)單方便,但由于內(nèi)部震蕩源確定,只能發(fā)出單一的聲音,所以我們這里選用無(wú)源振蕩器;無(wú)緣振蕩器內(nèi)部不含震蕩源,使用的時(shí)候必須在引腳上加入震蕩的方波,驅(qū)動(dòng)起來(lái)比較復(fù)雜,但是無(wú)源蜂鳴器可以根據(jù)方波頻率的變化發(fā)出不同的聲音,非常適合我們做簡(jiǎn)易音樂(lè)播放器的發(fā)聲裝置。

2.4 三極管驅(qū)動(dòng)蜂鳴器
51hei.png
圖2.5 NPN三極管
無(wú)源蜂鳴器的驅(qū)動(dòng)方式有很多種,常見(jiàn)的有使用PNP三極管驅(qū)動(dòng)、NPN三極管驅(qū)動(dòng)、ULN2003D芯片驅(qū)動(dòng)。總而言之,單片機(jī)自身的驅(qū)動(dòng)電流無(wú)法驅(qū)動(dòng)蜂鳴器發(fā)聲,需要一個(gè)放大器件進(jìn)行驅(qū)動(dòng)。
這里選用NPN三極管進(jìn)行驅(qū)動(dòng),因?yàn)镹PN三極管常見(jiàn),成本低、穩(wěn)定性好,相對(duì)于ULN2003D來(lái)說(shuō)性價(jià)比更好,更符合工程實(shí)際。

2.5 LCD1602顯示電路
LCD1602的8根數(shù)據(jù)線和3根控制線E,RS和R/W與單片機(jī)相連后即可正常工作。一般應(yīng)用中只須往LCD1602中寫入命令和數(shù)據(jù),因此,可將LCD1602的R/W讀/寫選擇控制端直接接地,這樣可節(jié)省1根數(shù)據(jù)線。VO引腳是液晶對(duì)比度調(diào)試端,通常連接一個(gè)10kΩ的電位器即可實(shí)現(xiàn)對(duì)比度的調(diào)整;也可采用將一個(gè)適當(dāng)大小的電阻從該引腳接地的方法進(jìn)行調(diào)整,不過(guò)電阻的大小應(yīng)通過(guò)調(diào)試決定。


第三章 電路分析與參數(shù)計(jì)算
圖3.1 STC89C52單片機(jī)復(fù)位電路
8051系列單片機(jī)的ALE及/PSEN兩引腳輸出高電平,RST引腳高電平到時(shí),單片機(jī)復(fù)位。若直接由啟動(dòng)瞬間產(chǎn)生,則為啟動(dòng)復(fù)位,若通過(guò)按動(dòng)按鈕產(chǎn)生高電平復(fù)位稱手動(dòng)復(fù)位。如圖3.1所示,上電時(shí),接通電源,電容器C相當(dāng)于瞬間短路,+5V加到了RST/VPD端,該高電平使8051全機(jī)復(fù)位。

3.2 蜂鳴器驅(qū)動(dòng)電路
51hei.png
圖3.2 蜂鳴器驅(qū)動(dòng)電路
蜂鳴器的驅(qū)動(dòng)電路,如圖3.2所示。由于單片機(jī)1/0口的驅(qū)動(dòng)電流僅有100~200
uA,遠(yuǎn)遠(yuǎn)小于驅(qū)動(dòng)蜂鳴器的電流,故用三極管來(lái)擴(kuò)流,這里用的是2    N3417(NPN)。由原理圖可知,單片機(jī)的P2.6端口出現(xiàn)高電平時(shí),三極管導(dǎo)通,從而電流由VCC經(jīng)三極管再經(jīng)蜂鳴器到達(dá)GND,這樣蜂鳴器就會(huì)發(fā)聲;相反,若D5為低電平,則三極管截止,蜂鳴器中沒(méi)有電流,那么肯定就不發(fā)聲。
3.3 按鍵控制電路
51hei.png
圖3.3 按鍵控制電路
簡(jiǎn)易音樂(lè)播放器的按鍵控制電路由三個(gè)按鍵組成,分別接在單片機(jī)的P1.0-P1.2口,單片機(jī)IO口在默認(rèn)情況下為高電平,當(dāng)按鍵按下后引腳接地,單片機(jī)IO口變?yōu)榈碗娖健纹瑱C(jī)由此判斷哪個(gè)按鍵按下。
MUSIC1:音樂(lè)一播放按鍵,按鍵按下后,簡(jiǎn)易音樂(lè)播放器播放第一首音樂(lè)。
MUSIC2:音樂(lè)二播放按鍵,按鍵按下后,簡(jiǎn)易音樂(lè)播放器播放第二首音樂(lè)。
PAUSE/CONTINUE:音樂(lè)暫停/播放按鍵,在音樂(lè)播放時(shí),可以通過(guò)此按鍵控制音樂(lè)的播放與暫停。

第四章 程序設(shè)計(jì)與仿真調(diào)試

4.1 程序設(shè)計(jì)
4.1.1 簡(jiǎn)易音樂(lè)播放器總體流程
  1.系統(tǒng)上電后,等待音樂(lè)選擇。
  2.音樂(lè)播放時(shí)可以暫停和切換歌曲。
51hei.png

仿真中遇到的問(wèn)題
1.簡(jiǎn)易音樂(lè)播放器仿真時(shí),無(wú)源蜂鳴器元件BUZZTON無(wú)法發(fā)出聲音。

排查過(guò)程:首先檢查了蜂鳴器驅(qū)動(dòng)電路,元件是否選擇正確,電路是否連接正確。然后檢查其他硬件電路是否正常,最后檢查程序是否正確。
原因與改進(jìn)辦法:在Proteus8.6版本中元件無(wú)源蜂鳴器BUZZTON不支持仿真,無(wú)論如何都是無(wú)法發(fā)出聲音的,故使用無(wú)源蜂鳴器SOUNDER代替。

簡(jiǎn)易音樂(lè)播放器共有三個(gè)部分組成。第一個(gè)部分為STC89C52最小系統(tǒng)。最小系統(tǒng)控制引腳輸出頻率變化的方波,驅(qū)動(dòng)無(wú)源蜂鳴器播放音樂(lè)。
第二部分是無(wú)源蜂鳴器驅(qū)動(dòng)電路,因?yàn)閱纹瑱C(jī)IO口本身驅(qū)動(dòng)電流及其微小,無(wú)法直接驅(qū)動(dòng)無(wú)源蜂鳴器,所以使用了一個(gè)NPN三極管放大電流,此部分也可以使用PNP型三極管或者ULN2003D驅(qū)動(dòng)芯片。
第三部分是按鍵控制電路,三個(gè)按鍵分別控制播放兩首音樂(lè)和控制音樂(lè)的播放和暫停。

單片機(jī)源程序如下:
  1. #include "reg52.h"   
  2. #include "string.h"   

  3. #define uint8     unsigned char
  4. #define uint16   unsigned short int

  5. #define SETMODE  0x38  //16*2顯示,5*7點(diǎn)陣,8位數(shù)據(jù)接口
  6. #define DISOPEN  0x0C  //顯示開(kāi),不顯示光標(biāo),光標(biāo)不閃爍
  7. #define DISMODE  0x06  //讀寫字符后地址加1,屏顯不移動(dòng)
  8. #define SETADDR  0x80  //設(shè)置數(shù)據(jù)地址指針初始值
  9. #define CLEAR  0x01  //清屏,數(shù)據(jù)指針清零
  10. #define RET  0x02  //回車,數(shù)據(jù)指針清零
  11. #define PORT  P0  //I/O口

  12. sbit RS = P2^6;
  13. sbit RW = P2^5;
  14. sbit E = P2^7;
  15. sbit key_stop = P3^0;//暫停按鍵
  16. sbit key_play = P3^1;//播放
  17. sbit key_next = P3^2;//下一首按鍵
  18. sbit key_last = P3^3;//上一首按鍵

  19. sbit Beep =  P1^5;

  20. uint8 code MUSIC1_NAME[]="MUSIC1";
  21. uint8 code MUSIC1_lyric[]="Bells on bob.tail ring";
  22. uint8 code MUSIC2_NAME[]="MUSIC2";
  23. uint8 code MUSIC2_lyric[]="Happy birthday to you!";
  24. uint8 code MUSIC3_NAME[]="MUSIC3";
  25. uint8 code MUSIC3_lyric[]="Two tigers,Two tigers";

  26. uint8 code string_stop[]="now stop................";



  27. uint8 music_cacah=0;//記錄當(dāng)前音樂(lè)曲目

  28. uint8 flag_music = 1;//音樂(lè)曲目標(biāo)志
  29. uint8 flag_stop=1;//音樂(lè)播放/暫停標(biāo)志

  30. unsigned char p,m;   //m為頻率常數(shù)變量   
  31. unsigned char i=0;  



  32. unsigned char n=0;  //n為節(jié)拍常數(shù)變量   
  33. unsigned char code MUSIC1[] ={0xff,//Jing Bells
  34.                     0x26,0x20,0x18,0x20,0x19,0x20,0x1c,0x20,0x26,0x40,0x60,0x10,0x26,0x20,
  35.                     0x26,0x20,0x18,0x20,0x19,0x20,0x1c,0x20,0x24,0x40,0x60,0x10,0x24,0x20,
  36.                     0x18,0x20,0x19,0x20,0x13,0x20,0x13,0x20,0x13,0x20,0x13,0x20,0x12,0x20,
  37.                     0x13,0x20,0x15,0x20,0x19,0x20,0x1c,0x20,0x00,
  38.                    };
  39. unsigned char code MUSIC2[] ={0xff,//happy birthday
  40.                     0x26,0x20,0x26,0x20,0x24,0x40,0x26,0x40,0x1c,0x40,0x20,0x80,0x26,0x20,
  41.                     0x26,0x20,0x24,0x40,0x26,0x40,0x19,0x40,0x1c,0x80,0x26,0x20,0x26,0x20,
  42.                     0x13,0x40,0x18,0x40,0x1c,0x40,0x20,0x40,0x12,0x40,0x15,0x20,0x15,0x20,
  43.                     0x18,0x40,0x1c,0x40,0x19,0x40,0x18,0x80,0x26,0x20,0x26,0x20,0x18,0x40,
  44.                     0x1c,0x40,0x19,0x40,0x18,0x80,0x26,0x20,0x26,0x20,0x24,0x80,0x00,
  45.                    };
  46. unsigned char code MUSIC3[] ={0xff,//Two tigers
  47.                     0x39,0x40,0x33,0x40,0x30,0x40,0x39,0x40,0x39,0x40,0x33,0x40,0x30,0x40,
  48.                     0x39,0x40,0x30,0x40,0x2b,0x40,0x26,0x80,0x30,0x40,0x2b,0x40,0x26,0x80,
  49.                     0x26,0x10,0x24,0x30,0x26,0x10,0x2b,0x30,0x30,0x40,0x39,0x40,0x26,0x10,
  50.                     0x24,0x30,0x26,0x10,0x24,0x30,0x26,0x10,0x2b,0x30,0x30,0x40,0x39,0x40,
  51.                     0x39,0x40,0x26,0x40,0x39,0x80,0x39,0x40,0x26,0x40,0x39,0x80,0x00,
  52.                    };


  53. void Int1Init()
  54. {
  55.         TMOD&=0x0f;   
  56.   TMOD|=0x01;   
  57.   TH0=0xd8;TL0=0xef;  
  58.         EA=1;
  59.   ET0=1;
  60. }

  61. void delayms (unsigned char m)   //控制頻率延時(shí)   
  62. {   
  63. unsigned i=3*m;   
  64. while(--i);   
  65. }  

  66. void delaymsms(unsigned char a)  //豪秒延時(shí)子程序   
  67. {   
  68.   while(--a);                  
  69. }  
  70. void Write1602_Com(uint8 com)
  71. {
  72.     E=0;
  73.     RS=0;  //命令
  74.     delayms(50);  //延時(shí)
  75.     RW=0;  //寫
  76.     delayms(50);
  77.     PORT=com;  //端口賦值
  78.     delayms(50);
  79.     E=1;  //高脈沖
  80.     delayms(50);
  81.     E=0;
  82. }

  83. void Write1602_Dat(uint8 dat)
  84. {
  85.     E=0;
  86.     RS=1;  //數(shù)據(jù)
  87.     delayms(50);  //延時(shí)
  88.     RW=0;  //寫
  89.     delayms(50);
  90.     PORT=dat;  //端口賦值
  91.     delayms(50);
  92.     E=1;  //高脈沖
  93.     delayms(50);
  94.     E=0;
  95. }

  96. void Init1602(void)
  97. {
  98.     Write1602_Com(SETMODE);  //模式設(shè)置
  99.     delayms(500);
  100.     Write1602_Com(DISOPEN);  //顯示設(shè)置
  101.     delayms(500);
  102.     Write1602_Com(DISMODE);  //顯示模式
  103.     delayms(500);
  104.     Write1602_Com(CLEAR);  //清屏
  105.     delayms(500);
  106. }

  107. void Write1602_Str(uint8 addr,uint8 length,uint8 *pbuf)
  108. {
  109.     uint8 i;
  110.     Write1602_Com(addr);
  111.     for(i=0;i<length;i++)
  112.     {
  113.        Write1602_Dat(pbuf[i]);
  114.     }
  115. }

  116. void scanf()
  117. {
  118.         if(key_stop == 0)
  119.         {
  120.                 delaymsms(10);//消抖
  121.                 flag_stop = 0;
  122.                 while(key_stop==0);//等待按鍵彈起
  123.         }
  124.         if(key_next == 0)
  125.         {
  126.                 delaymsms(10);//消抖
  127.                 flag_stop = 0;
  128.                 flag_music++;
  129.                 while(key_next==0);//等待按鍵彈起
  130.         }
  131.         if(key_last == 0)
  132.         {
  133.                 delaymsms(10);//消抖
  134.                 flag_stop = 0;
  135.                 flag_music--;
  136.                 while(key_last==0);//等待按鍵彈起
  137.         }
  138.        
  139.         if(flag_music==0)//1-8循環(huán)切歌
  140.                 flag_music=3;
  141.         if(flag_music==4)
  142.                 flag_music=1;
  143. }

  144. void music_play(uint8 ur[])
  145. {
  146.         music_cacah = flag_music;
  147.         i = 0;
  148. play:   
  149.    while(1)   
  150.     {   
  151.     a:
  152.                         if(flag_stop==0)//音樂(lè)暫停
  153.                                 {
  154.                                         if(flag_music != music_cacah)//如果播放途中切換了曲目,跳出當(dāng)前播放
  155.                                         {
  156.                                                 flag_stop=1;
  157.                                                 break;
  158.                                         }
  159.                                         else
  160.                                         {
  161.                                                 Write1602_Str(0x80+0x40,strlen(string_stop),string_stop);  //"stoping..."
  162.                                                 while(1)//等待音樂(lè)播放
  163.                                                 {
  164.                                                         scanf();
  165.                                                         if(key_play==0||flag_music != music_cacah)//按下播放鍵
  166.                                                         {
  167.                                                                 flag_stop=1;
  168.                                                                 break;
  169.                                                         }
  170.                                                 }
  171.                                                 if(flag_music != music_cacah)//如果暫停途中切換了曲目,跳出當(dāng)前播放
  172.                                                 {
  173.                                                         flag_stop=1;
  174.                                                         break;
  175.                                                 }
  176.                                         }
  177.                                 }
  178.                          p=ur[i];   
  179.        if(p==0x00)       { i=0, delaymsms(1000); goto play;}     //如果碰到結(jié)束符,延時(shí)1秒,回到開(kāi)始再來(lái)一遍   
  180.        else if(p==0xff)  { i=i+1;delaymsms(100),TR0=0; goto a;}  //若碰到休止符,延時(shí)100ms,繼續(xù)取下一音符   
  181.             else         {m=ur[i++], n=ur[i++];}  //取頻率常數(shù) 和 節(jié)拍常數(shù)   
  182.              TR0=1;                                             //開(kāi)定時(shí)器1   
  183.        while(n!=0) Beep=~Beep,delayms(m);                         //等待節(jié)拍完成  
  184.        TR0=0;                                             //關(guān)定時(shí)器1   
  185.     }
  186. }



  187. void main()
  188. {
  189.           Int1Init();//定時(shí)器中斷1初始化

  190.                 Init1602();  //初始化1602
  191.           Write1602_Str(0x80+0x40,strlen(string_stop),string_stop);  //"stop"

  192.     while(1)
  193. ……………………

  194. …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼

仿真代碼與word資料51hei附件下載:
音樂(lè)播放器-3首lcd1602顯示歌詞.zip (507.25 KB, 下載次數(shù): 81)

評(píng)分

參與人數(shù) 1黑幣 +30 收起 理由
admin + 30 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表